udunits-2.2.0/0000755000175000017500000000000012260406765014350 5ustar amckinstryamckinstryudunits-2.2.0/installdirs.texi.in0000644000175000017500000000012612260406756020177 0ustar amckinstryamckinstry@set includedir @prefix@/include @set libdir @prefix@/lib @set datadir @prefix@/share udunits-2.2.0/Makefile.am0000644000175000017500000000757312260406756016420 0ustar amckinstryamckinstry# Copyright 2013 University Corporation for Atmospheric Research # # This file is part of the UDUNITS-2 package. See the file COPYRIGHT # in the top-level source-directory of the package for copying and # redistribution conditions. # ## Process this file with automake to produce Makefile.in ACLOCAL_AMFLAGS = -I m4 SUBDIRS = lib prog DIST_SUBDIRS = lib prog test info_TEXINFOS = udunits2.texi udunits2_TEXINFOS = success.texi failure.texi make.texi EXTRA_DIST = \ ANNOUNCEMENT \ CHANGE_LOG \ CMakeLists.txt \ config.h.cmake \ COPYRIGHT \ texinfo.tex \ udunits2.html \ udunits2.pdf AM_MAKEINFOHTMLFLAGS = --no-split RSYNC_FLAGS = --rsh=ssh --rsync-path=/opt/bin/rsync distName = $(PACKAGE)-$(VERSION) distArchive = $(distName).tar.gz DISTCLEANFILES = *.log $(distArchive) success.texi: test/results.tab sleep 2 # to accomodate broken HP-UX B.11.00 make(1) sort -u -t : -k 2,2 -k 4,4 -k 5,5 test/results.tab | \ awk -F: ' \ BEGIN { \ print "@multitable {@code{Linux 2.6.18-1.2257.fc5smp}} {@code{/opt/csw/gcc4/bin/gcc}} {@code{--disable-shared}}"; \ print "@headitem O/S @tab Compiler @tab @code{configure} Option"; \ } \ $$6 == 1 { \ printf "@item @code{%s} @tab @code{%s} @tab @code{%s}\n", \ $$2, $$4, $$5; \ } \ END { \ print "@end multitable"; \ }' >$@ sleep 2 # to accomodate broken HP-UX B.11.00 make(1) failure.texi: test/results.tab sleep 2 # to accomodate broken HP-UX B.11.00 make(1) sort -u -t : -k 2,2 -k 4,4 -k 5,5 test/results.tab | \ awk -F: ' \ BEGIN { \ print "@multitable {@code{Linux 2.6.18-1.2257.fc5smp}} {@code{/opt/SUNWspro/bin/c99}} {@code{--disable-shared}}"; \ print "@headitem O/S @tab Compiler @tab @code{configure} Option"; \ } \ $$6 == 0 { \ printf "@item @code{%s} @tab @code{%s} @tab @code{%s}\n", \ $$2, $$4, $$5; \ } \ END { \ print "@end multitable"; \ }' >$@ sleep 2 # to accomodate broken HP-UX B.11.00 make(1) make.texi: test/results.tab sleep 2 # to accomodate broken HP-UX B.11.00 make(1) awk -F: '$$6 == 1 {printf "%s:%s\n", $$2, $$3}' test/results.tab | \ sort -t : -u | \ awk -F: ' \ BEGIN { \ print "@multitable {@code{Linux 2.6.18-1.2257.fc5smp}} {@code{/usr/bin/posix/make}}"; \ print "@headitem O/S @tab @code{make} Utility"; \ } \ { \ printf "@item @code{%s} @tab @code{%s}\n", $$1, $$2; \ } \ END { \ print "@end multitable"; \ }' >$@ sleep 2 # to accomodate broken HP-UX B.11.00 make(1) remote-checks: dist cd test && $(MAKE) $(AM_MAKEFLAGS) $@ $(MAKE) udunits2.html ftp: dist -git commit -a git tag -f v$(VERSION) cp $(distArchive) /web/ftp/pub/$(PACKAGE)/ mailx -s '$(distName) now available' -a CHANGE_LOG \ ed@unidata.ucar.edu toc.xml.new cp /web/content/downloads/$(PACKAGE)/toc.xml \ /web/content/downloads/$(PACKAGE)/toc.xml.old mv toc.xml.new /web/content/downloads/udunits/toc.xml available: ftp web-update download-update .PHONY: hostchecks hostcheck remote-checks web-update ftp \ download-update available udunits2.info: version.texi success.texi failure.texi make.texi COPYRIGHT udunits2.html: version.texi success.texi failure.texi make.texi COPYRIGHT udunits2.pdf: version.texi success.texi failure.texi make.texi COPYRIGHT $(srcdir)/version.texi: $(srcdir)/stamp-vti @cp $(srcdir)/stamp-vti $@ udunits-2.2.0/package.properties0000644000175000017500000000011612260406756020057 0ustar amckinstryamckinstryPKG_NAME=udunits PKG_VERSION=2.2.0 PKG_RELEASE=13 PKG_INDEX_HTML=udunits2.htmludunits-2.2.0/puppet/0000755000175000017500000000000012260406756015665 5ustar amckinstryamckinstryudunits-2.2.0/puppet/ubuntu-devel.pp0000644000175000017500000000105312260406756020644 0ustar amckinstryamckinstrygroup { "puppet": ensure => "present", } File { owner => 0, group => 0, mode => 0644 } Exec { path => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'], } package {'make': ensure => present, } package {'libcunit1': ensure => present, } package {'libcunit1-dev': ensure => present, } package {'cmake': ensure => present, } package {'expat': ensure => present, } package {'libexpat-dev': ensure => present, } exec {'bashrc': command => 'echo "set -o vi" >>/home/vagrant/.bashrc', unless => 'grep "set *-o" /home/vagrant/.bashrc', }udunits-2.2.0/puppet/centos-devel.pp0000644000175000017500000000077312260406756020625 0ustar amckinstryamckinstrygroup { "puppet": ensure => "present", } File { owner => 0, group => 0, mode => 0644 } Exec { path => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'], } package {'expat-devel': ensure => present, } package {'gcc': ensure => present, } package {'CUnit-devel': ensure => present, } package {'rpm-build': ensure => present, } package {'ruby': ensure => present, } exec {'bashrc': command => 'echo "set -o vi" >>/home/vagrant/.bashrc', unless => 'grep "set *-o" /home/vagrant/.bashrc', } udunits-2.2.0/puppet/precise32_run.pp0000644000175000017500000000074012260406756020712 0ustar amckinstryamckinstrygroup { "puppet": ensure => "present", } File { owner => 0, group => 0, mode => 0644 } Exec { path => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'], } exec {'update': command => 'apt-get update', } package {'expat': ensure => present, require => Exec['update'], } package {'libexpat-dev': ensure => present, require => Exec['update'], } exec {'bashrc': command => 'echo "set -o vi" >>/home/vagrant/.bashrc', unless => 'grep "set *-o" /home/vagrant/.bashrc', }udunits-2.2.0/CHANGE_LOG0000644000175000017500000002354512260406756015732 0ustar amckinstryamckinstry2.2.0 New Features: Program udunits2(1): Added "-H have" and "-W want" options. Added support for numeric unit amount so that "0 degC" equals "32 degF". Library udunits2(3): Added ut_get_path_xml() to retrieve pathname of XML unit database. Units Database: Added units "molecule" (for conversion with "mole") and "bit". Misc: Removed bundled EXPAT package. Ported code to 32-bit Windows-7 under MinGW. Added explicit chapters on the unit utility and unit library to the top-level package documentation. Bug Fixes: Library udunits2(3): Corrected logic of checking for location of element. Units Database: Corrected ISO Latin-1 encodings that somehow got corrupted. Release Engineering: Added support for building by CMake and for creating binary distributions by CPack. Added scripts and configuration-files to support continuous-delivery. Added acceptance-test scripts for 32-bit Ubuntu 12 (Precise Pangolin) and 32-bit Windows-7. Currently, only the Ubuntu script is used in the continuous-delivery pipeline. Misc: Changed file LICENSE to COPYRIGHT and corrected copyright year in many files. Refactored the documentation to make it more version aware. 2.1.24 2011-09-12 15:01-600 Removed superfluous "the" from library documentation. Added (against my better judgement) symbols "ppm", "ppb", "ppt", "ppq", and (shamefully) symbols "ppmv", "ppbv", "pptv", and "ppqv" to the "common" units database. Improved ut_decode_time(): the returned "seconds" value will now always be less than 60. Thanks Christian. 2.1.23 2011-05-19 13:35:40-600 Corrected "make install". Will now create the installation-directory $(DESTDIR)$(htmldir) for holding the symbolic links for HTML access to the unit database if that directory doesn't exist. Modified "formatter.c" to more rigorously handle the return value of snprintf(). Modified documentation on ut_format() to indicate that the number of bytes returned depends on the snprintf() function that's used. 2.1.22 2011-05-16 10:50:34-600 Corrected ut_compare(3) for Galilean units (e.g., "1.01 m" and "1.1 m"). Corrected access to units database from documentation for both installations and the online webpages. Added shared library version numbers. Modified use of snprinf(3) in "formatter.c" to handle case where snprintf(3) returns the number of characters that *would* have been printed had the buffer been big enough (change in Unix standard from X-Open 2 to X-Open 3). This should prevent segmentation violations from occurring if the print-buffer is too small. Thank you Alex Cobb. 2.1.21 2011-01-24 Eliminate expectation and use of leading scale factor in the "have" unit of udunits2(1). Add verification of commit status to "make ftp". Add dependency of documentation on version. Add "force" flag to tagging rule in makefile. 2.1.20 2010-12-20 Added "fahrenheit" as an alias for "degrees fahrenheit". Added hyperlinks from HTML documentation to XML files of the units database. 2.1.19 2010-08-17 Moved ut_set_error_message_handler(ut_ignore) call in version 2.1.18 to eliminate more messages. 2.1.18 2010-08-13 Made the UDUNIT-1 function utInit() call ut_set_error_message_handler(ut_ignore) to make use of the UDUNITS-1 API more backward compatible. 2.1.17 2010-06-23 Added tagging of version in repository to "make ftp". Moved call to ut_set_second() in XML parser from after the XML file is read to as soon as the "second" unit is encountered. 2.1.16 2010-06-21 Corrected and updated definition of "e" -- the charge of an electron. 2.1.15 2010-05-27 Corrected return value of ut_get_status() when ut_parse() fails due to a syntax error. Added missing "void" parameter to declarations of UDUNITS-1 functions utIsInit() and utTerm(). Added commentary about the hybrid Gregorian/Julian calendar to the library documentation. Added the following units: "potential_vorticity_unit" (1e-6 m2 s-1 K kg-1) "einstein" (mole) Added "u" as a symbol for "micro". 2.1.14 2010-01-29 Modified the build procedure. It now 1) Builds the Expat (XML parsing) library that's bundled with the UDUNITS-2 package if and only if the host system doesn't have one; and 2) Installs the bundled Expat library if that library is built. Documented the need for linking against an Expat library. 2.1.13 2010-01-21 Modified the build procedure slightly. It now 1) Supports cross-compilation; and 2) Installs the info(1) documentation files by default. 2.1.12 2010-01-11 Corrected initialization of time-origin to prevent inconsistent results from ut_decode_time(). Thanks to David Pierce at the Scripps Institution of Oceanography. 2.1.11 2009-10-23 Added missing percent (%) unit. 2.1.10 2009-10-21 Fixed memory-related problems reported by valgrind(1). Changed $(pkgdatarootdir) to $(pkgdatadir) in the top-level Makefile. Corrected the syntax in the definition of the US survey foot. 2.1.9 2009-09-09 Fixed bug in ut_are_convertible() that caused it to return true for m2.s-2 and m.s-2. Changed installation directory for units database files from $(datadir) (default: /usr/local/share) to $(pkgdatadir) (default: /usr/local/share/udunits). Changed name of "ut_unit*" member in the UDUNITS-1 "utUnit" backward-compatibility structure from "ut_unit" to "unit2" because, unlike C, the g++ compiler doesn't allow a member to have the same name as a typedef. Added version specification to the top-level UDUNITS-2 documentation. 2.1.8 2009-06-19 Corrected definition of "lbf": was "2000 force_pounds"; is now "1 force_pound". 2.1.7 2009-05-05 Replaced angle brackets with quotation marks in inclusion of the UDUNITS-2 header-file by the UDUNITS-1 header-file. This was done to accomodate ncview's configure-script and because it's the right thing to do because both header-files are installed in the same directory. Added test for math library to configure script to support systems whose C library doesn't have them. Improved the process for making the "results.tab" target in the test/ subdirectory. Added delays to process for creating documentation source to accomodate broken HP-UX B.11.00 make(1). Added "make check" to git pre-commit hook. 2.1.6 2009-04-15 Added to the installed, top-level, UDUNITS-2 documentation, commentary about the existence of a version 1 C API in the package. Moved the UDUNITS-1 API into the UDUNITS-2 library subdirectory, "lib", in order to allow "make check" to build the package. 2.1.5 2009-03-24 Fixed bug in udunits2(1) utility introduced in version 2.1.2. Entering a "have" unit that didn't have a numerical first component risked a segmentation violation. 2.1.4 2009-03-24 Documented the change in meaning of the symbol "g" from the original package (standard free fall) to this package (gram). Returned HP-UX to the set of tested operating systems. 2.1.3 2009-03-23 Corrected typos in XML units database for "US_survey_foot" and "international_foot": removed embedded quotation marks. 2.1.2 2009-03-19 Corrected program udunits2(1): it now correctly parses units like "0.1 lg(re 1.0e-12 W.m-2)". Made the dimensionless unit one format as "1". Corrected rule for target "web-update": changed "distname" to "distName". Corrected the development make(1) target "hostcheck": added setting of MAKEFLAGS to the empty string before invoking make(1). 2.1.1 2009-03-13 Corrected and improved the development make(1) targets "ftp" and "download-update". Added publication of the XML database on the UDUNITS website to the target "web-update". Corrected typo in API documentation. 2.1.0 2009-03-11 Added UDUNITS-1 API. This thin interface uses the UDUNITS-2 library. Users will have to recompile their UDUNITS-1-based code using the new "udunits.h" header-file and rebuild their programs using the new UDUNITS-2 library. Because the UDUNITS-1 API uses the "utUnit" data-structure and the UDUNITS-2 API uses pointers to "ut_unit" data-structures, a small memory-leak is possible in code that creates many units. This leak can be avoided by calling the new method utFree(utUnit*) when the unit is no longer needed. Added some "const" qualifiers to the API. Modified ut_format() for timestamp units. It now prints the long form (with hyphens and colons) if the year of the origin is less than 1000 or greater than 9999. This was done to make ut_format() compatible with ut_parse(). 2.0.4 2009-02-21 Added copyright notices and LICENSE file. 2.0.3 2009-02-18 Added the function ut_root(const ut_unit* unit, int root) to return a root of a unit (e.g., "m2/s2" -> "m/s"). 2.0.2 2008-12-02 Changed order of calls to ut_set_status() and ut_handle_error_message() so that the status value is always set before the error-message handler is called. This allows error handlers to determine the cause of the message. 2.0.1 2008-11-13 Added parsing of timestamps that have dashes and colons but also use "T" (e.g., "seconds since 1970-01-01T00:00:00Z"). Corrected the regular expressions for matching the character-set specifier in the udunits2(1) program. 2.0.0 2007-07-18 Initial release. udunits-2.2.0/configure.scan0000644000175000017500000000145312260406756017202 0ustar amckinstryamckinstry# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CXX AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_RANLIB # Checks for libraries. # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([float.h inttypes.h stddef.h stdlib.h string.h strings.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T # Checks for library functions. AC_FUNC_MALLOC AC_CHECK_FUNCS([floor memmove memset modf pow strcasecmp strdup strpbrk]) AC_CONFIG_FILES([Makefile lib/Makefile]) AC_OUTPUT udunits-2.2.0/config.sub0000755000175000017500000010224012260406756016332 0ustar amckinstryamckinstry#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # Free Software Foundation, Inc. timestamp='2009-04-17' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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. # # 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. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tile*) basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: udunits-2.2.0/README0000644000175000017500000000076712260406756015242 0ustar amckinstryamckinstryThis package provides support for units of physical quantities. Its main components are: 1) A C library, "libudunits2", for: a) Obtaining a binary representation of a unit; b) Manipulating units arithmetically; and c) Obtaining a converter of numeric values between compatible units; 2) A utility, "udunits2", for a) Obtaining the definition of a unit; and b) Converting a numeric value between compatible units; and 3) An extensive database of units.udunits-2.2.0/udunits2.info0000644000175000017500000004010612260406756017003 0ustar amckinstryamckinstryThis is udunits2.info, produced by makeinfo version 4.13 from udunits2.texi. INFO-DIR-SECTION Science START-INFO-DIR-ENTRY * udunits-2: (udunits2). The Unidata package for units of physical quantities. END-INFO-DIR-ENTRY Copyright 2013 University Corporation for Atmospheric Research. All rights reserved. This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware. 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 CONTRIBUTORS 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 WITH THE SOFTWARE.  File: udunits2.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) UDUNITS-2 ********* This manual describes the UDUNITS-2 package, which contains a C library for units of physical quantities and a unit-definition and value-conversion utility. Copyright 2013 University Corporation for Atmospheric Research. All rights reserved. This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware. 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 CONTRIBUTORS 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 WITH THE SOFTWARE. * Menu: * Introduction:: Introduction * Differences:: How this package differs from the UDUNITS-1 package * Installation:: Installing this package * Library:: The unit library * Utility:: The unit utility * Database:: The unit database * Support:: Support for this package * Complete Index:: Complete index  File: udunits2.info, Node: Introduction, Next: Differences, Prev: Top, Up: Top 1 Introduction ************** The UDUNITS-2 package provides support for units of physical quantities. Its three main components are: 1) *note a C library: (udunits2lib)Top. for units of physical quantities; 2) *note a utility: (udunits2prog)Top.; for obtaining the definition of a unit and for converting numeric values between compatible units; and 3) an *note extensive database of units: Database.  File: udunits2.info, Node: Differences, Next: Installation, Prev: Introduction, Up: Top 2 How This Package Differs from the Original `UDUNITS' Package ************************************************************** The `UDUNIT-2' package differs from the `UDUNITS-1' package in the following ways: * *Support for non-ASCII characters:* The `UDUNITS-1' package only supports the ASCII character set. The `UDUNITS-2' package supports the following character sets: ASCII, ISO 8859-1 (Latin-1), and the UTF-8 encoding of ISO 10646 (Unicode). This means that unit string specifications like "`µ°F·Ω⁻¹'" are now supported (your viewer must support UTF-8 to display this string correctly). * *Support for logarithmic units:* The unit string specification "`0.1 lg(re 1 mW)'" specifies a deciBel unit with a one milliwatt reference level. Such units are fully integrated into the package and all meaningful operations and conversions are supported. * *Persistent value converters:* It is now possible to obtain a _converter_ data-object, which can be used to convert numeric values in one unit to numeric values in another, compatible unit. The values can be `float', `double', or one-dimensional arrays of `float's or `double's. * *Improved API:* Due to the above changes, it was not possible to keep the application programming interface (API) of the `UDUNITS-1' package. The new interface, however, is easily understood and easy to use. To support backward comptibility, the package does contain a version 1 C API, which uses the version 2 library. * *XML unit database:* The unit database is encoded using human-readable XML rather than a custom format. The XML parser included in the package supports an __ element to allow easy and convenient customization. * *No Fortran or Perl API:* Interfaces for these languages have not yet been created. Contact if you are interested in helping to create these interfaces. One thing that has not changed is that almost all unit string specifications understood by the `UDUNITS-1' package are also understood by the `UDUNITS-2' package. One exception is the symbol `g', which in version 1 of the package was associated with standard free fall (a unit of accelleration) but which is associated with the unit gram in version 2 of the package.  File: udunits2.info, Node: Installation, Next: Library, Prev: Differences, Up: Top 3 Installing this Package ************************* * Menu: * Binary:: Installing from a binary distribution * Source:: Installing from a source distribution  File: udunits2.info, Node: Binary, Next: Source, Up: Installation 3.1 Installing from a Binary Distribution ========================================= Currently, the only supported binary distribution is for 64-bit CentOS 6.4. If your computer is compatible with this (e.g., your computer is 64-bit CentOS, Fedora, or RedHat), then create the file `/etc/yum.repos.d/unidata.repo' with the following contents: [unidata] name=Unidata Repository baseurl=http://www.unidata.ucar.edu/yum-repo/CentOS/6/$basearch enabled=1 You should then be able to install this package in the usual manner. For example, su - yum install udunits  File: udunits2.info, Node: Source, Prev: Binary, Up: Installation 3.2 Installing from a Source Distribution ========================================= * Menu: * Prerequisites:: Prerequisites for this package * Obtain:: Obtaining this package * Unix:: Installing on Unix-like environments * Windows:: Installing on Windows environments  File: udunits2.info, Node: Prerequisites, Next: Obtain, Up: Source 3.2.1 Prerequisites for This Package ------------------------------------ The Expat library and header-files must be installed. Look for the library "libexpat" and the header-file "expat.h". If this package is to be tested (which is optional), then the CUnit library and header-files must be installed. Look for the library "libcunit" and the header-files "CUnit/CUnit.h" and "CUnit/Basic.h". If this package is to be built on a Windows system, then the CMake and MinGW packages must be installed. Look for the utility "cmake" and the directory/folder "MinGW".  File: udunits2.info, Node: Obtain, Next: Unix, Prev: Prerequisites, Up: Source 3.2.2 Obtaining this Package ---------------------------- Get the source for this package from its download-page at `ftp://ftp.unidata.ucar.edu/pub/udunits/' and unpack it in an appropriate place. For example, su - cd /usr/local/src wget -O - ftp://ftp.unidata.ucar.edu/pub/udunits/udunits-2.2.0-Source.tar.gz | gunzip -c | pax -r  File: udunits2.info, Node: Unix, Next: Windows, Prev: Obtain, Up: Source 3.2.3 Unix Installation Instructions ------------------------------------ * Menu: * Autoconf:: Autoconf-based installation * CMake:: CMake-based installation  File: udunits2.info, Node: Autoconf, Next: CMake, Up: Unix 3.2.3.1 Autoconf-based Installation ................................... Short instructions: ./configure [--prefix=ROOT] [--disable-shared] [CC=PATH] make make check # optional; requires CUNIT installation make install # also installs INFO documentation make install-html install-pdf # optional make clean By default, the installation root is `/usr/local'. Long instructions: 1. Go to the top-level source-directory of this package, e.g., cd udunits-2.2.0 2. If necessary, clean-up from a previous installation attempt by making the `distclean' target using the MAKE utility from step 2: MAKE distclean The option `--disable-shared' causes the build process to create a static library only: a sharable library is not created. This option is necessary if the `libtool' utility that's included in this package can't build a sharable library using the given compiler. 3. Execute the `configure' script. Specify the installation prefix, the compiler from the previous step, and any required option. For example, if you are on an HP-UX system and want to use the `/bin/c89' compiler and install under `/opt', then the following command is appropriate: ./configure --prefix=/opt --disable-shared CC=/bin/c89 If the installation prefix is not specified, then the default is to install under `/usr/local'. If the compiler isn't specified, then the default is to use `gcc'. 4. Build this package by making the default target using the MAKE utility from step 2: MAKE 5. If you wish to verify that this package works correctly, then make the `check' target using the MAKE utility from step 2: MAKE check This step is only effective if the `configure' script found an installed `CUNIT' unit-testing package. If that package wasn't found, then the above command will quickly exit without testing this package. 6. Install the *note library: (udunits2lib)Top, *note utility: (udunits2prog)Top, header-files, units-database, and INFO documentation files by making the `install' target using the MAKE utility from step 2: MAKE install 7. If desired, install the HTML and PDF documentation files by making one or more of the following targets using the MAKE utility from step 2: MAKE install-html install-pdf 8. Clean up by making the `clean' target using the MAKE utility from step 2: MAKE clean  File: udunits2.info, Node: CMake, Prev: Autoconf, Up: Unix 3.2.3.2 CMake-based Installation ................................ cmake make all [test] install [install_test] where the arguments in square brackets are optional.  File: udunits2.info, Node: Windows, Prev: Unix, Up: Source 3.2.4 Windows Installation Instructions --------------------------------------- Currently, only a 32-bit MinGW (http://www.mingw.org)-based installation is supported: cmake -G "MinGW Makefiles" cmake --build . [-DUDUNITS_INSTALL_PREFIX=_dir_] -- all [test] install [install_test] where arguments in square brackets are optional. The default installation-prefix is "`C:\Program Files (x86)\udunits-2.'MINOR.BUG", where MINOR and BUG are the minor version and bug-fix level, respectively.  File: udunits2.info, Node: Library, Next: Utility, Prev: Installation, Up: Top 4 Unit Library ************** *Note UDUNITS Library: (udunits2lib)UDUNITS Library, for details on this package's unit library.  File: udunits2.info, Node: Utility, Next: Database, Prev: Library, Up: Top 5 Unit Utility ************** *Note UDUNITS Utility: (udunits2prog)UDUNITS Utility, for details on this package's unit utility.  File: udunits2.info, Node: Database, Next: Support, Prev: Utility, Up: Top 6 The Units Database ******************** The database for the UDUNITS-2 package comprises one XML file containing unit prefixes and four XML files containing unit definitions: * SI unit prefixes (../../udunits/udunits2-prefixes.xml) * SI base units (../../udunits/udunits2-base.xml) * SI derived units (../../udunits/udunits2-derived.xml) * Units accepted for use with the SI (../../udunits/udunits2-accepted.xml) * Non-SI units (../../udunits/udunits2-common.xml)  File: udunits2.info, Node: Support, Next: Complete Index, Prev: Database, Up: Top 7 Support for this Package ************************** The home-page for this package can be found at `http://www.unidata.ucar.edu/software/udunits/'. Bug reports should be sent to .  File: udunits2.info, Node: Complete Index, Prev: Support, Up: Top Index ***** [index] * Menu: * database: Database. (line 6) * installation: Installation. (line 6) * Installation, binary: Binary. (line 6) * Installation, source: Source. (line 6) * Introduction: Introduction. (line 6) * Library, unit: Library. (line 6) * obtaining this package: Obtain. (line 6) * package, support: Support. (line 6) * prerequisites for this package: Prerequisites. (line 6) * support: Support. (line 6) * Utility, unit: Utility. (line 6)  Tag Table: Node: Top2155 Node: Introduction4728 Node: Differences5218 Node: Installation7704 Node: Binary7981 Node: Source8648 Node: Prerequisites9037 Node: Obtain9681 Node: Unix10121 Node: Autoconf10371 Node: CMake13034 Node: Windows13279 Node: Library13852 Node: Utility14067 Node: Database14279 Node: Support14854 Node: Complete Index15165  End Tag Table udunits-2.2.0/configure.ac0000644000175000017500000000771312260406756016646 0ustar amckinstryamckinstry# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # # Copyright 2013 University Corporation for Atmospheric Research # # This file is part of the UDUNITS-2 package. See the file COPYRIGHT # in the top-level source-directory of the package for terms and # conditions. # AC_PREREQ(2.59) AC_INIT(UDUNITS, 2.1.24, support-udunits@unidata.ucar.edu) AC_CONFIG_SRCDIR([lib/converter.c]) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_CONFIG_HEADERS([config.h]) CFLAGS_COVERAGE='' LIBS_COVERAGE='' AC_ARG_ENABLE([coverage], [AS_HELP_STRING([--enable-coverage],[Turn on code-coverage support])], [case "${enableval}" in yes) CFLAGS_COVERAGE='--coverage' LIBS_COVERAGE=-lgcov coverage_enabled=true;; no) ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-coverage]) ;; esac]) AC_SUBST(CFLAGS_COVERAGE) AC_SUBST(LIBS_COVERAGE) AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug],[Turn on debugging support])], [case "${enableval}" in yes) CFLAGS="-g${CFLAGS:+ $CFLAGS}" debug=true ;; no) CFLAGS="-O${CFLAGS:+ $CFLAGS}" debug=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;; esac], [if test "$coverage_enabled" = true; then CFLAGS="-g${CFLAGS:+ $CFLAGS}" debug=true else debug=false fi ]) AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) AM_CONDITIONAL([ENABLE_UDUNITS_1], [true]) AC_ARG_ENABLE([udunits-1], [AS_HELP_STRING([--disable-udunits-1], [Turn off support for the UDUNITS-1 API [default=enabled]])], [case "${enableval}" in no) AM_CONDITIONAL([ENABLE_UDUNITS_1], [false]) ;; yes) ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-udunits-1]) ;; esac]) # Ensure that compilation is optimized and with assertions disabled by default. CFLAGS=${CFLAGS:--O} CPPFLAGS=${CPPFLAGS:--DNDEBUG} # The default absolute pathname of the installed units database. "pkgdatadir" # isn't a configure-variable in the normal sense: it doesn't appear in # "config.status" yet appears in "Makefile"; consequently, the following # nonsense just to avoid defining the pathname in the makefile so that Eclipse # is happy. pkgdatadir=$(eval echo $(eval echo `echo ${datadir}`/${PACKAGE})) AC_DEFINE_UNQUOTED([DEFAULT_UDUNITS2_XML_PATH], ["${pkgdatadir}/udunits2.xml"], [The default absolute pathname of the installed units database]) # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O #if test "$ac_cv_prog_cc_${ac_cc}_c_o" = yes; then # case "$AM_CFLAGS" in # "-g") ;; # *) AM_CFLAGS="${AM_CFLAGS:+$AM_CFLAGS }-g";; # esac #fi AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_YACC AM_PROG_LEX AC_PROG_FC # Checks for libraries. AC_SEARCH_LIBS([dirname], [gen], , AC_MSG_ERROR([cannot find function dirname])) AC_SEARCH_LIBS([log10], [m], , AC_MSG_ERROR([cannot find function log10])) AC_SEARCH_LIBS([XML_StopParser], [expat], , AC_MSG_ERROR([cannot find EXPAT function XML_StopParser])) # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([float.h inttypes.h stddef.h stdlib.h string.h strings.h]) # Checks for the CUNIT unit-testing package LD_CUNIT= AC_MSG_NOTICE([Checking for the CUNIT unit-testing package.]) AC_CHECK_HEADER([CUnit/CUnit.h], [AC_CHECK_LIB([cunit], [CU_initialize_registry], [LD_CUNIT=-lcunit])]) AC_SUBST([LD_CUNIT]) if test "$LD_CUNIT"; then AC_MSG_NOTICE([CUNIT found. Enabling unit-tests.]) else AC_MSG_NOTICE([CUNIT not found. Disabling unit-tests.]) fi AM_CONDITIONAL([HAVE_CUNIT], [test "$LD_CUNIT"]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T # Checks for library functions. AC_CHECK_FUNCS([floor memmove memset modf pow strcasecmp strdup strpbrk]) AC_PROG_LIBTOOL AC_CONFIG_FILES([Makefile lib/Makefile lib/xmlFailures/Makefile lib/xmlSuccesses/Makefile prog/Makefile test/Makefile]) AC_OUTPUT udunits-2.2.0/config.h.cmake0000644000175000017500000000014312260406756017043 0ustar amckinstryamckinstry/* * C macros set by cmake(1) */ #define DEFAULT_UDUNITS2_XML_PATH "@DEFAULT_UDUNITS2_XML_PATH@" udunits-2.2.0/push.sh0000755000175000017500000000407412260406756015673 0ustar amckinstryamckinstry# This script does the following: # 1. Ensures correct version information in the CMake configuration-file # and the texinfo(1) version file; # 2. Updates the release number. # 3. Commits to the local repository if appropriate; # 4. Tags the HEAD revision with the current version; and # 5. Pushes to the remote repository # 6. Updates the package version of the previous release. set -e # exit upon error # # Get the package version information from the CHANGE_LOG file. # versionId=`awk '{print $1;exit}' CHANGE_LOG` majorId=`echo $versionId | cut -d . -f 1` minorId=`echo $versionId | cut -d . -f 2` patchId=`echo $versionId | cut -d . -f 3` test "$majorId" test "$minorId" test "$patchId" # # Set the package version in the CMake configuration-file. # sed " /^[ \t]*[Ss][Ee][Tt][ \t]*(VERSION_MAJOR[ \t]/cSET(VERSION_MAJOR $majorId) /^[ \t]*[Ss][Ee][Tt][ \t]*(VERSION_MINOR[ \t]/cSET(VERSION_MINOR $minorId) /^[ \t]*[Ss][Ee][Tt][ \t]*(VERSION_PATCH[ \t]/cSET(VERSION_PATCH $patchId)" \ CMakeLists.txt >CMakeLists.txt.tmp mv CMakeLists.txt.tmp CMakeLists.txt # # Set the package version in the texinfo(1) version file. # sed " /^@set EDITION/c@set EDITION $versionId /^@set VERSION/c@set VERSION $versionId" \ version.texi >version.texi.tmp mv version.texi.tmp version.texi # # Get the previous package information. # . package.properties # # If the current package version differs from that of the previous release # (i.e., the previous invocation of this script), # if ! test $versionId = $PKG_VERSION; then # # A new package version is being released. Reset the release number. # PKG_RELEASE=1 else # # The same package version is being released. Increment the release number. # PKG_RELEASE=$(($PKG_RELEASE + 1)) fi # # Save the package information. # sed " /PKG_VERSION/cPKG_VERSION=$PKG_VERSION /PKG_RELEASE/cPKG_RELEASE=$PKG_RELEASE" package.properties >package.properties.tmp mv package.properties.tmp package.properties # # Commit, tag, and push the package. # git commit -a || true git tag -f v$versionId git push udunits-2.2.0/version.texi0000644000175000017500000000014412260406756016727 0ustar amckinstryamckinstry@set UPDATED 1 November 2013 @set UPDATED-MONTH November 2013 @set EDITION 2.2.0 @set VERSION 2.2.0 udunits-2.2.0/aclocal.m40000644000175000017500000010741612260406756016221 0ustar amckinstryamckinstry# generated automatically by aclocal 1.11.1 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # 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. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.66],, [m4_warning([this file was generated for autoconf 2.66. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # # 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. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # 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. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # 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 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 # Free Software Foundation, Inc. # # 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 10 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # 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 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # 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 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. # # 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. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # 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 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 # Free Software Foundation, Inc. # # 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 # AM_PROG_LEX # ----------- # Autoconf leaves LEX=: if lex or flex can't be found. Change that to a # "missing" invocation, for better error output. AC_DEFUN([AM_PROG_LEX], [AC_PREREQ(2.50)dnl AC_REQUIRE([AM_MISSING_HAS_RUN])dnl AC_REQUIRE([AC_PROG_LEX])dnl if test "$LEX" = :; then LEX=${am_missing_run}flex fi]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # 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 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # 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 # AM_PROG_CC_C_O # -------------- # Like AC_PROG_CC_C_O, but changed for automake. AC_DEFUN([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC_C_O])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi dnl Make sure AC_PROG_CC is never called again, or it will override our dnl setting of CC. m4_define([AC_PROG_CC], [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # 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 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # # 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. # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. # # 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 4 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # 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 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # 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. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008 Free Software Foundation, Inc. # # 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 2 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005 Free Software Foundation, Inc. # # 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 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) udunits-2.2.0/publish.sh0000644000175000017500000001355612260406756016364 0ustar amckinstryamckinstry# Copies a binary distribution to the download area and ensures existence of # a source distribution in the download area. Does this if and only if the # upstream, binary-distribution-creating jobs in the delivery pipeline were # successful. # # This script is complicated by the fact that it will be invoked by every # upstream job that creates a binary distribution. # # Usage: # $0 pipeId nJobs binDistroFile srcDistroFile binRepoRelDir docDistroFile binDistroGlob pkgName indexHtml # # where: # pipeId Unique identifier for the parent delivery pipeline # instance (e.g., top-of-the-pipe job number) # nJobs Number of upstream jobs # binDistroFile Pathname of the binary distribution file # srcDistroFile Pathname of the source distribution file # binRepoRelDir Pathname of the binary repository directory relative to # the root of the binary repository # docDistroFile Pathname of the documentation distribution file # binDistroGlob Glob pattern matching filenames of all releases of # this version of the binary distribution of the package # pkgName Name of the package (e.g., "udunits") # indexHtml Name of the top-level HTML documentation file (e.g., # "udunits2.html") binRepoHost=spock # Name of computer hosting binary repository binRepoRoot=repo # Pathname of the root directory of the binary # repository. A relative pathname is resolved # against the home directory of $USER on # $binRepoHost srcRepoHost=webserver # Name of computer hosting source repository srcRepoDir=/web/ftp/pub/$pkgName # Pathname of source repository webHost=webserver # Name of computer hosting package website set -e # exit on failure # # Indicates if the outcome of the upstream jobs is decidable. # decidable() { test `ls $jobId.success $jobId.failure 2>/dev/null | wc -w` -ge $nJobs } # # Indicates if the upstream jobs were successful. # success() { test `ls $jobId.success 2>/dev/null | wc -w` -ge $nJobs } pipeId=${1:?Group ID not specified} nJobs=${2:?Number of upstream jobs not specified} binDistroFile=${3:?Binary distribution file not specified} srcDistroFile=${4:?Source distribution file not specified} binRepoRelDir=${5:?Relative pathname of binary repository directory not specified} docDistroFile=${6:?Documentation distribution file not specified} binDistroGlob=${7:?Release-independent, version-dependent filename glob pattern not specified} pkgName=${8:?Package name not specified} indexHtml=${9:?Top-level HTML documentation-file not specified} # # Ensure valid pathnames. # binDistroFile=`ls $binDistroFile` srcDistroFile=`ls $srcDistroFile` # # Form a unique identifier for this invocation. # binDistroFileName=`basename $binDistroFile` jobId=$pipeId-$binDistroFileName # # Remove any leftovers from an earlier delivery pipeline. # ls *.success *.failure 2>/dev/null | grep -v ^$jobId | xargs rm -rf # # Make known to all invocations of this script in the delivery pipeline the # outcome of the upstream job associated with this invocation. # if test -e $binDistroFile; then touch $jobId.success else touch $jobId.failure fi # # Wait until the outcome of all the upstream jobs can be decided. # while ! decidable; do sleep 3 done # # Copy the binary distribution to the binary repository. # binRepoDir=$binRepoRoot/$binRepoRelDir trap "ssh $binRepoHost rm -f $binRepoDir/$binDistroFileName; `trap -p ERR`" ERR success && scp $binDistroFile $binRepoHost:$binRepoDir # # Delete all previous binary releases of the same package version. # ssh $binRepoHost "ls $binRepoDir/$binDistroGlob | fgrep -v $binDistroFileName | xargs rm -f" # # Rebuild the binary repository. # ssh $binRepoHost $binRepoRoot/rebuild $binRepoRelDir srcDistroPath=/web/ftp/pub/$pkgName/`basename $srcDistroFile` # # If the source repository doesn't have the source distribution, # if ! ssh $srcRepoHost test -e $srcDistroPath; then # # Copy the source distribution to the source repository. # trap "ssh $srcRepoHost rm -f $srcDistroPath; `trap -p ERR`" ERR scp $srcDistroFile $srcRepoHost:$srcDistroPath fi pkgId=`basename $docDistroFile | sed 's/^\([^-]*-[0-9.]*\).*/\1/'` version=`echo $pkgId | sed 's/^[^-]*-//'` pkgWebDir=/web/content/software/$pkgName versionWebDir=$pkgWebDir/$pkgId # # If the package's website doesn't have this version's documentation, # if ! ssh $webHost test -e $versionWebDir; then # # Provision the package's website with the documentation distribution. NB: # Assumes that the first component of all pathnames in the distribution is # "share/". # trap "ssh $webHost rm -rf $versionWebDir; `trap -p ERR`" ERR gunzip -c $docDistroFile | ssh $webHost "cd $pkgWebDir && pax -r -s ';share/;$pkgId/;'" ssh $webHost "cd $versionWebDir && rm -f index.html && ln -s doc/$pkgName/${indexHtml} index.html" ssh $webHost "cd $versionWebDir && cp doc/$pkgName/CHANGE_LOG $pkgWebDir" # # Ensure that the top-level HTML file contains a reference to this version. # ssh -T $webHost <$version } /
  • $version<\/a>/d ' index.html >index.html.new cp index.html index.html.old mv index.html.new index.html # # Set the curent-version symbolic link to the current version # rm -f $pkgName-current ln -s $pkgId $pkgName-current EOF fiudunits-2.2.0/acceptance_test.cmd0000755000175000017500000000076312260406756020173 0ustar amckinstryamckinstryset PATH=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0 set PATH=%PATH%;C:\Program Files (x86)\Cmake 2.8\bin;C:\MinGW\bin set PATH=%PATH%;C:\Program Files (x86)\Expat 2.1.0\Bin set CMAKE_INCLUDE_PATH=C:\Program Files (x86)\Expat 2.1.0\Source\lib;C:\Users\vagrant\include set CMAKE_LIBRARY_PATH=C:\Program Files (x86)\Expat 2.1.0\Bin;C:\Users\vagrant\lib cmake -G "MinGW Makefiles" . && cmake --build . -- all test install install_test packageudunits-2.2.0/install-sh0000755000175000017500000003253712260406756016366 0ustar amckinstryamckinstry#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # 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 # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: udunits-2.2.0/CI-commit.sh0000755000175000017500000000045312260406756016472 0ustar amckinstryamckinstry# This script does the following: # 1. Builds the package; # 2. Tests the package; and # 3. Creates a source-distribution. set -e # exit if error # # Build and test the package and create a source-distribution. # rm -rf build mkdir build cd build cmake .. make all test package_sourceudunits-2.2.0/Vagrantfile0000644000175000017500000001227512260406756016544 0ustar amckinstryamckinstry# -*- mode: ruby -*- # vi: set ft=ruby : # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.define "centos64_64" do |centos64_64| centos64_64.vm.box = "centos-6.4-x86_64-devel" centos64_64.vm.network "private_network", ip: "192.168.56.102" centos64_64.vm.provision :puppet do |puppet| puppet.manifests_path = "puppet" puppet.manifest_file = "centos-devel.pp" end end config.vm.define "ubuntu12_32" do |ubuntu12_32| ubuntu12_32.vm.box = "precise32" ubuntu12_32.vm.network "private_network", ip: "192.168.56.103" ubuntu12_32.vm.provision :puppet do |puppet| puppet.manifests_path = "puppet" puppet.manifest_file = "ubuntu-devel.pp" end end # config.vm.define "win7" do |win7| # win7.vm.box = "win7" # end # All Vagrant configuration is done here. The most common configuration # options are documented and commented below. For a complete reference, # please see the online documentation at vagrantup.com. # Every Vagrant virtual environment requires a box to build off of. # config.vm.box = "precise32" # The url from where the 'config.vm.box' box will be fetched if it # doesn't already exist on the user's system. # config.vm.box_url = "http://domain.com/path/to/above.box" # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine. In the example below, # accessing "localhost:8080" will access port 80 on the guest machine. # config.vm.network :forwarded_port, guest: 80, host: 8080 # Create a private network, which allows host-only access to the machine # using a specific IP. # config.vm.network :private_network, ip: "192.168.33.10" # Create a public network, which generally matched to bridged network. # Bridged networks make the machine appear as another physical device on # your network. # config.vm.network :public_network # If true, then any SSH connections made will enable agent forwarding. # Default value: false # config.ssh.forward_agent = true # Share an additional folder to the guest VM. The first argument is # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. # config.vm.synced_folder "../data", "/vagrant_data" # Provider-specific configuration so you can fine-tune various # backing providers for Vagrant. These expose provider-specific options. # Example for VirtualBox: # # config.vm.provider :virtualbox do |vb| # # Don't boot with headless mode # vb.gui = true # # # Use VBoxManage to customize the VM. For example to change memory: # vb.customize ["modifyvm", :id, "--memory", "1024"] # end # # View the documentation for the provider you're using for more # information on available options. # Enable provisioning with Puppet stand alone. Puppet manifests # are contained in a directory path relative to this Vagrantfile. # You will need to create the manifests directory and a manifest in # the file win7.pp in the manifests_path directory. # # An example Puppet manifest to provision the message of the day: # # # group { "puppet": # # ensure => "present", # # } # # # # File { owner => 0, group => 0, mode => 0644 } # # # # file { '/etc/motd': # # content => "Welcome to your Vagrant-built virtual machine! # # Managed by Puppet.\n" # # } # # config.vm.provision :puppet do |puppet| # puppet.manifests_path = "manifests" # puppet.manifest_file = "init.pp" # end # Enable provisioning with chef solo, specifying a cookbooks path, roles # path, and data_bags path (all relative to this Vagrantfile), and adding # some recipes and/or roles. # # config.vm.provision :chef_solo do |chef| # chef.cookbooks_path = "../my-recipes/cookbooks" # chef.roles_path = "../my-recipes/roles" # chef.data_bags_path = "../my-recipes/data_bags" # chef.add_recipe "mysql" # chef.add_role "web" # # # You may also specify custom JSON attributes: # chef.json = { :mysql_password => "foo" } # end # Enable provisioning with chef server, specifying the chef server URL, # and the path to the validation key (relative to this Vagrantfile). # # The Opscode Platform uses HTTPS. Substitute your organization for # ORGNAME in the URL and validation key. # # If you have your own Chef Server, use the appropriate URL, which may be # HTTP instead of HTTPS depending on your configuration. Also change the # validation key to validation.pem. # # config.vm.provision :chef_client do |chef| # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME" # chef.validation_key_path = "ORGNAME-validator.pem" # end # # If you're using the Opscode platform, your validator client is # ORGNAME-validator, replacing ORGNAME with your organization name. # # If you have your own Chef Server, the default validation client name is # chef-validator, unless you changed the configuration. # # chef.validation_client_name = "ORGNAME-validator" end udunits-2.2.0/depcomp0000755000175000017500000004426712260406756015742 0ustar amckinstryamckinstry#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2009-04-28.21; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free # Software Foundation, Inc. # This program 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, or (at your option) # any later version. # 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. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputing dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u="sed s,\\\\\\\\,/,g" depmode=msvisualcpp fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add `dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: udunits-2.2.0/prog/0000755000175000017500000000000012260406756015317 5ustar amckinstryamckinstryudunits-2.2.0/prog/Makefile.am0000644000175000017500000000170612260406756017357 0ustar amckinstryamckinstry# Copyright 2013 University Corporation for Atmospheric Research # # This file is part of the UDUNITS-2 package. See the file COPYRIGHT # in the top-level source-directory of the package for copying and # redistribution conditions. # ## Process this file with automake to produce Makefile.in bin_PROGRAMS = udunits2 LDADD = ../lib/libudunits2.la @LIBS@ TEXINFO_TEX = ../texinfo.tex info_TEXINFOS = udunits2prog.texi AM_MAKEINFOFLAGS = -I $(top_srcdir) AM_MAKEINFOHTMLFLAGS = --no-split -I $(top_srcdir) AM_CPPFLAGS = -I$(top_srcdir)/lib MOSTLYCLEANFILES = lint.log *.ln LINTFLAGS = -u LINT = lint TAGS_FILES = $(top_srcdir)/lib/*.c $(top_srcdir)/lib/*.h EXTRA_DIST = \ CMakeLists.txt \ udunits2prog.html \ udunits2prog.pdf .c.ln: $(LINT.c) $(AM_CPPFLAGS) $(CPPFLAGS) -c $< .c.i: $(CPP) $(AM_CPPFLAGS) $(CPPFLAGS) $< >$@ debug: udunits2 UDUNITS2_XML_PATH=$(top_srcdir)/lib/udunits2.xml libtool \ --mode=execute gdb udunits2 udunits-2.2.0/prog/udunits2prog.texi0000644000175000017500000000731612260406756020666 0ustar amckinstryamckinstry\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename udunits2prog.info @settitle udunits2 Program Guide @c %**end of header @dircategory Science @direntry * udunits2: (udunits2prog). The Unidata units-conversion program. @end direntry @copying @include COPYRIGHT @end copying @titlepage @title The @code{udunits2} Program @author Steven R. Emmerson @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top, Synopsis, (dir), (dir) @top udunits2 This manual describes how to use the @code{udunits2} program. This program allows you to discover the definition of a unit as well as convert numeric values between compatible units. @insertcopying @end ifnottex @menu * Synopsis:: Terse usage example * Options:: Command-line options * Description:: Description of the program * See Also:: Additional information * Complete Index:: Complete index @end menu @node Synopsis, Options, Top, Top @chapter Synopsis @cindex synopsis @example udunits2 -h @end example @example udunits2 [-A|-L|-U] [-r] [-H have] [-W want] [XML_file] @end example @node Options, Description, Synopsis, Top @chapter Options @cindex options The following options and arguments are supported: @table @code @item -A Use the ASCII character-set. @item -L Use the ISO Latin-1 (ISO-8859-1) character-set. @item -U Use the full Unicode character-set with UTF-8 encoding. @item -h Print a help message. @item -r Reveal any problems with the units database (by default, no error messages are printed during import of the database). @item -H have Use @code{have} unit for conversion. The default is the reply to the prompt. @item -W want Use @code{want} unit for conversion. An empty string requests the definition of the @code{have} unit. The default is the reply to the prompt. @item XML_file The pathname of the XML-formatted units database. If not specified, then the default, compile-time pathname is used. @end table @node Description, See Also, Options, Top @chapter Description When successfully started without the @code{-H have} or @code{-W want} options, the program will print the prompt @example You have: @end example At this point you can exit the program by entering the end-of-file character (usually control-D) or continue by entering either a value or a unit. (a value comprises a numerical value and a unit. For example, @example You have: 80 km/h You want: @end example At this point, if you enter a blank line, then the program will assume that you entered a unit in the previous line and will print the definition of that unit in terms of the base units of the unit-system that it imported on startup. For example, @example You have: 80 km/h You want: 22.2222222222222 m.s-1 You have: @end example Details of the formatting depend on the character-set being used. @xref{Options}. Alternatively, at the ``@kbd{You want:}'' prompt you can enter the unit in which you want the previously-entered value. For example, @example You have: 80 km/h You want: mi/h 80 km/h = 49.7097 mi/h x/(mi/h) = 0.621371*(x/(km/h)) You have: @end example The first line after ``@kbd{You want:}'' shows the ``have'' value in the desired ``want'' unit. The second line shows the transformation between numerical values in the ``have'' unit to numerical values in the ``want'' unit. The symbol ``@kbd{x}'' represents the physical quantity in question. See @url{http://physics.nist.gov/Pubs/SP811/sec07.html}. @node See Also, Complete Index, Description, Top @chapter See Also @xref{Top, , UDUNITS-2, udunits2lib, The UDUNITS-2 C API Guide}, for information on the UDUNITS-2 library, which is used by this program. @node Complete Index, , See Also, Top @unnumbered Index @printindex cp @bye udunits-2.2.0/prog/udunits2.c0000644000175000017500000003620012260406756017241 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research. All rights * reserved. * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * This program prints definitions of units of physical quantities and converts * values between such units. */ #include "config.h" #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include #include #include #include #ifndef _POSIX_MAX_INPUT # define _POSIX_MAX_INPUT 255 #endif static const char* _cmdHave; /* command-line "have" unit specification */ static const char* _cmdWant; /* command-line "want" unit specification */ static int _reveal; /* reveal problems with unit database? */ static int _encodingSet; /* is the character encoding set? */ static ut_encoding _encoding; /* the character encoding to use */ static const char* _progname; static const char* _xmlPath = NULL; /* use default path */ static ut_system* _unitSystem; static double _haveUnitAmount; /* amount of "have" unit */ static char _haveUnitSpec[_POSIX_MAX_INPUT+1]; /* "have" unit minus amount */ static char _wantSpec[_POSIX_MAX_INPUT+1]; /* complete "want" unit specification */ static ut_unit* _haveUnit; /* "have" unit minus amount */ static ut_unit* _wantUnit; /* complete "want" unit */ static int _wantDefinition; /* "have" unit definition desired? */ static int _formattingOptions = UT_DEFINITION; static int _exitStatus = EXIT_FAILURE; static void usage(void) { (void)fprintf(stderr, "Usage:\n" " %s -h\n" " %s [-A|-L|-U] [-r] [-H have] [-W want] [XML_file]\n" "\n" "where:\n" " -A Use ASCII encoding (default).\n" " -L Use ISO-8859-1 (ISO Latin-1) encoding.\n" " -U Use UTF-8 encoding.\n" " -h Help. Print this message.\n" " -r Reveal any problems in the database.\n" " -H have Use \"have\" unit for conversion. Default is reply to prompt.\n" " -W want Use \"want\" unit for conversion. Empty string requests\n" " definition of \"have\" unit. Default is reply to prompt.\n" " XML_file XML database file. Default is \"%s\".\n", _progname, _progname, DEFAULT_UDUNITS2_XML_PATH); } /** * Prints an error-message to the standard error stream. * * @param format The format for the error-message. It shouldn't have a * trailing newline. * @param ... Arguments referenced by the format. */ static void errMsg( const char* const format, ...) { (void)fprintf(stderr, "%s: ", _progname); { va_list ap; va_start(ap, format); (void)vfprintf(stderr, format, ap); va_end(ap); } (void)fputc('\n', stderr); } static int decodeCommandLine( int argc, char* const* argv) { int c; int success = 0; _progname = basename(argv[0]); while ((c = getopt(argc, argv, "ALUhrH:W:")) != -1) { switch (c) { case 'A': _encoding = UT_ASCII; _encodingSet = 1; continue; case 'H': _cmdHave = optarg; continue; case 'W': _cmdWant = optarg; continue; case 'L': _encoding = UT_LATIN1; _encodingSet = 1; continue; case 'U': _encoding = UT_UTF8; _encodingSet = 1; continue; case 'r': _reveal = 1; continue; case 'h': _exitStatus = EXIT_SUCCESS; /*FALLTHROUGH*/ case '?': usage(); break; default: errMsg("Unknown option \"%c\"", c); usage(); } break; } if (c == -1) { if (optind < argc) _xmlPath = argv[optind]; success = 1; } return success; } /** * Returns a lower-case copy of a NUL-terminated string. * * @param string The NUL-terminated string to be copied. * @retval NULL The string couldn't be copied. An error-message is * printed to the standard error stream. * @return A NUL-terminated lower-case copy of the string. The * caller should call free() on the string when it is no * longer needed. * @raise SIGSEGV if "string" is NULL. */ static char* duplower( const char* string) { char* const copy = malloc(strlen(string)+1); if (copy == NULL) { errMsg("Couldn't copy string \"%s\": %s", string, strerror(errno)); } else { char* cp = copy; while (*cp++ = tolower(*string++)) ; /* empty */ } return copy; } /** * Sets the character encoding from a (case insensitive) string specification * of the encoding that might be embedded in a larger string. * * @param value The string specification of the encoding. Contains * one of the substrings "ascii", "latin1", "latin?1", * "8859", "8859?1", "utf8", or "utf?8" (where the '?' * is one of the characters ' ', '-', '_', or '.'). If the * string contains more than one of these substrings, then * the result is unspecified. * @return Whether or not the character encoding was set from the * given string specification. 0 means no; otherwise, yes. */ static int setEncodingFromEmbeddedString( char* value) { char* lowerValue = duplower(value); int success = 0; if (lowerValue != NULL) { typedef struct { const char* string; const ut_encoding encoding; } Entry; static const Entry entries[] = { {"ascii", UT_ASCII}, {"latin1", UT_LATIN1}, {"latin 1", UT_LATIN1}, {"latin-1", UT_LATIN1}, {"latin_1", UT_LATIN1}, {"latin.1", UT_LATIN1}, {"8859 1", UT_LATIN1}, {"8859-1", UT_LATIN1}, {"8859_1", UT_LATIN1}, {"8859.1", UT_LATIN1}, {"utf8", UT_UTF8}, {"utf 8", UT_UTF8}, {"utf-8", UT_UTF8}, {"utf_8", UT_UTF8}, {"utf.8", UT_UTF8} }; const Entry* entry; for (entry = entries; entry < entries + sizeof(entries)/sizeof(entries[0]); entry++) { if (strstr(lowerValue, entry->string) != NULL) { _encoding = entry->encoding; _encodingSet = 1; success = 1; break; } } free(lowerValue); } return success; } /** * Sets the character encoding from a (case insensitive but exact) string * specification of the encoding. * * @param value The string specification of the encoding. One of * "c" or "posix". * @return Whether or not the encoding was set. 0 means no; * otherwise, yes. */ static int setEncodingFromExactString( char* value) { if (strcasecmp(value, "c") == 0 || strcasecmp(value, "posix") == 0) { _encoding = UT_ASCII; _encodingSet = 1; return 1; } return 0; } /** * Sets the character encoding from a (case insensitive) string specification * of the encoding. * * @param value The string specification of the encoding or NULL. If * not NULL, then one of "c" or "posix", or a string that * contains one of the substrings "ascii", "latin1", * "latin?1", "8859", "8859?1", "utf8", or "utf?8" (where * the '?' is one of the characters ' ', '-', '_', or '.'). * If the string contains multiple instances of the * substrings, then the result is unspecified. */ static void setEncoding( char* value) { if (value != NULL) { if (!setEncodingFromExactString(value)) (void)setEncodingFromEmbeddedString(value); } } static int ensureEncodingSet() { if (!_encodingSet) { setEncoding(getenv("LC_ALL")); if (!_encodingSet) { setEncoding(getenv("LC_CTYPE")); if (!_encodingSet) { setEncoding(getenv("LANG")); if (!_encodingSet) { errMsg("Character encoding not specified and not settable " "from environment variables LC_ALL, LC_CTYPE, or LANG. " "Assuming ASCII encoding."); setEncoding("ASCII"); } } } } if (_encodingSet) _formattingOptions |= _encoding; return _encodingSet; } static int readXmlDatabase(void) { int success = 0; if (!_reveal) ut_set_error_message_handler(ut_ignore); _unitSystem = ut_read_xml(_xmlPath); ut_set_error_message_handler(ut_write_to_stderr); if (_unitSystem != NULL) { success = 1; } else { ut_status status; errMsg("Couldn't initialize unit-system from database \"%s\": %s", ut_get_path_xml(_xmlPath, &status), strerror(errno)); } return success; } /* * Prompt the user and get a specification. */ static int getSpec( const char* const prompt, char* const spec, const size_t size) { int nbytes = -1; /* failure */ if (fputs(prompt, stdout) == EOF) { errMsg("Couldn't write prompt: %s", strerror(errno)); } else if (fgets(spec, size, stdin) == NULL) { putchar('\n'); if (feof(stdin)) { _exitStatus = EXIT_SUCCESS; } else { errMsg("Couldn't read from standard input: %s", strerror(errno)); } } else { /* * Trim any whitespace from the specification. */ (void)ut_trim(spec, _encoding); nbytes = strlen(spec); } return nbytes; } static int decodeInput( const char* const buf) { int success = 0; if (sscanf(buf, "%lg %[^ \t\n]", &_haveUnitAmount, _haveUnitSpec) != 2) { _haveUnitAmount = 1; (void)strcpy(_haveUnitSpec, buf); } ut_free(_haveUnit); _haveUnit = ut_parse(_unitSystem, _haveUnitSpec, _encoding); if (_haveUnit == NULL) { errMsg("Don't recognize \"%s\"", _haveUnitSpec); } else { success = 1; } return success; } static int getInputValue(void) { int success = 0; if (_cmdHave) { static int initialized = 0; if (initialized) { if (_cmdWant == NULL) { /* * Multiple, prompt-driven conversions desired. */ success = 1; } else { /* * Single, previous, command-line-driven conversion desired. */ success = 0; _exitStatus = EXIT_SUCCESS; } } else { success = decodeInput(_cmdHave); initialized = 1; } } else { for (;;) { char buf[sizeof(_haveUnitSpec)]; int nbytes = getSpec("You have: ", buf, sizeof(buf)); if (nbytes < 0) break; if (nbytes > 0) { success = decodeInput(buf); if (success) break; } } } return success; } static int decodeOutput( const char* const buf) { int success = 0; size_t nbytes = strlen(buf); if (nbytes == 0) { _wantDefinition = 1; success = 1; } else { ut_free(_wantUnit); _wantDefinition = 0; _wantUnit = ut_parse(_unitSystem, buf, _encoding); if (_wantUnit == NULL) { errMsg("Don't recognize \"%s\"", buf); } else { success = 1; } } return success; } static int getOutputRequest(void) { int success = 0; if (_cmdWant) { static int initialized = 0; if (initialized) { success = 1; } else { (void)strncpy(_wantSpec, _cmdWant, sizeof(_wantSpec)); _wantSpec[sizeof(_wantSpec)-1] = 0; success = decodeOutput(_wantSpec); initialized = 1; } } else { for (;;) { int nbytes = getSpec("You want: ", _wantSpec, sizeof(_wantSpec)); if (nbytes < 0) break; success = decodeOutput(_wantSpec); if (success) break; } } return success; } static int handleRequest(void) { int success = 0; if (getInputValue()) { if (getOutputRequest()) { if (_wantDefinition) { char buf[256]; ut_unit* unit = ut_scale(_haveUnitAmount, _haveUnit); int nbytes = ut_format(unit, buf, sizeof(buf), _formattingOptions); if (nbytes >= sizeof(buf)) { errMsg("Resulting unit specification is too long"); } else if (nbytes >= 0) { buf[nbytes] = 0; (void)printf(" %s\n", buf); } ut_free(unit); } else if (!ut_are_convertible(_wantUnit, _haveUnit)) { errMsg("Units are not convertible"); } else { cv_converter* conv = ut_get_converter(_haveUnit, _wantUnit); if (conv == NULL) { errMsg("Couldn't get unit converter"); } else { char haveExp[_POSIX_MAX_INPUT+1]; char exp[_POSIX_MAX_INPUT+1]; char whiteSpace[] = " \t\n\r\f\v\xa0"; int needsParens = strpbrk(_wantSpec, whiteSpace) != NULL; int n; (void)printf( needsParens ? " %g %s = %g (%s)\n" : " %g %s = %g %s\n", _haveUnitAmount, _haveUnitSpec, cv_convert_double(conv, _haveUnitAmount), _wantSpec); (void)sprintf(haveExp, strpbrk(_haveUnitSpec, whiteSpace) || strpbrk(_haveUnitSpec, "/") ? "(x/(%s))" : "(x/%s)", _haveUnitSpec); n = cv_get_expression(conv, exp, sizeof(exp), haveExp); if (n >= 0) (void)printf( strpbrk(_wantSpec, whiteSpace) || strpbrk(_wantSpec, "/") ? " x/(%s) = %*s\n" : " x/%s = %*s\n", _wantSpec, n, exp); cv_free(conv); } } success = 1; } } return success; } int main( const int argc, char* const* const argv) { if (decodeCommandLine(argc, argv)) { if (ensureEncodingSet()) { if (readXmlDatabase()) { while (handleRequest()) ; /* EMPTY */ } } } return _exitStatus; } udunits-2.2.0/prog/udunits2prog.html0000644000175000017500000002525612260406756020664 0ustar amckinstryamckinstry udunits2 Program Guide

    udunits2 Program Guide


    Next: , Previous: (dir), Up: (dir)

    udunits2

    This manual describes how to use the udunits2 program. This program allows you to discover the definition of a unit as well as convert numeric values between compatible units.

    Copyright 2013 University Corporation for Atmospheric Research. All rights reserved.

    This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) <http://www.unidata.ucar.edu>.

    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware.

    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 CONTRIBUTORS 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 WITH THE SOFTWARE.


    Next: , Previous: Top, Up: Top

    1 Synopsis

         udunits2 -h
    
         udunits2 [-A|-L|-U] [-r] [-H have] [-W want] [XML_file]
    


    Next: , Previous: Synopsis, Up: Top

    2 Options

    The following options and arguments are supported:

    -A
    Use the ASCII character-set.
    -L
    Use the ISO Latin-1 (ISO-8859-1) character-set.
    -U
    Use the full Unicode character-set with UTF-8 encoding.
    -h
    Print a help message.
    -r
    Reveal any problems with the units database (by default, no error messages are printed during import of the database).
    -H have
    Use have unit for conversion. The default is the reply to the prompt.
    -W want
    Use want unit for conversion. An empty string requests the definition of the have unit. The default is the reply to the prompt.
    XML_file
    The pathname of the XML-formatted units database. If not specified, then the default, compile-time pathname is used.


    Next: , Previous: Options, Up: Top

    3 Description

    When successfully started without the -H have or -W want options, the program will print the prompt

         You have:
    

    At this point you can exit the program by entering the end-of-file character (usually control-D) or continue by entering either a value or a unit. (a value comprises a numerical value and a unit. For example,

         You have: 80 km/h
         You want:
    

    At this point, if you enter a blank line, then the program will assume that you entered a unit in the previous line and will print the definition of that unit in terms of the base units of the unit-system that it imported on startup. For example,

         You have: 80 km/h
         You want:
             22.2222222222222 m.s-1
         You have:
    

    Details of the formatting depend on the character-set being used. See Options.

    Alternatively, at the “You want:” prompt you can enter the unit in which you want the previously-entered value. For example,

         You have: 80 km/h
         You want: mi/h
             80 km/h = 49.7097 mi/h
             x/(mi/h) = 0.621371*(x/(km/h))
         You have:
    

    The first line after “You want:” shows the “have” value in the desired “want” unit.

    The second line shows the transformation between numerical values in the “have” unit to numerical values in the “want” unit. The symbol “x” represents the physical quantity in question. See http://physics.nist.gov/Pubs/SP811/sec07.html.


    Next: , Previous: Description, Up: Top

    4 See Also

    See UDUNITS-2, for information on the UDUNITS-2 library, which is used by this program.


    Previous: See Also, Up: Top

    Index

    udunits-2.2.0/prog/CMakeLists.txt0000644000175000017500000000106512260406756020061 0ustar amckinstryamckinstryinclude_directories ("${PROJECT_SOURCE_DIR}/lib") link_directories(${PROJECT_BINARY_DIR}/lib) add_executable(udunits2 udunits2.c) target_link_libraries(udunits2 libudunits2) target_link_libraries(udunits2 ${EXPAT_LIBRARY}) target_link_libraries(udunits2 ${MATH_LIBRARY}) set_target_properties(udunits2 PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib" INSTALL_RPATH_USE_LINK_PATH "TRUE") # The documentation is in multiple texinfo(5) format files texi_doc(udunits2prog.texi ${CMAKE_SOURCE_DIR}/COPYRIGHT) install(TARGETS udunits2 DESTINATION bin) udunits-2.2.0/prog/udunits2prog.info0000644000175000017500000001723212260406756020646 0ustar amckinstryamckinstryThis is udunits2prog.info, produced by makeinfo version 4.13 from udunits2prog.texi. INFO-DIR-SECTION Science START-INFO-DIR-ENTRY * udunits2: (udunits2prog). The Unidata units-conversion program. END-INFO-DIR-ENTRY Copyright 2013 University Corporation for Atmospheric Research. All rights reserved. This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware. 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 CONTRIBUTORS 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 WITH THE SOFTWARE.  File: udunits2prog.info, Node: Top, Next: Synopsis, Prev: (dir), Up: (dir) udunits2 ******** This manual describes how to use the `udunits2' program. This program allows you to discover the definition of a unit as well as convert numeric values between compatible units. Copyright 2013 University Corporation for Atmospheric Research. All rights reserved. This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware. 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 CONTRIBUTORS 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 WITH THE SOFTWARE. * Menu: * Synopsis:: Terse usage example * Options:: Command-line options * Description:: Description of the program * See Also:: Additional information * Complete Index:: Complete index  File: udunits2prog.info, Node: Synopsis, Next: Options, Prev: Top, Up: Top 1 Synopsis ********** udunits2 -h udunits2 [-A|-L|-U] [-r] [-H have] [-W want] [XML_file]  File: udunits2prog.info, Node: Options, Next: Description, Prev: Synopsis, Up: Top 2 Options ********* The following options and arguments are supported: `-A' Use the ASCII character-set. `-L' Use the ISO Latin-1 (ISO-8859-1) character-set. `-U' Use the full Unicode character-set with UTF-8 encoding. `-h' Print a help message. `-r' Reveal any problems with the units database (by default, no error messages are printed during import of the database). `-H have' Use `have' unit for conversion. The default is the reply to the prompt. `-W want' Use `want' unit for conversion. An empty string requests the definition of the `have' unit. The default is the reply to the prompt. `XML_file' The pathname of the XML-formatted units database. If not specified, then the default, compile-time pathname is used.  File: udunits2prog.info, Node: Description, Next: See Also, Prev: Options, Up: Top 3 Description ************* When successfully started without the `-H have' or `-W want' options, the program will print the prompt You have: At this point you can exit the program by entering the end-of-file character (usually control-D) or continue by entering either a value or a unit. (a value comprises a numerical value and a unit. For example, You have: 80 km/h You want: At this point, if you enter a blank line, then the program will assume that you entered a unit in the previous line and will print the definition of that unit in terms of the base units of the unit-system that it imported on startup. For example, You have: 80 km/h You want: 22.2222222222222 m.s-1 You have: Details of the formatting depend on the character-set being used. *Note Options::. Alternatively, at the "`You want:'" prompt you can enter the unit in which you want the previously-entered value. For example, You have: 80 km/h You want: mi/h 80 km/h = 49.7097 mi/h x/(mi/h) = 0.621371*(x/(km/h)) You have: The first line after "`You want:'" shows the "have" value in the desired "want" unit. The second line shows the transformation between numerical values in the "have" unit to numerical values in the "want" unit. The symbol "`x'" represents the physical quantity in question. See `http://physics.nist.gov/Pubs/SP811/sec07.html'.  File: udunits2prog.info, Node: See Also, Next: Complete Index, Prev: Description, Up: Top 4 See Also ********** *Note UDUNITS-2: (udunits2lib)Top, for information on the UDUNITS-2 library, which is used by this program.  File: udunits2prog.info, Node: Complete Index, Prev: See Also, Up: Top Index ***** [index] * Menu: * options: Options. (line 6) * synopsis: Synopsis. (line 6)  Tag Table: Node: Top2153 Node: Synopsis4602 Node: Options4787 Node: Description5675 Node: See Also7194 Node: Complete Index7423  End Tag Table udunits-2.2.0/udunits2.html0000644000175000017500000005626512260406756017031 0ustar amckinstryamckinstry UDUNITS 2.2.0 Manual

    UDUNITS 2.2.0 Manual


    Next: , Previous: (dir), Up: (dir)

    UDUNITS-2

    This manual describes the UDUNITS-2 package, which contains a C library for units of physical quantities and a unit-definition and value-conversion utility.

    Copyright 2013 University Corporation for Atmospheric Research. All rights reserved.

    This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) <http://www.unidata.ucar.edu>.

    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware.

    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 CONTRIBUTORS 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 WITH THE SOFTWARE.


    Next: , Previous: Top, Up: Top

    1 Introduction

    The UDUNITS-2 package provides support for units of physical quantities. Its three main components are: 1) a C library for units of physical quantities; 2) a utility; for obtaining the definition of a unit and for converting numeric values between compatible units; and 3) an extensive database of units.


    Next: , Previous: Introduction, Up: Top

    2 How This Package Differs from the Original UDUNITS Package

    The UDUNIT-2 package differs from the UDUNITS-1 package in the following ways:

    • Support for non-ASCII characters: The UDUNITS-1 package only supports the ASCII character set. The UDUNITS-2 package supports the following character sets: ASCII, ISO 8859-1 (Latin-1), and the UTF-8 encoding of ISO 10646 (Unicode). This means that unit string specifications like "µ°F·Ω⁻¹" are now supported (your viewer must support UTF-8 to display this string correctly).
    • Support for logarithmic units: The unit string specification "0.1 lg(re 1 mW)" specifies a deciBel unit with a one milliwatt reference level. Such units are fully integrated into the package and all meaningful operations and conversions are supported.
    • Persistent value converters: It is now possible to obtain a converter data-object, which can be used to convert numeric values in one unit to numeric values in another, compatible unit. The values can be float, double, or one-dimensional arrays of floats or doubles.
    • Improved API: Due to the above changes, it was not possible to keep the application programming interface (API) of the UDUNITS-1 package. The new interface, however, is easily understood and easy to use. To support backward comptibility, the package does contain a version 1 C API, which uses the version 2 library.
    • XML unit database: The unit database is encoded using human-readable XML rather than a custom format. The XML parser included in the package supports an <import> element to allow easy and convenient customization.
    • No Fortran or Perl API: Interfaces for these languages have not yet been created. Contact support-udunits@unidata.ucar.edu if you are interested in helping to create these interfaces.

    One thing that has not changed is that almost all unit string specifications understood by the UDUNITS-1 package are also understood by the UDUNITS-2 package. One exception is the symbol g, which in version 1 of the package was associated with standard free fall (a unit of accelleration) but which is associated with the unit gram in version 2 of the package.


    Next: , Previous: Differences, Up: Top

    3 Installing this Package


    Next: , Up: Installation

    3.1 Installing from a Binary Distribution

    Currently, the only supported binary distribution is for 64-bit CentOS 6.4. If your computer is compatible with this (e.g., your computer is 64-bit CentOS, Fedora, or RedHat), then create the file /etc/yum.repos.d/unidata.repo with the following contents:

         [unidata]
         name=Unidata Repository
         baseurl=http://www.unidata.ucar.edu/yum-repo/CentOS/6/$basearch
         enabled=1
    

    You should then be able to install this package in the usual manner. For example,

         su -
         yum install udunits
    


    Previous: Binary, Up: Installation

    3.2 Installing from a Source Distribution


    Next: , Up: Source

    3.2.1 Prerequisites for This Package

    The Expat library and header-files must be installed. Look for the library "libexpat" and the header-file "expat.h".

    If this package is to be tested (which is optional), then the CUnit library and header-files must be installed. Look for the library "libcunit" and the header-files "CUnit/CUnit.h" and "CUnit/Basic.h".

    If this package is to be built on a Windows system, then the CMake and MinGW packages must be installed. Look for the utility "cmake" and the directory/folder "MinGW".


    Next: , Previous: Prerequisites, Up: Source

    3.2.2 Obtaining this Package

    Get the source for this package from its download-page at ftp://ftp.unidata.ucar.edu/pub/udunits/ and unpack it in an appropriate place. For example,

         su -
         cd /usr/local/src
         wget -O - ftp://ftp.unidata.ucar.edu/pub/udunits/udunits-2.2.0-Source.tar.gz |
         gunzip -c | pax -r
    


    Next: , Previous: Obtain, Up: Source

    3.2.3 Unix Installation Instructions


    Next: , Up: Unix
    3.2.3.1 Autoconf-based Installation

    Short instructions:

         ./configure [--prefix=root] [--disable-shared] [CC=path]
         make
         make check                      # optional; requires CUNIT installation
         make install                    # also installs INFO documentation
         make install-html install-pdf   # optional
         make clean
    

    By default, the installation root is /usr/local.

    Long instructions:

    1. Go to the top-level source-directory of this package, e.g.,
                cd udunits-2.2.0
      
    2. If necessary, clean-up from a previous installation attempt by making the distclean target using the make utility from step 2:
                make distclean
      

      The option --disable-shared causes the build process to create a static library only: a sharable library is not created. This option is necessary if the libtool utility that's included in this package can't build a sharable library using the given compiler.

    3. Execute the configure script. Specify the installation prefix, the compiler from the previous step, and any required option. For example, if you are on an HP-UX system and want to use the /bin/c89 compiler and install under /opt, then the following command is appropriate:
                ./configure --prefix=/opt --disable-shared CC=/bin/c89
      

      If the installation prefix is not specified, then the default is to install under /usr/local.

      If the compiler isn't specified, then the default is to use gcc.

    4. Build this package by making the default target using the make utility from step 2:
                make
      
    5. If you wish to verify that this package works correctly, then make the check target using the make utility from step 2:
                make check
      

      This step is only effective if the configure script found an installed CUNIT unit-testing package. If that package wasn't found, then the above command will quickly exit without testing this package.

    6. Install the library, utility, header-files, units-database, and INFO documentation files by making the install target using the make utility from step 2:
                make install
      
    7. If desired, install the HTML and PDF documentation files by making one or more of the following targets using the make utility from step 2:
                make install-html install-pdf
      
    8. Clean up by making the clean target using the make utility from step 2:
                make clean
      


    Previous: Autoconf, Up: Unix
    3.2.3.2 CMake-based Installation
         cmake
         make all [test] install [install_test]
    

    where the arguments in square brackets are optional.


    Previous: Unix, Up: Source

    3.2.4 Windows Installation Instructions

    Currently, only a 32-bit MinGW-based installation is supported:

         cmake -G "MinGW Makefiles"
         cmake --build . [-DUDUNITS_INSTALL_PREFIX=dir] -- all [test] install [install_test]
    

    where arguments in square brackets are optional.

    The default installation-prefix is "C:\Program Files (x86)\udunits-2.minor.bug", where minor and bug are the minor version and bug-fix level, respectively.


    Next: , Previous: Installation, Up: Top

    4 Unit Library

    See UDUNITS Library, for details on this package's unit library.


    Next: , Previous: Library, Up: Top

    5 Unit Utility

    See UDUNITS Utility, for details on this package's unit utility.


    Next: , Previous: Utility, Up: Top

    6 The Units Database

    The database for the UDUNITS-2 package comprises one XML file containing unit prefixes and four XML files containing unit definitions:


    Next: , Previous: Database, Up: Top

    7 Support for this Package

    The home-page for this package can be found at http://www.unidata.ucar.edu/software/udunits/.

    Bug reports should be sent to support-udunits@unidata.ucar.edu.


    Previous: Support, Up: Top

    Index

    udunits-2.2.0/COPYRIGHT0000644000175000017500000000361112260406756015644 0ustar amckinstryamckinstryCopyright 2013 University Corporation for Atmospheric Research. All rights reserved. This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware. 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 CONTRIBUTORS 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 WITH THE SOFTWARE. udunits-2.2.0/mdate-sh0000755000175000017500000001275112260406756016006 0ustar amckinstryamckinstry#!/bin/sh # Get modification time of a file or directory and pretty-print it. scriptversion=2009-04-28.21; # UTC # Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005, 2007, 2009 Free # Software Foundation, Inc. # written by Ulrich Drepper , June 1995 # # This program 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, or (at your option) # any later version. # # 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . case $1 in '') echo "$0: No file. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: mdate-sh [--help] [--version] FILE Pretty-print the modification time of FILE. Report bugs to . EOF exit $? ;; -v | --v*) echo "mdate-sh $scriptversion" exit $? ;; esac # Prevent date giving response in another language. LANG=C export LANG LC_ALL=C export LC_ALL LC_TIME=C export LC_TIME # GNU ls changes its time format in response to the TIME_STYLE # variable. Since we cannot assume `unset' works, revert this # variable to its documented default. if test "${TIME_STYLE+set}" = set; then TIME_STYLE=posix-long-iso export TIME_STYLE fi save_arg1=$1 # Find out how to get the extended ls output of a file or directory. if ls -L /dev/null 1>/dev/null 2>&1; then ls_command='ls -L -l -d' else ls_command='ls -l -d' fi # Avoid user/group names that might have spaces, when possible. if ls -n /dev/null 1>/dev/null 2>&1; then ls_command="$ls_command -n" fi # A `ls -l' line looks as follows on OS/2. # drwxrwx--- 0 Aug 11 2001 foo # This differs from Unix, which adds ownership information. # drwxrwx--- 2 root root 4096 Aug 11 2001 foo # # To find the date, we split the line on spaces and iterate on words # until we find a month. This cannot work with files whose owner is a # user named `Jan', or `Feb', etc. However, it's unlikely that `/' # will be owned by a user whose name is a month. So we first look at # the extended ls output of the root directory to decide how many # words should be skipped to get the date. # On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. set x`$ls_command /` # Find which argument is the month. month= command= until test $month do shift # Add another shift to the command. command="$command shift;" case $1 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac done # Get the extended ls output of the file or directory. set dummy x`eval "$ls_command \"\$save_arg1\""` # Remove all preceding arguments eval $command # Because of the dummy argument above, month is in $2. # # On a POSIX system, we should have # # $# = 5 # $1 = file size # $2 = month # $3 = day # $4 = year or time # $5 = filename # # On Darwin 7.7.0 and 7.6.0, we have # # $# = 4 # $1 = day # $2 = month # $3 = year or time # $4 = filename # Get the month. case $2 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac case $3 in ???*) day=$1;; *) day=$3; shift;; esac # Here we have to deal with the problem that the ls output gives either # the time of day or the year. case $3 in *:*) set `date`; eval year=\$$# case $2 in Jan) nummonthtod=1;; Feb) nummonthtod=2;; Mar) nummonthtod=3;; Apr) nummonthtod=4;; May) nummonthtod=5;; Jun) nummonthtod=6;; Jul) nummonthtod=7;; Aug) nummonthtod=8;; Sep) nummonthtod=9;; Oct) nummonthtod=10;; Nov) nummonthtod=11;; Dec) nummonthtod=12;; esac # For the first six month of the year the time notation can also # be used for files modified in the last year. if (expr $nummonth \> $nummonthtod) > /dev/null; then year=`expr $year - 1` fi;; *) year=$3;; esac # The result. echo $day $month $year # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: udunits-2.2.0/CMakeLists.txt0000644000175000017500000002146012260406756017113 0ustar amckinstryamckinstryPROJECT (udunits C) CMAKE_MINIMUM_REQUIRED(VERSION 2.8) SET(VERSION_MAJOR 2) SET(VERSION_MINOR 2) SET(VERSION_PATCH 0) # Ensure a path in the format common to both Unix and MinGW. FUNCTION(to_common_path input result) FILE(TO_NATIVE_PATH ${input} tmp) STRING(REGEX REPLACE "^(.):" "/\\1" tmp ${tmp}) SET(${result} ${tmp} PARENT_SCOPE) ENDFUNCTION(to_common_path) # Ensures a path in the native format. #FUNCTION(to_native_path input result) # FILE(TO_NATIVE_PATH ${input} tmp) # IF (WIN32 AND NOT UNIX) # STRING(REGEX REPLACE "/" "\\\\" tmp "${tmp}") # ENDIF() # SET(${result} "${tmp}" PARENT_SCOPE) #ENDFUNCTION(to_native_path) #FILE(TO_NATIVE_PATH "${CMAKE_INSTALL_PREFIX}/share/udunits/udunits2.xml" # DEFAULT_UDUNITS2_XML_PATH) FILE(TO_NATIVE_PATH "${CMAKE_INSTALL_PREFIX}/share/udunits/udunits2.xml" tmp) #MESSAGE("tmp = \"${tmp}\"") STRING(REGEX REPLACE "\\\\ " " " tmp "${tmp}") #MESSAGE("tmp = \"${tmp}\"") #STRING(REGEX REPLACE "\\\\" "\\\\\\\\" DEFAULT_UDUNITS2_XML_PATH "${tmp}") SET(DEFAULT_UDUNITS2_XML_PATH "${tmp}") MESSAGE("DEFAULT_UDUNITS2_XML_PATH = \"${DEFAULT_UDUNITS2_XML_PATH}\"") INCLUDE(CheckFunctionExists) INCLUDE(CTest) # The following fails on Gilda: #INCLUDE(GNUInstallDirs) # Hence: SET(CMAKE_INSTALL_INFODIR share/info) SET(CMAKE_INSTALL_DOCDIR share/doc/udunits) OPTION(BUILD_SHARED_LIBS "Whether or not to build a shared library" "ON") to_common_path(${CMAKE_SOURCE_DIR} common_source_dir) to_common_path(${CMAKE_INSTALL_INFODIR} common_install_infodir) # Determines if the top-level info(1)-file, "dir", should be modified. find_program(INSTALL_INFO install-info) IF (NOT INSTALL_INFO) MESSAGE("install-info(1) not found. Top-level info(1)-file will not be modified.") ELSE() EXECUTE_PROCESS(COMMAND ${INSTALL_INFO} --version OUTPUT_QUIET RESULT_VARIABLE status) IF(NOT status EQUAL "0") MESSAGE("install-info(1) failure. Top-level info(1)-file will not be modified.") SET(INSTALL_INFO "NO") ELSE() EXECUTE_PROCESS(COMMAND ${INSTALL_INFO} --version COMMAND head -1 COMMAND grep -q -i -v debian RESULT_VARIABLE status) IF(NOT status EQUAL "0") MESSAGE("Debian system. Top-level info(1)-file will not be modified.") SET(INSTALL_INFO "NO") ENDIF() ENDIF() ENDIF() # Declares documentation in texinfo(5) format. If "input" is relative, then it's # resolved using the current source-directory. A custom target is derived from # the filename and added to the default build target. The resulting # documentation files are added to the "install" target. find_program(MAKEINFO makeinfo) IF (NOT MAKEINFO) MESSAGE(WARNING "makeinfo(1) not found. Existing documentation will be used.") ENDIF() FUNCTION(texi_doc input) string(REGEX REPLACE ".*/" "" basename ${input}) string(REGEX REPLACE "\\..*" "" file ${basename}) to_common_path(${input} common_input) IF (NOT MAKEINFO) MESSAGE("Texinfo-file \"${common_input}\" will not be processed.") ELSE() add_custom_command( WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/${file}.info" "${CMAKE_CURRENT_SOURCE_DIR}/${file}.html" MAIN_DEPENDENCY ${input} DEPENDS ${ARGN} COMMAND ${MAKEINFO} -o ${file}.info -I ${common_source_dir} ${common_input} COMMAND ${MAKEINFO} -o ${file}.html -I ${common_source_dir} --html --no-split ${common_input} VERBATIM COMMENT "Creating documentation from ${common_input}") ENDIF() add_custom_target(${file}_doc ALL DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.info ${CMAKE_CURRENT_SOURCE_DIR}/${file}.html) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/${file}.info" DESTINATION ${CMAKE_INSTALL_INFODIR}) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/${file}.html" DESTINATION ${CMAKE_INSTALL_DOCDIR}) if(INSTALL_INFO) SET(outpath "${common_install_infodir}/${file}.info") add_custom_command( OUTPUT "${CMAKE_INSTALL_INFODIR}/dir" MAIN_DEPENDENCY "${outpath}" COMMAND ${INSTALL_INFO} --info-dir="${common_install_infodir}" "${outpath}" VERBATIM COMMENT "Adjusting top-level info(1)-file according to ${outpath}") endif() ENDFUNCTION(texi_doc) # This package uses math functions CHECK_FUNCTION_EXISTS(log10 HAVE_LOG10) IF (NOT HAVE_LOG10) FIND_LIBRARY(MATH_LIBRARY NAMES m math) IF(NOT MATH_LIBRARY) MESSAGE(FATAL_ERROR "Unable to find a C math library.") ENDIF() ENDIF() # The EXPAT library, which implements a SAX XML parser, is used to parse the # units database INCLUDE(FindEXPAT) IF(NOT EXPAT_FOUND) MESSAGE(FATAL_ERROR "Unable to find an EXPAT library.") IF(NOT EXPAT_INCLUDE_DIRS) MESSAGE(FATAL_ERROR "Unable to find an EXPAT header-file.") ENDIF() ENDIF() # The CUnit library is used for unit-testing FIND_LIBRARY(CUNIT_LIBRARY cunit) IF(CUNIT_LIBRARY) FIND_PATH(CUNIT_INCLUDE_DIR "CUnit/CUnit.h") IF (NOT CUNIT_INCLUDE_DIR) MESSAGE(STATUS "Unable to find CUnit header-file. Unit-testing not enabled.") ELSE() MESSAGE(STATUS "Found CUnit. Unit-testing enabled.") ENABLE_TESTING() ENDIF() ELSE() MESSAGE(STATUS "Unable to find CUnit library. Unit-testing not enabled.") ENDIF() CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/config.h.cmake" "${PROJECT_BINARY_DIR}/config.h") # Necessary for the compiler to find "config.h": INCLUDE_DIRECTORIES("${PROJECT_BINARY_DIR}") ADD_SUBDIRECTORY (lib) ADD_SUBDIRECTORY (prog) # The documentation is in texinfo(5) format texi_doc(udunits2.texi version.texi COPYRIGHT) # Install CHANGE_LOG and COPYRIGHT install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/CHANGE_LOG" DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/COPYRIGHT" DESTINATION ${CMAKE_INSTALL_DOCDIR}) # Test the installation SET(util "${CMAKE_INSTALL_PREFIX}/bin/udunits2") IF(WIN32) STRING(REGEX REPLACE "/" "\\\\" util "${util}") ENDIF() #MESSAGE("util = \"${util}\"") ADD_CUSTOM_TARGET(install_test "${util}" -A -H km -W m COMMENT "Checking installation...") # Create an installer INCLUDE(InstallRequiredSystemLibraries) # Apparently, CMAKE_SYSTEM_PROCESSOR can't be overridden via the "-D..." option. IF (WIN32) SET(CPACK_GENERATOR "NSIS") GET_FILENAME_COMPONENT(CPACK_NSIS_INSTALL_ROOT "${CMAKE_INSTALL_PREFIX}" PATH) GET_FILENAME_COMPONENT(CPACK_PACKAGE_INSTALL_DIRECTORY "${CMAKE_INSTALL_PREFIX}" NAME) STRING(REGEX REPLACE "/" "\\\\" CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_INSTALL_DIRECTORY}") SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} UDUNITS-2") SET(CPACK_NSIS_HELP_LINK "http://www.unidata.ucar.edu/software/udunits") SET(CPACK_NSIS_MODIFY_PATH ON) SET(CPACK_NSIS_URL_INFO_ABOUT "${CPACK_NSIS_HELP_LINK }") # # There is a bug in NSI that does not handle full unix paths properly. Make # # sure there is at least one set of four (4) backslashes. # SET(CPACK_PACKAGE_ICON "${CMake_SOURCE_DIR}/Utilities/Release\\\\InstallIcon.bmp") # SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\MyExecutable.exe") ENDIF() SET(CPACK_DEBIAN_PACKAGE_DEPENDS "expat, libexpat-dev") SET(CPACK_PACKAGE_CONTACT "support-udunits@unidata.ucar.edu") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Units of physical quantities C library and utility") SET(CPACK_PACKAGE_EXECUTABLES "udunits2;udunits2") SET(CPACK_PACKAGE_VENDOR "University Corporation for Atmospheric Research") SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH}) SET(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) SET(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYRIGHT") # The following line is necessary for installing to anything other than "/usr" SET(CPACK_SET_DESTDIR "ON") SET(CPACK_PACKAGE_RELOCATABLE "ON") SET(CPACK_SOURCE_GENERATOR "TGZ;ZIP") SET(CPACK_SOURCE_IGNORE_FILES "${CPACK_SOURCE_IGNORE_FILES};config\\\\.h$;/xmlFailures/;/xmlSuccesses/;/m4/;/\\\\.gradle/;\\\\.git;Makefile$") SET(CPACK_SOURCE_IGNORE_FILES "${CPACK_SOURCE_IGNORE_FILES};Makefile\\\\.in;\\\\.log$;config\\\\.status;\\\\.cproject;\\\\.project") SET(CPACK_SOURCE_IGNORE_FILES "${CPACK_SOURCE_IGNORE_FILES};/autom4te\\\\.cache/;/test/;/\\\\.deps/;/\\\\.vagrant/;~$;so_locations;\\\\.swp$") SET(CPACK_SOURCE_IGNORE_FILES "${CPACK_SOURCE_IGNORE_FILES};\\\\.metadata/;/CMakeFiles/;/build/") SET(CPACK_SOURCE_STRIP_FILES "") SET(CPACK_STRIP_FILES "bin/udunits2") INCLUDE(CPack) #include(UseRPMTools) # if(RPMTools_ADD_RPM_TARGETS("udunits")) #endif() udunits-2.2.0/udunits2.texi0000644000175000017500000002600412260406756017022 0ustar amckinstryamckinstry\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename udunits2.info @include version.texi @settitle UDUNITS @value{VERSION} Manual @c %**end of header @dircategory Science @direntry * udunits-2: (udunits2). The Unidata package for units of physical quantities. @end direntry @copying @include COPYRIGHT @end copying @titlepage @title The UDUNITS-2 Package @author Steven R. Emmerson @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top, Introduction, (dir), (dir) @top UDUNITS-2 This manual describes the UDUNITS-2 package, which contains a C library for units of physical quantities and a unit-definition and value-conversion utility. @insertcopying @end ifnottex @menu * Introduction:: Introduction * Differences:: How this package differs from the UDUNITS-1 package * Installation:: Installing this package * Library:: The unit library * Utility:: The unit utility * Database:: The unit database * Support:: Support for this package * Complete Index:: Complete index @end menu @node Introduction, Differences, Top, Top @chapter Introduction @cindex Introduction The UDUNITS-2 package provides support for units of physical quantities. Its three main components are: 1) @ref{Top, , a C library, udunits2lib} for units of physical quantities; 2) @ref{Top, , a utility, udunits2prog}; for obtaining the definition of a unit and for converting numeric values between compatible units; and 3) an @ref{Database, , extensive database of units}. @node Differences, Installation, Introduction, Top @chapter How This Package Differs from the Original @code{UDUNITS} Package The @code{UDUNIT-2} package differs from the @code{UDUNITS-1} package in the following ways: @itemize @bullet @item @strong{Support for non-ASCII characters:} The @code{UDUNITS-1} package only supports the ASCII character set. The @code{UDUNITS-2} package supports the following character sets: ASCII, ISO 8859-1 (Latin-1), and the UTF-8 encoding of ISO 10646 (Unicode). This means that unit string specifications like "@code{µ°F·Ω⁻¹}" are now supported (your viewer must support UTF-8 to display this string correctly). @item @strong{Support for logarithmic units:} The unit string specification "@code{0.1 lg(re 1 mW)}" specifies a deciBel unit with a one milliwatt reference level. Such units are fully integrated into the package and all meaningful operations and conversions are supported. @item @strong{Persistent value converters:} It is now possible to obtain a @emph{converter} data-object, which can be used to convert numeric values in one unit to numeric values in another, compatible unit. The values can be @code{float}, @code{double}, or one-dimensional arrays of @code{float}s or @code{double}s. @item @strong{Improved API:} Due to the above changes, it was not possible to keep the application programming interface (API) of the @code{UDUNITS-1} package. The new interface, however, is easily understood and easy to use. To support backward comptibility, the package does contain a version 1 C API, which uses the version 2 library. @item @strong{XML unit database:} The unit database is encoded using human-readable XML rather than a custom format. The XML parser included in the package supports an @emph{} element to allow easy and convenient customization. @item @strong{No Fortran or Perl API:} Interfaces for these languages have not yet been created. Contact @email{support-udunits@@unidata.ucar.edu} if you are interested in helping to create these interfaces. @end itemize One thing that has not changed is that almost all unit string specifications understood by the @code{UDUNITS-1} package are also understood by the @code{UDUNITS-2} package. One exception is the symbol @code{g}, which in version 1 of the package was associated with standard free fall (a unit of accelleration) but which is associated with the unit gram in version 2 of the package. @node Installation, Library, Differences, Top @chapter Installing this Package @cindex installation @menu * Binary:: Installing from a binary distribution * Source:: Installing from a source distribution @end menu @node Binary, Source, , Installation @section Installing from a Binary Distribution @cindex Installation, binary Currently, the only supported binary distribution is for 64-bit CentOS 6.4. If your computer is compatible with this (e.g., your computer is 64-bit CentOS, Fedora, or RedHat), then create the file @code{/etc/yum.repos.d/unidata.repo} with the following contents: @example [unidata] name=Unidata Repository baseurl=http://www.unidata.ucar.edu/yum-repo/CentOS/6/$basearch enabled=1 @end example You should then be able to install this package in the usual manner. For example, @example su - yum install udunits @end example @node Source, , Binary, Installation @section Installing from a Source Distribution @cindex Installation, source @menu * Prerequisites:: Prerequisites for this package * Obtain:: Obtaining this package * Unix:: Installing on Unix-like environments * Windows:: Installing on Windows environments @end menu @node Prerequisites, Obtain, , Source @subsection Prerequisites for This Package @cindex prerequisites for this package The Expat library and header-files must be installed. Look for the library "libexpat" and the header-file "expat.h". If this package is to be tested (which is optional), then the CUnit library and header-files must be installed. Look for the library "libcunit" and the header-files "CUnit/CUnit.h" and "CUnit/Basic.h". If this package is to be built on a Windows system, then the CMake and MinGW packages must be installed. Look for the utility "cmake" and the directory/folder "MinGW". @node Obtain, Unix, Prerequisites, Source @subsection Obtaining this Package @cindex obtaining this package Get the source for this package from its download-page at @uref{ftp://ftp.unidata.ucar.edu/pub/udunits/} and unpack it in an appropriate place. For example, @example su - cd /usr/local/src wget -O - ftp://ftp.unidata.ucar.edu/pub/udunits/udunits-@value{VERSION}-Source.tar.gz | gunzip -c | pax -r @end example @node Unix, Windows, Obtain, Source @subsection Unix Installation Instructions @menu * Autoconf:: Autoconf-based installation * CMake:: CMake-based installation @end menu @node Autoconf, CMake, , Unix @subsubsection Autoconf-based Installation Short instructions: @example ./configure [--prefix=@var{root}] [--disable-shared] [CC=@var{path}] make make check # optional; requires CUNIT installation make install # also installs INFO documentation make install-html install-pdf # optional make clean @end example By default, the installation root is @code{/usr/local}. Long instructions: @enumerate @item Go to the top-level source-directory of this package, e.g., @example cd udunits-@value{VERSION} @end example @item If necessary, clean-up from a previous installation attempt by making the @code{distclean} target using the @var{make} utility from step 2: @example @var{make} distclean @end example The option @code{--disable-shared} causes the build process to create a static library only: a sharable library is not created. This option is necessary if the @code{libtool} utility that's included in this package can't build a sharable library using the given compiler. @item Execute the @code{configure} script. Specify the installation prefix, the compiler from the previous step, and any required option. For example, if you are on an HP-UX system and want to use the @code{/bin/c89} compiler and install under @code{/opt}, then the following command is appropriate: @example ./configure --prefix=/opt --disable-shared CC=/bin/c89 @end example If the installation prefix is not specified, then the default is to install under @code{/usr/local}. If the compiler isn't specified, then the default is to use @code{gcc}. @item Build this package by making the default target using the @var{make} utility from step 2: @example @var{make} @end example @item If you wish to verify that this package works correctly, then make the @code{check} target using the @var{make} utility from step 2: @example @var{make} check @end example This step is only effective if the @code{configure} script found an installed @code{CUNIT} unit-testing package. If that package wasn't found, then the above command will quickly exit without testing this package. @item Install the @ref{Top, , library, udunits2lib}, @ref{Top, , utility, udunits2prog}, header-files, units-database, and INFO documentation files by making the @code{install} target using the @var{make} utility from step 2: @example @var{make} install @end example @item If desired, install the HTML and PDF documentation files by making one or more of the following targets using the @var{make} utility from step 2: @example @var{make} install-html install-pdf @end example @item Clean up by making the @code{clean} target using the @var{make} utility from step 2: @example @var{make} clean @end example @end enumerate @node CMake, , Autoconf, Unix @subsubsection CMake-based Installation @example cmake make all [test] install [install_test] @end example where the arguments in square brackets are optional. @node Windows, , Unix, Source @subsection Windows Installation Instructions Currently, only a 32-bit @uref{http://www.mingw.org,MinGW}-based installation is supported: @example cmake -G "MinGW Makefiles" cmake --build . [-DUDUNITS_INSTALL_PREFIX=@emph{dir}] -- all [test] install [install_test] @end example where arguments in square brackets are optional. The default installation-prefix is "@code{C:\Program Files (x86)\udunits-2.}@var{minor}.@var{bug}", where @var{minor} and @var{bug} are the minor version and bug-fix level, respectively. @node Library, Utility, Installation, Top @chapter Unit Library @cindex Library, unit @xref{UDUNITS Library, , , udunits2lib}, for details on this package's unit library. @node Utility, Database, Library, Top @chapter Unit Utility @cindex Utility, unit @xref{UDUNITS Utility, , , udunits2prog}, for details on this package's unit utility. @node Database, Support, Utility, Top @chapter The Units Database @cindex database The database for the UDUNITS-2 package comprises one XML file containing unit prefixes and four XML files containing unit definitions: @itemize @item @uref{../../udunits/udunits2-prefixes.xml,SI unit prefixes} @item @uref{../../udunits/udunits2-base.xml,SI base units} @item @uref{../../udunits/udunits2-derived.xml,SI derived units} @item @uref{../../udunits/udunits2-accepted.xml,Units accepted for use with the SI} @item @uref{../../udunits/udunits2-common.xml,Non-SI units} @end itemize @node Support, Complete Index, Database, Top @chapter Support for this Package @cindex support @cindex package, support The home-page for this package can be found at @uref{http://www.unidata.ucar.edu/software/udunits/}. Bug reports should be sent to @email{support-udunits@@unidata.ucar.edu}. @node Complete Index, , Support, Top @unnumbered Index @printindex cp @bye udunits-2.2.0/acceptance_test_win32.sh0000755000175000017500000000046412260406756021062 0ustar amckinstryamckinstryssh vagrant@192.168.56.101 'rm -rf udunits-2.1.26-Source' scp udunits-2.1.26-Source.zip vagrant@192.168.56.101: && ssh vagrant@192.168.56.101 '"/cygdrive/c/Program Files (x86)/7-Zip/7z"' \ x -y udunits-2.1.26-Source.zip && ssh vagrant@192.168.56.101 'cd udunits-2.1.26-Source && ./acceptance_test.cmd' udunits-2.2.0/ylwrap0000755000175000017500000001404312260406756015616 0ustar amckinstryamckinstry#! /bin/sh # ylwrap - wrapper for lex/yacc invocations. scriptversion=2009-04-28.21; # UTC # Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, # 2007, 2009 Free Software Foundation, Inc. # # Written by Tom Tromey . # # This program 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, or (at your option) # any later version. # # 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . case "$1" in '') echo "$0: No files given. Try \`$0 --help' for more information." 1>&2 exit 1 ;; --basedir) basedir=$2 shift 2 ;; -h|--h*) cat <<\EOF Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... Wrapper for lex/yacc invocations, renaming files as desired. INPUT is the input file OUTPUT is one file PROG generates DESIRED is the file we actually want instead of OUTPUT PROGRAM is program to run ARGS are passed to PROG Any number of OUTPUT,DESIRED pairs may be used. Report bugs to . EOF exit $? ;; -v|--v*) echo "ylwrap $scriptversion" exit $? ;; esac # The input. input="$1" shift case "$input" in [\\/]* | ?:[\\/]*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. input="`pwd`/$input" ;; esac pairlist= while test "$#" -ne 0; do if test "$1" = "--"; then shift break fi pairlist="$pairlist $1" shift done # The program to run. prog="$1" shift # Make any relative path in $prog absolute. case "$prog" in [\\/]* | ?:[\\/]*) ;; *[\\/]*) prog="`pwd`/$prog" ;; esac # FIXME: add hostname here for parallel makes that run commands on # other machines. But that might take us over the 14-char limit. dirname=ylwrap$$ trap "cd '`pwd`'; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15 mkdir $dirname || exit 1 cd $dirname case $# in 0) "$prog" "$input" ;; *) "$prog" "$@" "$input" ;; esac ret=$? if test $ret -eq 0; then set X $pairlist shift first=yes # Since DOS filename conventions don't allow two dots, # the DOS version of Bison writes out y_tab.c instead of y.tab.c # and y_tab.h instead of y.tab.h. Test to see if this is the case. y_tab_nodot="no" if test -f y_tab.c || test -f y_tab.h; then y_tab_nodot="yes" fi # The directory holding the input. input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'` # Quote $INPUT_DIR so we can use it in a regexp. # FIXME: really we should care about more than `.' and `\'. input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'` while test "$#" -ne 0; do from="$1" # Handle y_tab.c and y_tab.h output by DOS if test $y_tab_nodot = "yes"; then if test $from = "y.tab.c"; then from="y_tab.c" else if test $from = "y.tab.h"; then from="y_tab.h" fi fi fi if test -f "$from"; then # If $2 is an absolute path name, then just use that, # otherwise prepend `../'. case "$2" in [\\/]* | ?:[\\/]*) target="$2";; *) target="../$2";; esac # We do not want to overwrite a header file if it hasn't # changed. This avoid useless recompilations. However the # parser itself (the first file) should always be updated, # because it is the destination of the .y.c rule in the # Makefile. Divert the output of all other files to a temporary # file so we can compare them to existing versions. if test $first = no; then realtarget="$target" target="tmp-`echo $target | sed s/.*[\\/]//g`" fi # Edit out `#line' or `#' directives. # # We don't want the resulting debug information to point at # an absolute srcdir; it is better for it to just mention the # .y file with no path. # # We want to use the real output file name, not yy.lex.c for # instance. # # We want the include guards to be adjusted too. FROM=`echo "$from" | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` TARGET=`echo "$2" | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \ -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$? # Check whether header files must be updated. if test $first = no; then if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then echo "$2" is unchanged rm -f "$target" else echo updating "$2" mv -f "$target" "$realtarget" fi fi else # A missing file is only an error for the first file. This # is a blatant hack to let us support using "yacc -d". If -d # is not specified, we don't want an error when the header # file is "missing". if test $first = yes; then ret=1 fi fi shift shift first=no done else ret=$? fi # Remove the directory. cd .. rm -rf $dirname exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: udunits-2.2.0/texinfo.tex0000644000175000017500000110032012260406756016543 0ustar amckinstryamckinstry% texinfo.tex -- TeX macros to handle Texinfo files. % % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % \def\texinfoversion{2009-05-16.16} % % Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, % 2007, 2008, 2009 Free Software Foundation, Inc. % % This texinfo.tex file 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 3 of the % License, or (at your option) any later version. % % This texinfo.tex file 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 this program. If not, see . % % As a special exception, when this file is read by TeX when processing % a Texinfo source document, you may use the result without % restriction. (This has been our intent since Texinfo was invented.) % % Please try the latest version of texinfo.tex before submitting bug % reports; you can get the latest version from: % http://www.gnu.org/software/texinfo/ (the Texinfo home page), or % ftp://tug.org/tex/texinfo.tex % (and all CTAN mirrors, see http://www.ctan.org). % The texinfo.tex in any given distribution could well be out % of date, so if that's what you're using, please check. % % Send bug reports to bug-texinfo@gnu.org. Please include including a % complete document in each bug report with which we can reproduce the % problem. Patches are, of course, greatly appreciated. % % To process a Texinfo manual with TeX, it's most reliable to use the % texi2dvi shell script that comes with the distribution. For a simple % manual foo.texi, however, you can get away with this: % tex foo.texi % texindex foo.?? % tex foo.texi % tex foo.texi % dvips foo.dvi -o # or whatever; this makes foo.ps. % The extra TeX runs get the cross-reference information correct. % Sometimes one run after texindex suffices, and sometimes you need more % than two; texi2dvi does it as many times as necessary. % % It is possible to adapt texinfo.tex for other languages, to some % extent. You can get the existing language-specific files from the % full Texinfo distribution. % % The GNU Texinfo home page is http://www.gnu.org/software/texinfo. \message{Loading texinfo [version \texinfoversion]:} % If in a .fmt file, print the version number % and turn on active characters that we couldn't do earlier because % they might have appeared in the input file name. \everyjob{\message{[Texinfo version \texinfoversion]}% \catcode`+=\active \catcode`\_=\active} \chardef\other=12 % We never want plain's \outer definition of \+ in Texinfo. % For @tex, we can use \tabalign. \let\+ = \relax % Save some plain tex macros whose names we will redefine. \let\ptexb=\b \let\ptexbullet=\bullet \let\ptexc=\c \let\ptexcomma=\, \let\ptexdot=\. \let\ptexdots=\dots \let\ptexend=\end \let\ptexequiv=\equiv \let\ptexexclam=\! \let\ptexfootnote=\footnote \let\ptexgtr=> \let\ptexhat=^ \let\ptexi=\i \let\ptexindent=\indent \let\ptexinsert=\insert \let\ptexlbrace=\{ \let\ptexless=< \let\ptexnewwrite\newwrite \let\ptexnoindent=\noindent \let\ptexplus=+ \let\ptexrbrace=\} \let\ptexslash=\/ \let\ptexstar=\* \let\ptext=\t \let\ptextop=\top {\catcode`\'=\active \global\let\ptexquoteright'}% Math-mode def from plain.tex. \let\ptexraggedright=\raggedright % If this character appears in an error message or help string, it % starts a new line in the output. \newlinechar = `^^J % Use TeX 3.0's \inputlineno to get the line number, for better error % messages, but if we're using an old version of TeX, don't do anything. % \ifx\inputlineno\thisisundefined \let\linenumber = \empty % Pre-3.0. \else \def\linenumber{l.\the\inputlineno:\space} \fi % Set up fixed words for English if not already set. \ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi \ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi \ifx\putwordfile\undefined \gdef\putwordfile{file}\fi \ifx\putwordin\undefined \gdef\putwordin{in}\fi \ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi \ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi \ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi \ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi \ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi \ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi \ifx\putwordof\undefined \gdef\putwordof{of}\fi \ifx\putwordon\undefined \gdef\putwordon{on}\fi \ifx\putwordpage\undefined \gdef\putwordpage{page}\fi \ifx\putwordsection\undefined \gdef\putwordsection{section}\fi \ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi \ifx\putwordsee\undefined \gdef\putwordsee{see}\fi \ifx\putwordSee\undefined \gdef\putwordSee{See}\fi \ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi \ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi % \ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi \ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi \ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi \ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi \ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi \ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi \ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi \ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi \ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi \ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi \ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi \ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi % \ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi \ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi \ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi \ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi \ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi % Since the category of space is not known, we have to be careful. \chardef\spacecat = 10 \def\spaceisspace{\catcode`\ =\spacecat} % sometimes characters are active, so we need control sequences. \chardef\colonChar = `\: \chardef\commaChar = `\, \chardef\dashChar = `\- \chardef\dotChar = `\. \chardef\exclamChar= `\! \chardef\lquoteChar= `\` \chardef\questChar = `\? \chardef\rquoteChar= `\' \chardef\semiChar = `\; \chardef\underChar = `\_ % Ignore a token. % \def\gobble#1{} % The following is used inside several \edef's. \def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} % Hyphenation fixes. \hyphenation{ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script ap-pen-dix bit-map bit-maps data-base data-bases eshell fall-ing half-way long-est man-u-script man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces spell-ing spell-ings stand-alone strong-est time-stamp time-stamps which-ever white-space wide-spread wrap-around } % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset \newdimen\pagewidth \newdimen\pageheight % For a final copy, take out the rectangles % that mark overfull boxes (in case you have decided % that the text looks ok even though it passes the margin). % \def\finalout{\overfullrule=0pt} % @| inserts a changebar to the left of the current line. It should % surround any changed text. This approach does *not* work if the % change spans more than two lines of output. To handle that, we would % have adopt a much more difficult approach (putting marks into the main % vertical list for the beginning and end of each change). % \def\|{% % \vadjust can only be used in horizontal mode. \leavevmode % % Append this vertical mode material after the current line in the output. \vadjust{% % We want to insert a rule with the height and depth of the current % leading; that is exactly what \strutbox is supposed to record. \vskip-\baselineskip % % \vadjust-items are inserted at the left edge of the type. So % the \llap here moves out into the left-hand margin. \llap{% % % For a thicker or thinner bar, change the `1pt'. \vrule height\baselineskip width1pt % % This is the space between the bar and the text. \hskip 12pt }% }% } % Sometimes it is convenient to have everything in the transcript file % and nothing on the terminal. We don't just call \tracingall here, % since that produces some useless output on the terminal. We also make % some effort to order the tracing commands to reduce output in the log % file; cf. trace.sty in LaTeX. % \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% \def\loggingall{% \tracingstats2 \tracingpages1 \tracinglostchars2 % 2 gives us more in etex \tracingparagraphs1 \tracingoutput1 \tracingmacros2 \tracingrestores1 \showboxbreadth\maxdimen \showboxdepth\maxdimen \ifx\eTeXversion\undefined\else % etex gives us more logging \tracingscantokens1 \tracingifs1 \tracinggroups1 \tracingnesting2 \tracingassigns1 \fi \tracingcommands3 % 3 gives us more in etex \errorcontextlines16 }% % add check for \lastpenalty to plain's definitions. If the last thing % we did was a \nobreak, we don't want to insert more space. % \def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount \removelastskip\penalty-50\smallskip\fi\fi} \def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount \removelastskip\penalty-100\medskip\fi\fi} \def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount \removelastskip\penalty-200\bigskip\fi\fi} % For @cropmarks command. % Do @cropmarks to get crop marks. % \newif\ifcropmarks \let\cropmarks = \cropmarkstrue % % Dimensions to add cropmarks at corners. % Added by P. A. MacKay, 12 Nov. 1986 % \newdimen\outerhsize \newdimen\outervsize % set by the paper size routines \newdimen\cornerlong \cornerlong=1pc \newdimen\cornerthick \cornerthick=.3pt \newdimen\topandbottommargin \topandbottommargin=.75in % Output a mark which sets \thischapter, \thissection and \thiscolor. % We dump everything together because we only have one kind of mark. % This works because we only use \botmark / \topmark, not \firstmark. % % A mark contains a subexpression of the \ifcase ... \fi construct. % \get*marks macros below extract the needed part using \ifcase. % % Another complication is to let the user choose whether \thischapter % (\thissection) refers to the chapter (section) in effect at the top % of a page, or that at the bottom of a page. The solution is % described on page 260 of The TeXbook. It involves outputting two % marks for the sectioning macros, one before the section break, and % one after. I won't pretend I can describe this better than DEK... \def\domark{% \toks0=\expandafter{\lastchapterdefs}% \toks2=\expandafter{\lastsectiondefs}% \toks4=\expandafter{\prevchapterdefs}% \toks6=\expandafter{\prevsectiondefs}% \toks8=\expandafter{\lastcolordefs}% \mark{% \the\toks0 \the\toks2 \noexpand\or \the\toks4 \the\toks6 \noexpand\else \the\toks8 }% } % \topmark doesn't work for the very first chapter (after the title % page or the contents), so we use \firstmark there -- this gets us % the mark with the chapter defs, unless the user sneaks in, e.g., % @setcolor (or @url, or @link, etc.) between @contents and the very % first @chapter. \def\gettopheadingmarks{% \ifcase0\topmark\fi \ifx\thischapter\empty \ifcase0\firstmark\fi \fi } \def\getbottomheadingmarks{\ifcase1\botmark\fi} \def\getcolormarks{\ifcase2\topmark\fi} % Avoid "undefined control sequence" errors. \def\lastchapterdefs{} \def\lastsectiondefs{} \def\prevchapterdefs{} \def\prevsectiondefs{} \def\lastcolordefs{} % Main output routine. \chardef\PAGE = 255 \output = {\onepageout{\pagecontents\PAGE}} \newbox\headlinebox \newbox\footlinebox % \onepageout takes a vbox as an argument. Note that \pagecontents % does insertions, but you have to call it yourself. \def\onepageout#1{% \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi % \ifodd\pageno \advance\hoffset by \bindingoffset \else \advance\hoffset by -\bindingoffset\fi % % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% % {% % Have to do this stuff outside the \shipout because we want it to % take effect in \write's, yet the group defined by the \vbox ends % before the \shipout runs. % \indexdummies % don't expand commands in the output. \normalturnoffactive % \ in index entries must not stay \, e.g., if % the page break happens to be in the middle of an example. % We don't want .vr (or whatever) entries like this: % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}} % "\acronym" won't work when it's read back in; % it needs to be % {\code {{\tt \backslashcurfont }acronym} \shipout\vbox{% % Do this early so pdf references go to the beginning of the page. \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi % \ifcropmarks \vbox to \outervsize\bgroup \hsize = \outerhsize \vskip-\topandbottommargin \vtop to0pt{% \line{\ewtop\hfil\ewtop}% \nointerlineskip \line{% \vbox{\moveleft\cornerthick\nstop}% \hfill \vbox{\moveright\cornerthick\nstop}% }% \vss}% \vskip\topandbottommargin \line\bgroup \hfil % center the page within the outer (page) hsize. \ifodd\pageno\hskip\bindingoffset\fi \vbox\bgroup \fi % \unvbox\headlinebox \pagebody{#1}% \ifdim\ht\footlinebox > 0pt % Only leave this space if the footline is nonempty. % (We lessened \vsize for it in \oddfootingyyy.) % The \baselineskip=24pt in plain's \makefootline has no effect. \vskip 24pt \unvbox\footlinebox \fi % \ifcropmarks \egroup % end of \vbox\bgroup \hfil\egroup % end of (centering) \line\bgroup \vskip\topandbottommargin plus1fill minus1fill \boxmaxdepth = \cornerthick \vbox to0pt{\vss \line{% \vbox{\moveleft\cornerthick\nsbot}% \hfill \vbox{\moveright\cornerthick\nsbot}% }% \nointerlineskip \line{\ewbot\hfil\ewbot}% }% \egroup % \vbox from first cropmarks clause \fi }% end of \shipout\vbox }% end of group with \indexdummies \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi } \newinsert\margin \dimen\margin=\maxdimen \def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi % marginal hacks, juha@viisa.uucp (Juha Takala) \ifvoid\margin\else % marginal info is present \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi \dimen@=\dp#1\relax \unvbox#1\relax \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi \ifr@ggedbottom \kern-\dimen@ \vfil \fi} } % Here are the rules for the cropmarks. Note that they are % offset so that the space between them is truly \outerhsize or \outervsize % (P. A. MacKay, 12 November, 1986) % \def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} \def\nstop{\vbox {\hrule height\cornerthick depth\cornerlong width\cornerthick}} \def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} \def\nsbot{\vbox {\hrule height\cornerlong depth\cornerthick width\cornerthick}} % Parse an argument, then pass it to #1. The argument is the rest of % the input line (except we remove a trailing comment). #1 should be a % macro which expects an ordinary undelimited TeX argument. % \def\parsearg{\parseargusing{}} \def\parseargusing#1#2{% \def\argtorun{#2}% \begingroup \obeylines \spaceisspace #1% \parseargline\empty% Insert the \empty token, see \finishparsearg below. } {\obeylines % \gdef\parseargline#1^^M{% \endgroup % End of the group started in \parsearg. \argremovecomment #1\comment\ArgTerm% }% } % First remove any @comment, then any @c comment. \def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} \def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} % Each occurrence of `\^^M' or `\^^M' is replaced by a single space. % % \argremovec might leave us with trailing space, e.g., % @end itemize @c foo % This space token undergoes the same procedure and is eventually removed % by \finishparsearg. % \def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} \def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} \def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% \def\temp{#3}% \ifx\temp\empty % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: \let\temp\finishparsearg \else \let\temp\argcheckspaces \fi % Put the space token in: \temp#1 #3\ArgTerm } % If a _delimited_ argument is enclosed in braces, they get stripped; so % to get _exactly_ the rest of the line, we had to prevent such situation. % We prepended an \empty token at the very beginning and we expand it now, % just before passing the control to \argtorun. % (Similarly, we have to think about #3 of \argcheckspacesY above: it is % either the null string, or it ends with \^^M---thus there is no danger % that a pair of braces would be stripped. % % But first, we have to remove the trailing space token. % \def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} % \parseargdef\foo{...} % is roughly equivalent to % \def\foo{\parsearg\Xfoo} % \def\Xfoo#1{...} % % Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my % favourite TeX trick. --kasal, 16nov03 \def\parseargdef#1{% \expandafter \doparseargdef \csname\string#1\endcsname #1% } \def\doparseargdef#1#2{% \def#2{\parsearg#1}% \def#1##1% } % Several utility definitions with active space: { \obeyspaces \gdef\obeyedspace{ } % Make each space character in the input produce a normal interword % space in the output. Don't allow a line break at this space, as this % is used only in environments like @example, where each line of input % should produce a line of output anyway. % \gdef\sepspaces{\obeyspaces\let =\tie} % If an index command is used in an @example environment, any spaces % therein should become regular spaces in the raw index file, not the % expansion of \tie (\leavevmode \penalty \@M \ ). \gdef\unsepspaces{\let =\space} } \def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} % Define the framework for environments in texinfo.tex. It's used like this: % % \envdef\foo{...} % \def\Efoo{...} % % It's the responsibility of \envdef to insert \begingroup before the % actual body; @end closes the group after calling \Efoo. \envdef also % defines \thisenv, so the current environment is known; @end checks % whether the environment name matches. The \checkenv macro can also be % used to check whether the current environment is the one expected. % % Non-false conditionals (@iftex, @ifset) don't fit into this, so they % are not treated as environments; they don't open a group. (The % implementation of @end takes care not to call \endgroup in this % special case.) % At run-time, environments start with this: \def\startenvironment#1{\begingroup\def\thisenv{#1}} % initialize \let\thisenv\empty % ... but they get defined via ``\envdef\foo{...}'': \long\def\envdef#1#2{\def#1{\startenvironment#1#2}} \def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} % Check whether we're in the right environment: \def\checkenv#1{% \def\temp{#1}% \ifx\thisenv\temp \else \badenverr \fi } % Environment mismatch, #1 expected: \def\badenverr{% \errhelp = \EMsimple \errmessage{This command can appear only \inenvironment\temp, not \inenvironment\thisenv}% } \def\inenvironment#1{% \ifx#1\empty out of any environment% \else in environment \expandafter\string#1% \fi } % @end foo executes the definition of \Efoo. % But first, it executes a specialized version of \checkenv % \parseargdef\end{% \if 1\csname iscond.#1\endcsname \else % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03 \expandafter\checkenv\csname#1\endcsname \csname E#1\endcsname \endgroup \fi } \newhelp\EMsimple{Press RETURN to continue.} %% Simple single-character @ commands % @@ prints an @ % Kludge this until the fonts are right (grr). \def\@{{\tt\char64}} % This is turned off because it was never documented % and you can use @w{...} around a quote to suppress ligatures. %% Define @` and @' to be the same as ` and ' %% but suppressing ligatures. %\def\`{{`}} %\def\'{{'}} % Used to generate quoted braces. \def\mylbrace {{\tt\char123}} \def\myrbrace {{\tt\char125}} \let\{=\mylbrace \let\}=\myrbrace \begingroup % Definitions to produce \{ and \} commands for indices, % and @{ and @} for the aux/toc files. \catcode`\{ = \other \catcode`\} = \other \catcode`\[ = 1 \catcode`\] = 2 \catcode`\! = 0 \catcode`\\ = \other !gdef!lbracecmd[\{]% !gdef!rbracecmd[\}]% !gdef!lbraceatcmd[@{]% !gdef!rbraceatcmd[@}]% !endgroup % @comma{} to avoid , parsing problems. \let\comma = , % Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent % Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. \let\, = \c \let\dotaccent = \. \def\ringaccent#1{{\accent23 #1}} \let\tieaccent = \t \let\ubaraccent = \b \let\udotaccent = \d % Other special characters: @questiondown @exclamdown @ordf @ordm % Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. \def\questiondown{?`} \def\exclamdown{!`} \def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} \def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} % Dotless i and dotless j, used for accents. \def\imacro{i} \def\jmacro{j} \def\dotless#1{% \def\temp{#1}% \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi \else \errmessage{@dotless can be used only with i or j}% \fi\fi } % The \TeX{} logo, as in plain, but resetting the spacing so that a % period following counts as ending a sentence. (Idea found in latex.) % \edef\TeX{\TeX \spacefactor=1000 } % @LaTeX{} logo. Not quite the same results as the definition in % latex.ltx, since we use a different font for the raised A; it's most % convenient for us to use an explicitly smaller font, rather than using % the \scriptstyle font (since we don't reset \scriptstyle and % \scriptscriptstyle). % \def\LaTeX{% L\kern-.36em {\setbox0=\hbox{T}% \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}% \kern-.15em \TeX } % Be sure we're in horizontal mode when doing a tie, since we make space % equivalent to this in @example-like environments. Otherwise, a space % at the beginning of a line will start with \penalty -- and % since \penalty is valid in vertical mode, we'd end up putting the % penalty on the vertical list instead of in the new paragraph. {\catcode`@ = 11 % Avoid using \@M directly, because that causes trouble % if the definition is written into an index file. \global\let\tiepenalty = \@M \gdef\tie{\leavevmode\penalty\tiepenalty\ } } % @: forces normal size whitespace following. \def\:{\spacefactor=1000 } % @* forces a line break. \def\*{\hfil\break\hbox{}\ignorespaces} % @/ allows a line break. \let\/=\allowbreak % @. is an end-of-sentence period. \def\.{.\spacefactor=\endofsentencespacefactor\space} % @! is an end-of-sentence bang. \def\!{!\spacefactor=\endofsentencespacefactor\space} % @? is an end-of-sentence query. \def\?{?\spacefactor=\endofsentencespacefactor\space} % @frenchspacing on|off says whether to put extra space after punctuation. % \def\onword{on} \def\offword{off} % \parseargdef\frenchspacing{% \def\temp{#1}% \ifx\temp\onword \plainfrenchspacing \else\ifx\temp\offword \plainnonfrenchspacing \else \errhelp = \EMsimple \errmessage{Unknown @frenchspacing option `\temp', must be on/off}% \fi\fi } % @w prevents a word break. Without the \leavevmode, @w at the % beginning of a paragraph, when TeX is still in vertical mode, would % produce a whole line of output instead of starting the paragraph. \def\w#1{\leavevmode\hbox{#1}} % @group ... @end group forces ... to be all on one page, by enclosing % it in a TeX vbox. We use \vtop instead of \vbox to construct the box % to keep its height that of a normal line. According to the rules for % \topskip (p.114 of the TeXbook), the glue inserted is % max (\topskip - \ht (first item), 0). If that height is large, % therefore, no glue is inserted, and the space between the headline and % the text is small, which looks bad. % % Another complication is that the group might be very large. This can % cause the glue on the previous page to be unduly stretched, because it % does not have much material. In this case, it's better to add an % explicit \vfill so that the extra space is at the bottom. The % threshold for doing this is if the group is more than \vfilllimit % percent of a page (\vfilllimit can be changed inside of @tex). % \newbox\groupbox \def\vfilllimit{0.7} % \envdef\group{% \ifnum\catcode`\^^M=\active \else \errhelp = \groupinvalidhelp \errmessage{@group invalid in context where filling is enabled}% \fi \startsavinginserts % \setbox\groupbox = \vtop\bgroup % Do @comment since we are called inside an environment such as % @example, where each end-of-line in the input causes an % end-of-line in the output. We don't want the end-of-line after % the `@group' to put extra space in the output. Since @group % should appear on a line by itself (according to the Texinfo % manual), we don't worry about eating any user text. \comment } % % The \vtop produces a box with normal height and large depth; thus, TeX puts % \baselineskip glue before it, and (when the next line of text is done) % \lineskip glue after it. Thus, space below is not quite equal to space % above. But it's pretty close. \def\Egroup{% % To get correct interline space between the last line of the group % and the first line afterwards, we have to propagate \prevdepth. \endgraf % Not \par, as it may have been set to \lisppar. \global\dimen1 = \prevdepth \egroup % End the \vtop. % \dimen0 is the vertical size of the group's box. \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox % \dimen2 is how much space is left on the page (more or less). \dimen2 = \pageheight \advance\dimen2 by -\pagetotal % if the group doesn't fit on the current page, and it's a big big % group, force a page break. \ifdim \dimen0 > \dimen2 \ifdim \pagetotal < \vfilllimit\pageheight \page \fi \fi \box\groupbox \prevdepth = \dimen1 \checkinserts } % % TeX puts in an \escapechar (i.e., `@') at the beginning of the help % message, so this ends up printing `@group can only ...'. % \newhelp\groupinvalidhelp{% group can only be used in environments such as @example,^^J% where each line of input produces a line of output.} % @need space-in-mils % forces a page break if there is not space-in-mils remaining. \newdimen\mil \mil=0.001in % Old definition--didn't work. %\parseargdef\need{\par % %% This method tries to make TeX break the page naturally %% if the depth of the box does not fit. %{\baselineskip=0pt% %\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak %\prevdepth=-1000pt %}} \parseargdef\need{% % Ensure vertical mode, so we don't make a big box in the middle of a % paragraph. \par % % If the @need value is less than one line space, it's useless. \dimen0 = #1\mil \dimen2 = \ht\strutbox \advance\dimen2 by \dp\strutbox \ifdim\dimen0 > \dimen2 % % Do a \strut just to make the height of this box be normal, so the % normal leading is inserted relative to the preceding line. % And a page break here is fine. \vtop to #1\mil{\strut\vfil}% % % TeX does not even consider page breaks if a penalty added to the % main vertical list is 10000 or more. But in order to see if the % empty box we just added fits on the page, we must make it consider % page breaks. On the other hand, we don't want to actually break the % page after the empty box. So we use a penalty of 9999. % % There is an extremely small chance that TeX will actually break the % page at this \penalty, if there are no other feasible breakpoints in % sight. (If the user is using lots of big @group commands, which % almost-but-not-quite fill up a page, TeX will have a hard time doing % good page breaking, for example.) However, I could not construct an % example where a page broke at this \penalty; if it happens in a real % document, then we can reconsider our strategy. \penalty9999 % % Back up by the size of the box, whether we did a page break or not. \kern -#1\mil % % Do not allow a page break right after this kern. \nobreak \fi } % @br forces paragraph break (and is undocumented). \let\br = \par % @page forces the start of a new page. % \def\page{\par\vfill\supereject} % @exdent text.... % outputs text on separate line in roman font, starting at standard page margin % This records the amount of indent in the innermost environment. % That's how much \exdent should take out. \newskip\exdentamount % This defn is used inside fill environments such as @defun. \parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} % This defn is used inside nofill environments such as @example. \parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount \leftline{\hskip\leftskip{\rm#1}}}} % @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current % paragraph. For more general purposes, use the \margin insertion % class. WHICH is `l' or `r'. % \newskip\inmarginspacing \inmarginspacing=1cm \def\strutdepth{\dp\strutbox} % \def\doinmargin#1#2{\strut\vadjust{% \nobreak \kern-\strutdepth \vtop to \strutdepth{% \baselineskip=\strutdepth \vss % if you have multiple lines of stuff to put here, you'll need to % make the vbox yourself of the appropriate size. \ifx#1l% \llap{\ignorespaces #2\hskip\inmarginspacing}% \else \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% \fi \null }% }} \def\inleftmargin{\doinmargin l} \def\inrightmargin{\doinmargin r} % % @inmargin{TEXT [, RIGHT-TEXT]} % (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; % else use TEXT for both). % \def\inmargin#1{\parseinmargin #1,,\finish} \def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \def\lefttext{#1}% have both texts \def\righttext{#2}% \else \def\lefttext{#1}% have only one text \def\righttext{#1}% \fi % \ifodd\pageno \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin \else \def\temp{\inleftmargin\lefttext}% \fi \temp } % @include FILE -- \input text of FILE. % \def\include{\parseargusing\filenamecatcodes\includezzz} \def\includezzz#1{% \pushthisfilestack \def\thisfile{#1}% {% \makevalueexpandable % we want to expand any @value in FILE. \turnoffactive % and allow special characters in the expansion \indexnofonts % Allow `@@' and other weird things in file names. \edef\temp{\noexpand\input #1 }% % % This trickery is to read FILE outside of a group, in case it makes % definitions, etc. \expandafter }\temp \popthisfilestack } \def\filenamecatcodes{% \catcode`\\=\other \catcode`~=\other \catcode`^=\other \catcode`_=\other \catcode`|=\other \catcode`<=\other \catcode`>=\other \catcode`+=\other \catcode`-=\other \catcode`\`=\other \catcode`\'=\other } \def\pushthisfilestack{% \expandafter\pushthisfilestackX\popthisfilestack\StackTerm } \def\pushthisfilestackX{% \expandafter\pushthisfilestackY\thisfile\StackTerm } \def\pushthisfilestackY #1\StackTerm #2\StackTerm {% \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% } \def\popthisfilestack{\errthisfilestackempty} \def\errthisfilestackempty{\errmessage{Internal error: the stack of filenames is empty.}} \def\thisfile{} % @center line % outputs that line, centered. % \parseargdef\center{% \ifhmode \let\next\centerH \else \let\next\centerV \fi \next{\hfil \ignorespaces#1\unskip \hfil}% } \def\centerH#1{% {% \hfil\break \advance\hsize by -\leftskip \advance\hsize by -\rightskip \line{#1}% \break }% } \def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}} % @sp n outputs n lines of vertical space \parseargdef\sp{\vskip #1\baselineskip} % @comment ...line which is ignored... % @c is the same as @comment % @ignore ... @end ignore is another way to write a comment \def\comment{\begingroup \catcode`\^^M=\other% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \commentxxx} {\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} \let\c=\comment % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. % NCHARS can also be the word `asis' or `none'. % We cannot feasibly implement @paragraphindent asis, though. % \def\asisword{asis} % no translation, these are keywords \def\noneword{none} % \parseargdef\paragraphindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \defaultparindent = 0pt \else \defaultparindent = #1em \fi \fi \parindent = \defaultparindent } % @exampleindent NCHARS % We'll use ems for NCHARS like @paragraphindent. % It seems @exampleindent asis isn't necessary, but % I preserve it to make it similar to @paragraphindent. \parseargdef\exampleindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \lispnarrowing = 0pt \else \lispnarrowing = #1em \fi \fi } % @firstparagraphindent WORD % If WORD is `none', then suppress indentation of the first paragraph % after a section heading. If WORD is `insert', then do indent at such % paragraphs. % % The paragraph indentation is suppressed or not by calling % \suppressfirstparagraphindent, which the sectioning commands do. % We switch the definition of this back and forth according to WORD. % By default, we suppress indentation. % \def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} \def\insertword{insert} % \parseargdef\firstparagraphindent{% \def\temp{#1}% \ifx\temp\noneword \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent \else\ifx\temp\insertword \let\suppressfirstparagraphindent = \relax \else \errhelp = \EMsimple \errmessage{Unknown @firstparagraphindent option `\temp'}% \fi\fi } % Here is how we actually suppress indentation. Redefine \everypar to % \kern backwards by \parindent, and then reset itself to empty. % % We also make \indent itself not actually do anything until the next % paragraph. % \gdef\dosuppressfirstparagraphindent{% \gdef\indent{% \restorefirstparagraphindent \indent }% \gdef\noindent{% \restorefirstparagraphindent \noindent }% \global\everypar = {% \kern -\parindent \restorefirstparagraphindent }% } \gdef\restorefirstparagraphindent{% \global \let \indent = \ptexindent \global \let \noindent = \ptexnoindent \global \everypar = {}% } % @asis just yields its argument. Used with @table, for example. % \def\asis#1{#1} % @math outputs its argument in math mode. % % One complication: _ usually means subscripts, but it could also mean % an actual _ character, as in @math{@var{some_variable} + 1}. So make % _ active, and distinguish by seeing if the current family is \slfam, % which is what @var uses. { \catcode`\_ = \active \gdef\mathunderscore{% \catcode`\_=\active \def_{\ifnum\fam=\slfam \_\else\sb\fi}% } } % Another complication: we want \\ (and @\) to output a \ character. % FYI, plain.tex uses \\ as a temporary control sequence (why?), but % this is not advertised and we don't care. Texinfo does not % otherwise define @\. % % The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. \def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} % \def\math{% \tex \mathunderscore \let\\ = \mathbackslash \mathactive % make the texinfo accent commands work in math mode \let\"=\ddot \let\'=\acute \let\==\bar \let\^=\hat \let\`=\grave \let\u=\breve \let\v=\check \let\~=\tilde \let\dotaccent=\dot $\finishmath } \def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. % Some active characters (such as <) are spaced differently in math. % We have to reset their definitions in case the @math was an argument % to a command which sets the catcodes (such as @item or @section). % { \catcode`^ = \active \catcode`< = \active \catcode`> = \active \catcode`+ = \active \catcode`' = \active \gdef\mathactive{% \let^ = \ptexhat \let< = \ptexless \let> = \ptexgtr \let+ = \ptexplus \let' = \ptexquoteright } } % Some math mode symbols. \def\bullet{$\ptexbullet$} \def\geq{\ifmmode \ge\else $\ge$\fi} \def\leq{\ifmmode \le\else $\le$\fi} \def\minus{\ifmmode -\else $-$\fi} % @dots{} outputs an ellipsis using the current font. % We do .5em per period so that it has the same spacing in the cm % typewriter fonts as three actual period characters; on the other hand, % in other typewriter fonts three periods are wider than 1.5em. So do % whichever is larger. % \def\dots{% \leavevmode \setbox0=\hbox{...}% get width of three periods \ifdim\wd0 > 1.5em \dimen0 = \wd0 \else \dimen0 = 1.5em \fi \hbox to \dimen0{% \hskip 0pt plus.25fil .\hskip 0pt plus1fil .\hskip 0pt plus1fil .\hskip 0pt plus.5fil }% } % @enddots{} is an end-of-sentence ellipsis. % \def\enddots{% \dots \spacefactor=\endofsentencespacefactor } % @comma{} is so commas can be inserted into text without messing up % Texinfo's parsing. % \let\comma = , % @refill is a no-op. \let\refill=\relax % If working on a large document in chapters, it is convenient to % be able to disable indexing, cross-referencing, and contents, for test runs. % This is done with @novalidate (before @setfilename). % \newif\iflinks \linkstrue % by default we want the aux files. \let\novalidate = \linksfalse % @setfilename is done at the beginning of every texinfo file. % So open here the files we need to have open while reading the input. % This makes it possible to make a .fmt file for texinfo. \def\setfilename{% \fixbackslash % Turn off hack to swallow `\input texinfo'. \iflinks \tryauxfile % Open the new aux file. TeX will close it automatically at exit. \immediate\openout\auxfile=\jobname.aux \fi % \openindices needs to do some work in any case. \openindices \let\setfilename=\comment % Ignore extra @setfilename cmds. % % If texinfo.cnf is present on the system, read it. % Useful for site-wide @afourpaper, etc. \openin 1 texinfo.cnf \ifeof 1 \else \input texinfo.cnf \fi \closein 1 % \comment % Ignore the actual filename. } % Called from \setfilename. % \def\openindices{% \newindex{cp}% \newcodeindex{fn}% \newcodeindex{vr}% \newcodeindex{tp}% \newcodeindex{ky}% \newcodeindex{pg}% } % @bye. \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \message{pdf,} % adobe `portable' document format \newcount\tempnum \newcount\lnkcount \newtoks\filename \newcount\filenamelength \newcount\pgn \newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD \newbox\boxA \newcount\countA \newif\ifpdf \newif\ifpdfmakepagedest % when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 % can be set). So we test for \relax and 0 as well as \undefined, % borrowed from ifpdf.sty. \ifx\pdfoutput\undefined \else \ifx\pdfoutput\relax \else \ifcase\pdfoutput \else \pdftrue \fi \fi \fi % PDF uses PostScript string constants for the names of xref targets, % for display in the outlines, and in other places. Thus, we have to % double any backslashes. Otherwise, a name like "\node" will be % interpreted as a newline (\n), followed by o, d, e. Not good. % http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html % (and related messages, the final outcome is that it is up to the TeX % user to double the backslashes and otherwise make the string valid, so % that's what we do). % double active backslashes. % {\catcode`\@=0 \catcode`\\=\active @gdef@activebackslashdouble{% @catcode`@\=@active @let\=@doublebackslash} } % To handle parens, we must adopt a different approach, since parens are % not active characters. hyperref.dtx (which has the same problem as % us) handles it with this amazing macro to replace tokens, with minor % changes for Texinfo. It is included here under the GPL by permission % from the author, Heiko Oberdiek. % % #1 is the tokens to replace. % #2 is the replacement. % #3 is the control sequence with the string. % \def\HyPsdSubst#1#2#3{% \def\HyPsdReplace##1#1##2\END{% ##1% \ifx\\##2\\% \else #2% \HyReturnAfterFi{% \HyPsdReplace##2\END }% \fi }% \xdef#3{\expandafter\HyPsdReplace#3#1\END}% } \long\def\HyReturnAfterFi#1\fi{\fi#1} % #1 is a control sequence in which to do the replacements. \def\backslashparens#1{% \xdef#1{#1}% redefine it as its expansion; the definition is simply % \lastnode when called from \setref -> \pdfmkdest. \HyPsdSubst{(}{\realbackslash(}{#1}% \HyPsdSubst{)}{\realbackslash)}{#1}% } \newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images with PDF output, and none of those formats could be found. (.eps cannot be supported due to the design of the PDF format; use regular TeX (DVI output) for that.)} \ifpdf % % Color manipulation macros based on pdfcolor.tex. \def\cmykDarkRed{0.28 1 1 0.35} \def\cmykBlack{0 0 0 1} % % k sets the color for filling (usual text, etc.); % K sets the color for stroking (thin rules, e.g., normal _'s). \def\pdfsetcolor#1{\pdfliteral{#1 k #1 K}} % % Set color, and create a mark which defines \thiscolor accordingly, % so that \makeheadline knows which color to restore. \def\setcolor#1{% \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% \domark \pdfsetcolor{#1}% } % \def\maincolor{\cmykBlack} \pdfsetcolor{\maincolor} \edef\thiscolor{\maincolor} \def\lastcolordefs{} % \def\makefootline{% \baselineskip24pt \line{\pdfsetcolor{\maincolor}\the\footline}% } % \def\makeheadline{% \vbox to 0pt{% \vskip-22.5pt \line{% \vbox to8.5pt{}% % Extract \thiscolor definition from the marks. \getcolormarks % Typeset the headline with \maincolor, then restore the color. \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% }% \vss }% \nointerlineskip } % % \pdfcatalog{/PageMode /UseOutlines} % % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). \def\dopdfimage#1#2#3{% \def\imagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% \def\imageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% % % pdftex (and the PDF format) support .png, .jpg, .pdf (among % others). Let's try in that order. \let\pdfimgext=\empty \begingroup \openin 1 #1.png \ifeof 1 \openin 1 #1.jpg \ifeof 1 \openin 1 #1.jpeg \ifeof 1 \openin 1 #1.JPG \ifeof 1 \openin 1 #1.pdf \ifeof 1 \openin 1 #1.PDF \ifeof 1 \errhelp = \nopdfimagehelp \errmessage{Could not find image file #1 for pdf}% \else \gdef\pdfimgext{PDF}% \fi \else \gdef\pdfimgext{pdf}% \fi \else \gdef\pdfimgext{JPG}% \fi \else \gdef\pdfimgext{jpeg}% \fi \else \gdef\pdfimgext{jpg}% \fi \else \gdef\pdfimgext{png}% \fi \closein 1 \endgroup % % without \immediate, ancient pdftex seg faults when the same image is % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) \ifnum\pdftexversion < 14 \immediate\pdfimage \else \immediate\pdfximage \fi \ifdim \wd0 >0pt width \imagewidth \fi \ifdim \wd2 >0pt height \imageheight \fi \ifnum\pdftexversion<13 #1.\pdfimgext \else {#1.\pdfimgext}% \fi \ifnum\pdftexversion < 14 \else \pdfrefximage \pdflastximage \fi} % \def\pdfmkdest#1{{% % We have to set dummies so commands such as @code, and characters % such as \, aren't expanded when present in a section title. \indexnofonts \turnoffactive \activebackslashdouble \makevalueexpandable \def\pdfdestname{#1}% \backslashparens\pdfdestname \safewhatsit{\pdfdest name{\pdfdestname} xyz}% }} % % used to mark target names; must be expandable. \def\pdfmkpgn#1{#1} % % by default, use a color that is dark enough to print on paper as % nearly black, but still distinguishable for online viewing. \def\urlcolor{\cmykDarkRed} \def\linkcolor{\cmykDarkRed} \def\endlink{\setcolor{\maincolor}\pdfendlink} % % Adding outlines to PDF; macros for calculating structure of outlines % come from Petr Olsak \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% \else \csname#1\endcsname \fi} \def\advancenumber#1{\tempnum=\expnumber{#1}\relax \advance\tempnum by 1 \expandafter\xdef\csname#1\endcsname{\the\tempnum}} % % #1 is the section text, which is what will be displayed in the % outline by the pdf viewer. #2 is the pdf expression for the number % of subentries (or empty, for subsubsections). #3 is the node text, % which might be empty if this toc entry had no corresponding node. % #4 is the page number % \def\dopdfoutline#1#2#3#4{% % Generate a link to the node text if that exists; else, use the % page number. We could generate a destination for the section % text in the case where a section has no node, but it doesn't % seem worth the trouble, since most documents are normally structured. \def\pdfoutlinedest{#3}% \ifx\pdfoutlinedest\empty \def\pdfoutlinedest{#4}% \else % Doubled backslashes in the name. {\activebackslashdouble \xdef\pdfoutlinedest{#3}% \backslashparens\pdfoutlinedest}% \fi % % Also double the backslashes in the display string. {\activebackslashdouble \xdef\pdfoutlinetext{#1}% \backslashparens\pdfoutlinetext}% % \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% } % \def\pdfmakeoutlines{% \begingroup % Thanh's hack / proper braces in bookmarks \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace % % Read toc silently, to get counts of subentries for \pdfoutline. \def\numchapentry##1##2##3##4{% \def\thischapnum{##2}% \def\thissecnum{0}% \def\thissubsecnum{0}% }% \def\numsecentry##1##2##3##4{% \advancenumber{chap\thischapnum}% \def\thissecnum{##2}% \def\thissubsecnum{0}% }% \def\numsubsecentry##1##2##3##4{% \advancenumber{sec\thissecnum}% \def\thissubsecnum{##2}% }% \def\numsubsubsecentry##1##2##3##4{% \advancenumber{subsec\thissubsecnum}% }% \def\thischapnum{0}% \def\thissecnum{0}% \def\thissubsecnum{0}% % % use \def rather than \let here because we redefine \chapentry et % al. a second time, below. \def\appentry{\numchapentry}% \def\appsecentry{\numsecentry}% \def\appsubsecentry{\numsubsecentry}% \def\appsubsubsecentry{\numsubsubsecentry}% \def\unnchapentry{\numchapentry}% \def\unnsecentry{\numsecentry}% \def\unnsubsecentry{\numsubsecentry}% \def\unnsubsubsecentry{\numsubsubsecentry}% \readdatafile{toc}% % % Read toc second time, this time actually producing the outlines. % The `-' means take the \expnumber as the absolute number of % subentries, which we calculated on our first read of the .toc above. % % We use the node names as the destinations. \def\numchapentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% \def\numsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% \def\numsubsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% \def\numsubsubsecentry##1##2##3##4{% count is always zero \dopdfoutline{##1}{}{##3}{##4}}% % % PDF outlines are displayed using system fonts, instead of % document fonts. Therefore we cannot use special characters, % since the encoding is unknown. For example, the eogonek from % Latin 2 (0xea) gets translated to a | character. Info from % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. % % xx to do this right, we have to translate 8-bit characters to % their "best" equivalent, based on the @documentencoding. Right % now, I guess we'll just let the pdf reader have its way. \indexnofonts \setupdatafile \catcode`\\=\active \otherbackslash \input \tocreadfilename \endgroup } % \def\skipspaces#1{\def\PP{#1}\def\D{|}% \ifx\PP\D\let\nextsp\relax \else\let\nextsp\skipspaces \ifx\p\space\else\addtokens{\filename}{\PP}% \advance\filenamelength by 1 \fi \fi \nextsp} \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} \ifnum\pdftexversion < 14 \let \startlink \pdfannotlink \else \let \startlink \pdfstartlink \fi % make a live url in pdf output. \def\pdfurl#1{% \begingroup % it seems we really need yet another set of dummies; have not % tried to figure out what each command should do in the context % of @url. for now, just make @/ a no-op, that's the only one % people have actually reported a problem with. % \normalturnoffactive \def\@{@}% \let\/=\empty \makevalueexpandable % do we want to go so far as to use \indexnofonts instead of just % special-casing \var here? \def\var##1{##1}% % \leavevmode\setcolor{\urlcolor}% \startlink attr{/Border [0 0 0]}% user{/Subtype /Link /A << /S /URI /URI (#1) >>}% \endgroup} \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} \def\maketoks{% \expandafter\poptoks\the\toksA|ENDTOKS|\relax \ifx\first0\adn0 \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 \else \ifnum0=\countA\else\makelink\fi \ifx\first.\let\next=\done\else \let\next=\maketoks \addtokens{\toksB}{\the\toksD} \ifx\first,\addtokens{\toksB}{\space}\fi \fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} \def\pdflink#1{% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} \setcolor{\linkcolor}#1\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} \else % non-pdf mode \let\pdfmkdest = \gobble \let\pdfurl = \gobble \let\endlink = \relax \let\setcolor = \gobble \let\pdfsetcolor = \gobble \let\pdfmakeoutlines = \relax \fi % \ifx\pdfoutput \message{fonts,} % Change the current font style to #1, remembering it in \curfontstyle. % For now, we do not accumulate font styles: @b{@i{foo}} prints foo in % italics, not bold italics. % \def\setfontstyle#1{% \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. \csname ten#1\endcsname % change the current font } % Select #1 fonts with the current style. % \def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} \def\rm{\fam=0 \setfontstyle{rm}} \def\it{\fam=\itfam \setfontstyle{it}} \def\sl{\fam=\slfam \setfontstyle{sl}} \def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} \def\tt{\fam=\ttfam \setfontstyle{tt}} % Unfortunately, we have to override this for titles and the like, since % in those cases "rm" is bold. Sigh. \def\rmisbold{\rm\def\curfontstyle{bf}} % Texinfo sort of supports the sans serif font style, which plain TeX does not. % So we set up a \sf. \newfam\sffam \def\sf{\fam=\sffam \setfontstyle{sf}} \let\li = \sf % Sometimes we call it \li, not \sf. % We don't need math for this font style. \def\ttsl{\setfontstyle{ttsl}} % Default leading. \newdimen\textleading \textleading = 13.2pt % Set the baselineskip to #1, and the lineskip and strut size % correspondingly. There is no deep meaning behind these magic numbers % used as factors; they just match (closely enough) what Knuth defined. % \def\lineskipfactor{.08333} \def\strutheightpercent{.70833} \def\strutdepthpercent {.29167} % % can get a sort of poor man's double spacing by redefining this. \def\baselinefactor{1} % \def\setleading#1{% \dimen0 = #1\relax \normalbaselineskip = \baselinefactor\dimen0 \normallineskip = \lineskipfactor\normalbaselineskip \normalbaselines \setbox\strutbox =\hbox{% \vrule width0pt height\strutheightpercent\baselineskip depth \strutdepthpercent \baselineskip }% } % PDF CMaps. See also LaTeX's t1.cmap. % % do nothing with this by default. \expandafter\let\csname cmapOT1\endcsname\gobble \expandafter\let\csname cmapOT1IT\endcsname\gobble \expandafter\let\csname cmapOT1TT\endcsname\gobble % if we are producing pdf, and we have \pdffontattr, then define cmaps. % (\pdffontattr was introduced many years ago, but people still run % older pdftex's; it's easy to conditionalize, so we do.) \ifpdf \ifx\pdffontattr\undefined \else \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1-0) %%Title: (TeX-OT1-0 TeX OT1 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1) /Supplement 0 >> def /CMapName /TeX-OT1-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <23> <26> <0023> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 40 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1IT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1IT-0) %%Title: (TeX-OT1IT-0 TeX OT1IT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1IT) /Supplement 0 >> def /CMapName /TeX-OT1IT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <25> <26> <0025> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 42 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <23> <0023> <24> <00A3> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1IT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1TT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1TT-0) %%Title: (TeX-OT1TT-0 TeX OT1TT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1TT) /Supplement 0 >> def /CMapName /TeX-OT1TT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 5 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <21> <26> <0021> <28> <5F> <0028> <61> <7E> <0061> endbfrange 32 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <2191> <0C> <2193> <0D> <0027> <0E> <00A1> <0F> <00BF> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <20> <2423> <27> <2019> <60> <2018> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1TT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% \fi\fi % Set the font macro #1 to the font named #2, adding on the % specified font prefix (normally `cm'). % #3 is the font's design size, #4 is a scale factor, #5 is the CMap % encoding (currently only OT1, OT1IT and OT1TT are allowed, pass % empty to omit). \def\setfont#1#2#3#4#5{% \font#1=\fontprefix#2#3 scaled #4 \csname cmap#5\endcsname#1% } % This is what gets called when #5 of \setfont is empty. \let\cmap\gobble % emacs-page end of cmaps % Use cm as the default font prefix. % To specify the font prefix, you must define \fontprefix % before you read in texinfo.tex. \ifx\fontprefix\undefined \def\fontprefix{cm} \fi % Support font families that don't use the same naming scheme as CM. \def\rmshape{r} \def\rmbshape{bx} %where the normal face is bold \def\bfshape{b} \def\bxshape{bx} \def\ttshape{tt} \def\ttbshape{tt} \def\ttslshape{sltt} \def\itshape{ti} \def\itbshape{bxti} \def\slshape{sl} \def\slbshape{bxsl} \def\sfshape{ss} \def\sfbshape{ss} \def\scshape{csc} \def\scbshape{csc} % Definitions for a main text size of 11pt. This is the default in % Texinfo. % \def\definetextfontsizexi{% % Text fonts (11.2pt, magstep1). \def\textnominalsize{11pt} \edef\mainmagstep{\magstephalf} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1095} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstep1}{OT1} \setfont\deftt\ttshape{10}{\magstep1}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter (and unnumbered) fonts (17.28pt). \def\chapnominalsize{17pt} \setfont\chaprm\rmbshape{12}{\magstep2}{OT1} \setfont\chapit\itbshape{10}{\magstep3}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep3}{OT1} \setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} \setfont\chapsf\sfbshape{17}{1000}{OT1} \let\chapbf=\chaprm \setfont\chapsc\scbshape{10}{\magstep3}{OT1} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 \def\chapecsize{1728} % Section fonts (14.4pt). \def\secnominalsize{14pt} \setfont\secrm\rmbshape{12}{\magstep1}{OT1} \setfont\secit\itbshape{10}{\magstep2}{OT1IT} \setfont\secsl\slbshape{10}{\magstep2}{OT1} \setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\secsf\sfbshape{12}{\magstep1}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep2}{OT1} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 \def\sececsize{1440} % Subsection fonts (13.15pt). \def\ssecnominalsize{13pt} \setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} \setfont\ssecit\itbshape{10}{1315}{OT1IT} \setfont\ssecsl\slbshape{10}{1315}{OT1} \setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} \setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1315}{OT1} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled 1315 \def\ssececsize{1200} % Reduced fonts for @acro in text (10pt). \def\reducednominalsize{10pt} \setfont\reducedrm\rmshape{10}{1000}{OT1} \setfont\reducedtt\ttshape{10}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{1000}{OT1} \setfont\reducedit\itshape{10}{1000}{OT1IT} \setfont\reducedsl\slshape{10}{1000}{OT1} \setfont\reducedsf\sfshape{10}{1000}{OT1} \setfont\reducedsc\scshape{10}{1000}{OT1} \setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} \font\reducedi=cmmi10 \font\reducedsy=cmsy10 \def\reducedecsize{1000} % reset the current fonts \textfonts \rm } % end of 11pt text font size definitions % Definitions to make the main text be 10pt Computer Modern, with % section, chapter, etc., sizes following suit. This is for the GNU % Press printing of the Emacs 22 manual. Maybe other manuals in the % future. Used with @smallbook, which sets the leading to 12pt. % \def\definetextfontsizex{% % Text fonts (10pt). \def\textnominalsize{10pt} \edef\mainmagstep{1000} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1000} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstephalf}{OT1} \setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter fonts (14.4pt). \def\chapnominalsize{14pt} \setfont\chaprm\rmbshape{12}{\magstep1}{OT1} \setfont\chapit\itbshape{10}{\magstep2}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep2}{OT1} \setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\chapsf\sfbshape{12}{\magstep1}{OT1} \let\chapbf\chaprm \setfont\chapsc\scbshape{10}{\magstep2}{OT1} \font\chapi=cmmi12 scaled \magstep1 \font\chapsy=cmsy10 scaled \magstep2 \def\chapecsize{1440} % Section fonts (12pt). \def\secnominalsize{12pt} \setfont\secrm\rmbshape{12}{1000}{OT1} \setfont\secit\itbshape{10}{\magstep1}{OT1IT} \setfont\secsl\slbshape{10}{\magstep1}{OT1} \setfont\sectt\ttbshape{12}{1000}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} \setfont\secsf\sfbshape{12}{1000}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep1}{OT1} \font\seci=cmmi12 \font\secsy=cmsy10 scaled \magstep1 \def\sececsize{1200} % Subsection fonts (10pt). \def\ssecnominalsize{10pt} \setfont\ssecrm\rmbshape{10}{1000}{OT1} \setfont\ssecit\itbshape{10}{1000}{OT1IT} \setfont\ssecsl\slbshape{10}{1000}{OT1} \setfont\ssectt\ttbshape{10}{1000}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} \setfont\ssecsf\sfbshape{10}{1000}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1000}{OT1} \font\sseci=cmmi10 \font\ssecsy=cmsy10 \def\ssececsize{1000} % Reduced fonts for @acro in text (9pt). \def\reducednominalsize{9pt} \setfont\reducedrm\rmshape{9}{1000}{OT1} \setfont\reducedtt\ttshape{9}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{900}{OT1} \setfont\reducedit\itshape{9}{1000}{OT1IT} \setfont\reducedsl\slshape{9}{1000}{OT1} \setfont\reducedsf\sfshape{9}{1000}{OT1} \setfont\reducedsc\scshape{10}{900}{OT1} \setfont\reducedttsl\ttslshape{10}{900}{OT1TT} \font\reducedi=cmmi9 \font\reducedsy=cmsy9 \def\reducedecsize{0900} % reduce space between paragraphs \divide\parskip by 2 % reset the current fonts \textfonts \rm } % end of 10pt text font size definitions % We provide the user-level command % @fonttextsize 10 % (or 11) to redefine the text font size. pt is assumed. % \def\xword{10} \def\xiword{11} % \parseargdef\fonttextsize{% \def\textsizearg{#1}% \wlog{doing @fonttextsize \textsizearg}% % % Set \globaldefs so that documents can use this inside @tex, since % makeinfo 4.8 does not support it, but we need it nonetheless. % \begingroup \globaldefs=1 \ifx\textsizearg\xword \definetextfontsizex \else \ifx\textsizearg\xiword \definetextfontsizexi \else \errhelp=\EMsimple \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} \fi\fi \endgroup } % In order for the font changes to affect most math symbols and letters, % we have to define the \textfont of the standard families. Since % texinfo doesn't allow for producing subscripts and superscripts except % in the main text, we don't bother to reset \scriptfont and % \scriptscriptfont (which would also require loading a lot more fonts). % \def\resetmathfonts{% \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf \textfont\ttfam=\tentt \textfont\sffam=\tensf } % The font-changing commands redefine the meanings of \tenSTYLE, instead % of just \STYLE. We do this because \STYLE needs to also set the % current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire % \tenSTYLE to set the current font. % % Each font-changing command also sets the names \lsize (one size lower) % and \lllsize (three sizes lower). These relative commands are used in % the LaTeX logo and acronyms. % % This all needs generalizing, badly. % \def\textfonts{% \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl \def\curfontsize{text}% \def\lsize{reduced}\def\lllsize{smaller}% \resetmathfonts \setleading{\textleading}} \def\titlefonts{% \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy \let\tenttsl=\titlettsl \def\curfontsize{title}% \def\lsize{chap}\def\lllsize{subsec}% \resetmathfonts \setleading{25pt}} \def\titlefont#1{{\titlefonts\rmisbold #1}} \def\chapfonts{% \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl \def\curfontsize{chap}% \def\lsize{sec}\def\lllsize{text}% \resetmathfonts \setleading{19pt}} \def\secfonts{% \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl \def\curfontsize{sec}% \def\lsize{subsec}\def\lllsize{reduced}% \resetmathfonts \setleading{16pt}} \def\subsecfonts{% \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl \def\curfontsize{ssec}% \def\lsize{text}\def\lllsize{small}% \resetmathfonts \setleading{15pt}} \let\subsubsecfonts = \subsecfonts \def\reducedfonts{% \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy \let\tenttsl=\reducedttsl \def\curfontsize{reduced}% \def\lsize{small}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallfonts{% \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy \let\tenttsl=\smallttsl \def\curfontsize{small}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallerfonts{% \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy \let\tenttsl=\smallerttsl \def\curfontsize{smaller}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{9.5pt}} % Fonts for short table of contents. \setfont\shortcontrm\rmshape{12}{1000}{OT1} \setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 \setfont\shortcontsl\slshape{12}{1000}{OT1} \setfont\shortconttt\ttshape{12}{1000}{OT1TT} % Define these just so they can be easily changed for other fonts. \def\angleleft{$\langle$} \def\angleright{$\rangle$} % Set the fonts to use with the @small... environments. \let\smallexamplefonts = \smallfonts % About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample % can fit this many characters: % 8.5x11=86 smallbook=72 a4=90 a5=69 % If we use \scriptfonts (8pt), then we can fit this many characters: % 8.5x11=90+ smallbook=80 a4=90+ a5=77 % For me, subjectively, the few extra characters that fit aren't worth % the additional smallness of 8pt. So I'm making the default 9pt. % % By the way, for comparison, here's what fits with @example (10pt): % 8.5x11=71 smallbook=60 a4=75 a5=58 % --karl, 24jan03. % Set up the default fonts, so we can use them for creating boxes. % \definetextfontsizexi \message{markup,} % Check if we are currently using a typewriter font. Since all the % Computer Modern typewriter fonts have zero interword stretch (and % shrink), and it is reasonable to expect all typewriter fonts to have % this property, we can check that font parameter. % \def\ifmonospace{\ifdim\fontdimen3\font=0pt } % Markup style infrastructure. \defmarkupstylesetup\INITMACRO will % define and register \INITMACRO to be called on markup style changes. % \INITMACRO can check \currentmarkupstyle for the innermost % style and the set of \ifmarkupSTYLE switches for all styles % currently in effect. \newif\ifmarkupvar \newif\ifmarkupsamp \newif\ifmarkupkey %\newif\ifmarkupfile % @file == @samp. %\newif\ifmarkupoption % @option == @samp. \newif\ifmarkupcode \newif\ifmarkupkbd %\newif\ifmarkupenv % @env == @code. %\newif\ifmarkupcommand % @command == @code. \newif\ifmarkuptex % @tex (and part of @math, for now). \newif\ifmarkupexample \newif\ifmarkupverb \newif\ifmarkupverbatim \let\currentmarkupstyle\empty \def\setupmarkupstyle#1{% \csname markup#1true\endcsname \def\currentmarkupstyle{#1}% \markupstylesetup } \let\markupstylesetup\empty \def\defmarkupstylesetup#1{% \expandafter\def\expandafter\markupstylesetup \expandafter{\markupstylesetup #1}% \def#1% } % Markup style setup for left and right quotes. \defmarkupstylesetup\markupsetuplq{% \expandafter\let\expandafter \temp \csname markupsetuplq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuplqdefault \else \temp \fi } \defmarkupstylesetup\markupsetuprq{% \expandafter\let\expandafter \temp \csname markupsetuprq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuprqdefault \else \temp \fi } { \catcode`\'=\active \catcode`\`=\active \gdef\markupsetuplqdefault{\let`\lq} \gdef\markupsetuprqdefault{\let'\rq} \gdef\markupsetcodequoteleft{\let`\codequoteleft} \gdef\markupsetcodequoteright{\let'\codequoteright} \gdef\markupsetnoligaturesquoteleft{\let`\noligaturesquoteleft} } \let\markupsetuplqcode \markupsetcodequoteleft \let\markupsetuprqcode \markupsetcodequoteright \let\markupsetuplqexample \markupsetcodequoteleft \let\markupsetuprqexample \markupsetcodequoteright \let\markupsetuplqverb \markupsetcodequoteleft \let\markupsetuprqverb \markupsetcodequoteright \let\markupsetuplqverbatim \markupsetcodequoteleft \let\markupsetuprqverbatim \markupsetcodequoteright \let\markupsetuplqsamp \markupsetnoligaturesquoteleft \let\markupsetuplqkbd \markupsetnoligaturesquoteleft % Allow an option to not replace quotes with a regular directed right % quote/apostrophe (char 0x27), but instead use the undirected quote % from cmtt (char 0x0d). The undirected quote is ugly, so don't make it % the default, but it works for pasting with more pdf viewers (at least % evince), the lilypond developers report. xpdf does work with the % regular 0x27. % \def\codequoteright{% \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax '% \else \char'15 \fi \else \char'15 \fi } % % and a similar option for the left quote char vs. a grave accent. % Modern fonts display ASCII 0x60 as a grave accent, so some people like % the code environments to do likewise. % \def\codequoteleft{% \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax % [Knuth] pp. 380,381,391 % \relax disables Spanish ligatures ?` and !` of \tt font. \relax`% \else \char'22 \fi \else \char'22 \fi } % [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font. \def\noligaturesquoteleft{\relax\lq} % Count depth in font-changes, for error checks \newcount\fontdepth \fontdepth=0 %% Add scribe-like font environments, plus @l for inline lisp (usually sans %% serif) and @ii for TeX italic % \smartitalic{ARG} outputs arg in italics, followed by an italic correction % unless the following character is such as not to need one. \def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else \ptexslash\fi\fi\fi} \def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx} \def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx} % like \smartslanted except unconditionally uses \ttsl. % @var is set to this for defun arguments. \def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx} % @cite is like \smartslanted except unconditionally use \sl. We never want % ttsl for book titles, do we? \def\cite#1{{\sl #1}\futurelet\next\smartitalicx} \let\i=\smartitalic \let\slanted=\smartslanted \def\var#1{{\setupmarkupstyle{var}\smartslanted{#1}}} \let\dfn=\smartslanted \let\emph=\smartitalic % Explicit font changes: @r, @sc, undocumented @ii. \def\r#1{{\rm #1}} % roman font \def\sc#1{{\smallcaps#1}} % smallcaps font \def\ii#1{{\it #1}} % italic font % @b, explicit bold. Also @strong. \def\b#1{{\bf #1}} \let\strong=\b % @sansserif, explicit sans. \def\sansserif#1{{\sf #1}} % We can't just use \exhyphenpenalty, because that only has effect at % the end of a paragraph. Restore normal hyphenation at the end of the % group within which \nohyphenation is presumably called. % \def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} \def\restorehyphenation{\hyphenchar\font = `- } % Set sfcode to normal for the chars that usually have another value. % Can't use plain's \frenchspacing because it uses the `\x notation, and % sometimes \x has an active definition that messes things up. % \catcode`@=11 \def\plainfrenchspacing{% \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m \def\endofsentencespacefactor{1000}% for @. and friends } \def\plainnonfrenchspacing{% \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 \def\endofsentencespacefactor{3000}% for @. and friends } \catcode`@=\other \def\endofsentencespacefactor{3000}% default % @t, explicit typewriter. \def\t#1{% {\tt \rawbackslash \plainfrenchspacing #1}% \null } % @samp. \def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}} % definition of @key that produces a lozenge. Doesn't adjust to text size. %\setfont\keyrm\rmshape{8}{1000}{OT1} %\font\keysy=cmsy9 %\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% % \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% % \vbox{\hrule\kern-0.4pt % \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% % \kern-0.4pt\hrule}% % \kern-.06em\raise0.4pt\hbox{\angleright}}}} % definition of @key with no lozenge. If the current font is already % monospace, don't change it; that way, we respect @kbdinputstyle. But % if it isn't monospace, then use \tt. % \def\key#1{{\setupmarkupstyle{key}% \nohyphenation \ifmonospace\else\tt\fi #1}\null} % ctrl is no longer a Texinfo command. \def\ctrl #1{{\tt \rawbackslash \hat}#1} % @file, @option are the same as @samp. \let\file=\samp \let\option=\samp % @code is a modification of @t, % which makes spaces the same size as normal in the surrounding text. \def\tclose#1{% {% % Change normal interword space to be same as for the current font. \spaceskip = \fontdimen2\font % % Switch to typewriter. \tt % % But `\ ' produces the large typewriter interword space. \def\ {{\spaceskip = 0pt{} }}% % % Turn off hyphenation. \nohyphenation % \rawbackslash \plainfrenchspacing #1% }% \null } % We *must* turn on hyphenation at `-' and `_' in @code. % Otherwise, it is too hard to avoid overfull hboxes % in the Emacs manual, the Library manual, etc. % Unfortunately, TeX uses one parameter (\hyphenchar) to control % both hyphenation at - and hyphenation within words. % We must therefore turn them both off (\tclose does that) % and arrange explicitly to hyphenate at a dash. % -- rms. { \catcode`\-=\active \catcode`\_=\active \catcode`\'=\active \catcode`\`=\active \global\let'=\rq \global\let`=\lq % default definitions % \global\def\code{\begingroup \setupmarkupstyle{code}% % The following should really be moved into \setupmarkupstyle handlers. \catcode\dashChar=\active \catcode\underChar=\active \ifallowcodebreaks \let-\codedash \let_\codeunder \else \let-\realdash \let_\realunder \fi \codex } } \def\realdash{-} \def\codedash{-\discretionary{}{}{}} \def\codeunder{% % this is all so @math{@code{var_name}+1} can work. In math mode, _ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) % will therefore expand the active definition of _, which is us % (inside @code that is), therefore an endless loop. \ifusingtt{\ifmmode \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. \else\normalunderscore \fi \discretionary{}{}{}}% {\_}% } \def\codex #1{\tclose{#1}\endgroup} % An additional complication: the above will allow breaks after, e.g., % each of the four underscores in __typeof__. This is undesirable in % some manuals, especially if they don't have long identifiers in % general. @allowcodebreaks provides a way to control this. % \newif\ifallowcodebreaks \allowcodebreakstrue \def\keywordtrue{true} \def\keywordfalse{false} \parseargdef\allowcodebreaks{% \def\txiarg{#1}% \ifx\txiarg\keywordtrue \allowcodebreakstrue \else\ifx\txiarg\keywordfalse \allowcodebreaksfalse \else \errhelp = \EMsimple \errmessage{Unknown @allowcodebreaks option `\txiarg'}% \fi\fi } % @kbd is like @code, except that if the argument is just one @key command, % then @kbd has no effect. \def\kbd#1{{\setupmarkupstyle{kbd}\def\look{#1}\expandafter\kbdfoo\look??\par}} % @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), % `example' (@kbd uses ttsl only inside of @example and friends), % or `code' (@kbd uses normal tty font always). \parseargdef\kbdinputstyle{% \def\txiarg{#1}% \ifx\txiarg\worddistinct \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% \else\ifx\txiarg\wordexample \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% \else\ifx\txiarg\wordcode \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% \else \errhelp = \EMsimple \errmessage{Unknown @kbdinputstyle option `\txiarg'}% \fi\fi\fi } \def\worddistinct{distinct} \def\wordexample{example} \def\wordcode{code} % Default is `distinct'. \kbdinputstyle distinct \def\xkey{\key} \def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% \ifx\one\xkey\ifx\threex\three \key{#2}% \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi} % For @indicateurl, @env, @command quotes seem unnecessary, so use \code. \let\indicateurl=\code \let\env=\code \let\command=\code % @clicksequence{File @click{} Open ...} \def\clicksequence#1{\begingroup #1\endgroup} % @clickstyle @arrow (by default) \parseargdef\clickstyle{\def\click{#1}} \def\click{\arrow} % @uref (abbreviation for `urlref') takes an optional (comma-separated) % second argument specifying the text to display and an optional third % arg as text to display instead of (rather than in addition to) the url % itself. First (mandatory) arg is the url. Perhaps eventually put in % a hypertex \special here. % \def\uref#1{\douref #1,,,\finish} \def\douref#1,#2,#3,#4\finish{\begingroup \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url \fi \else \code{#1}% only url given, so show it \fi \fi \endlink \endgroup} % @url synonym for @uref, since that's how everyone uses it. % \let\url=\uref % rms does not like angle brackets --karl, 17may97. % So now @email is just like @uref, unless we are pdf. % %\def\email#1{\angleleft{\tt #1}\angleright} \ifpdf \def\email#1{\doemail#1,,\finish} \def\doemail#1,#2,#3\finish{\begingroup \unsepspaces \pdfurl{mailto:#1}% \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi \endlink \endgroup} \else \let\email=\uref \fi % Typeset a dimension, e.g., `in' or `pt'. The only reason for the % argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. % \def\dmn#1{\thinspace #1} % @l was never documented to mean ``switch to the Lisp font'', % and it is not used as such in any manual I can find. We need it for % Polish suppressed-l. --karl, 22sep96. %\def\l#1{{\li #1}\null} % @acronym for "FBI", "NATO", and the like. % We print this one point size smaller, since it's intended for % all-uppercase. % \def\acronym#1{\doacronym #1,,\finish} \def\doacronym#1,#2,#3\finish{% {\selectfonts\lsize #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi } % @abbr for "Comput. J." and the like. % No font change, but don't do end-of-sentence spacing. % \def\abbr#1{\doabbr #1,,\finish} \def\doabbr#1,#2,#3\finish{% {\plainfrenchspacing #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi } \message{glyphs,} % @point{}, @result{}, @expansion{}, @print{}, @equiv{}. % % Since these characters are used in examples, they should be an even number of % \tt widths. Each \tt character is 1en, so two makes it 1em. % \def\point{$\star$} \def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}} \def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} \def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}} \def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} \def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}} % The @error{} command. % Adapted from the TeXbook's \boxit. % \newbox\errorbox % {\tentt \global\dimen0 = 3em}% Width of the box. \dimen2 = .55pt % Thickness of rules % The text. (`r' is open on the right, `e' somewhat less so on the left.) \setbox0 = \hbox{\kern-.75pt \reducedsf error\kern-1.5pt} % \setbox\errorbox=\hbox to \dimen0{\hfil \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. \advance\hsize by -2\dimen2 % Rules. \vbox{% \hrule height\dimen2 \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. \kern3pt\vrule width\dimen2}% Space to right. \hrule height\dimen2} \hfil} % \def\error{\leavevmode\lower.7ex\copy\errorbox} % @pounds{} is a sterling sign, which Knuth put in the CM italic font. % \def\pounds{{\it\$}} % @euro{} comes from a separate font, depending on the current style. % We use the free feym* fonts from the eurosym package by Henrik % Theiling, which support regular, slanted, bold and bold slanted (and % "outlined" (blackboard board, sort of) versions, which we don't need). % It is available from http://www.ctan.org/tex-archive/fonts/eurosym. % % Although only regular is the truly official Euro symbol, we ignore % that. The Euro is designed to be slightly taller than the regular % font height. % % feymr - regular % feymo - slanted % feybr - bold % feybo - bold slanted % % There is no good (free) typewriter version, to my knowledge. % A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. % Hmm. % % Also doesn't work in math. Do we need to do math with euro symbols? % Hope not. % % \def\euro{{\eurofont e}} \def\eurofont{% % We set the font at each command, rather than predefining it in % \textfonts and the other font-switching commands, so that % installations which never need the symbol don't have to have the % font installed. % % There is only one designed size (nominal 10pt), so we always scale % that to the current nominal size. % % By the way, simply using "at 1em" works for cmr10 and the like, but % does not work for cmbx10 and other extended/shrunken fonts. % \def\eurosize{\csname\curfontsize nominalsize\endcsname}% % \ifx\curfontstyle\bfstylename % bold: \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize \else % regular: \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize \fi \thiseurofont } % Glyphs from the EC fonts. We don't use \let for the aliases, because % sometimes we redefine the original macro, and the alias should reflect % the redefinition. % % Use LaTeX names for the Icelandic letters. \def\DH{{\ecfont \char"D0}} % Eth \def\dh{{\ecfont \char"F0}} % eth \def\TH{{\ecfont \char"DE}} % Thorn \def\th{{\ecfont \char"FE}} % thorn % \def\guillemetleft{{\ecfont \char"13}} \def\guillemotleft{\guillemetleft} \def\guillemetright{{\ecfont \char"14}} \def\guillemotright{\guillemetright} \def\guilsinglleft{{\ecfont \char"0E}} \def\guilsinglright{{\ecfont \char"0F}} \def\quotedblbase{{\ecfont \char"12}} \def\quotesinglbase{{\ecfont \char"0D}} % % This positioning is not perfect (see the ogonek LaTeX package), but % we have the precomposed glyphs for the most common cases. We put the % tests to use those glyphs in the single \ogonek macro so we have fewer % dummy definitions to worry about for index entries, etc. % % ogonek is also used with other letters in Lithuanian (IOU), but using % the precomposed glyphs for those is not so easy since they aren't in % the same EC font. \def\ogonek#1{{% \def\temp{#1}% \ifx\temp\macrocharA\Aogonek \else\ifx\temp\macrochara\aogonek \else\ifx\temp\macrocharE\Eogonek \else\ifx\temp\macrochare\eogonek \else \ecfont \setbox0=\hbox{#1}% \ifdim\ht0=1ex\accent"0C #1% \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}% \fi \fi\fi\fi\fi }% } \def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A} \def\aogonek{{\ecfont \char"A1}}\def\macrochara{a} \def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E} \def\eogonek{{\ecfont \char"A6}}\def\macrochare{e} % % Use the ec* fonts (cm-super in outline format) for non-CM glyphs. \def\ecfont{% % We can't distinguish serif/sans and italic/slanted, but this % is used for crude hacks anyway (like adding French and German % quotes to documents typeset with CM, where we lose kerning), so % hopefully nobody will notice/care. \edef\ecsize{\csname\curfontsize ecsize\endcsname}% \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}% \ifx\curfontstyle\bfstylename % bold: \font\thisecfont = ecb\ifusingit{i}{x}\ecsize \space at \nominalsize \else % regular: \font\thisecfont = ec\ifusingit{ti}{rm}\ecsize \space at \nominalsize \fi \thisecfont } % @registeredsymbol - R in a circle. The font for the R should really % be smaller yet, but lllsize is the best we can do for now. % Adapted from the plain.tex definition of \copyright. % \def\registeredsymbol{% $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% \hfil\crcr\Orb}}% }$% } % @textdegree - the normal degrees sign. % \def\textdegree{$^\circ$} % Laurent Siebenmann reports \Orb undefined with: % Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 % so we'll define it if necessary. % \ifx\Orb\undefined \def\Orb{\mathhexbox20D} \fi % Quotes. \chardef\quotedblleft="5C \chardef\quotedblright=`\" \chardef\quoteleft=`\` \chardef\quoteright=`\' \message{page headings,} \newskip\titlepagetopglue \titlepagetopglue = 1.5in \newskip\titlepagebottomglue \titlepagebottomglue = 2pc % First the title page. Must do @settitle before @titlepage. \newif\ifseenauthor \newif\iffinishedtitlepage % Do an implicit @contents or @shortcontents after @end titlepage if the % user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. % \newif\ifsetcontentsaftertitlepage \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue \newif\ifsetshortcontentsaftertitlepage \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue \parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% \endgroup\page\hbox{}\page} \envdef\titlepage{% % Open one extra group, as we want to close it in the middle of \Etitlepage. \begingroup \parindent=0pt \textfonts % Leave some space at the very top of the page. \vglue\titlepagetopglue % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % % Most title ``pages'' are actually two pages long, with space % at the top of the second. We don't want the ragged left on the second. \let\oldpage = \page \def\page{% \iffinishedtitlepage\else \finishtitlepage \fi \let\page = \oldpage \page \null }% } \def\Etitlepage{% \iffinishedtitlepage\else \finishtitlepage \fi % It is important to do the page break before ending the group, % because the headline and footline are only empty inside the group. % If we use the new definition of \page, we always get a blank page % after the title page, which we certainly don't want. \oldpage \endgroup % % Need this before the \...aftertitlepage checks so that if they are % in effect the toc pages will come out with page numbers. \HEADINGSon % % If they want short, they certainly want long too. \ifsetshortcontentsaftertitlepage \shortcontents \contents \global\let\shortcontents = \relax \global\let\contents = \relax \fi % \ifsetcontentsaftertitlepage \contents \global\let\contents = \relax \global\let\shortcontents = \relax \fi } \def\finishtitlepage{% \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } %%% Macros to be used within @titlepage: \let\subtitlerm=\tenrm \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} \parseargdef\title{% \checkenv\titlepage \leftline{\titlefonts\rmisbold #1} % print a rule at the page bottom also. \finishedtitlepagefalse \vskip4pt \hrule height 4pt width \hsize \vskip4pt } \parseargdef\subtitle{% \checkenv\titlepage {\subtitlefont \rightline{#1}}% } % @author should come last, but may come many times. % It can also be used inside @quotation. % \parseargdef\author{% \def\temp{\quotation}% \ifx\thisenv\temp \def\quotationauthor{#1}% printed in \Equotation. \else \checkenv\titlepage \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi {\secfonts\rmisbold \leftline{#1}}% \fi } %%% Set up page headings and footings. \let\thispage=\folio \newtoks\evenheadline % headline on even pages \newtoks\oddheadline % headline on odd pages \newtoks\evenfootline % footline on even pages \newtoks\oddfootline % footline on odd pages % Now make TeX use those variables \headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}} \footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}\HEADINGShook} \let\HEADINGShook=\relax % Commands to set those variables. % For example, this is what @headings on does % @evenheading @thistitle|@thispage|@thischapter % @oddheading @thischapter|@thispage|@thistitle % @evenfooting @thisfile|| % @oddfooting ||@thisfile \def\evenheading{\parsearg\evenheadingxxx} \def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} \def\evenheadingyyy #1\|#2\|#3\|#4\finish{% \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddheading{\parsearg\oddheadingxxx} \def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} \def\oddheadingyyy #1\|#2\|#3\|#4\finish{% \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% \def\evenfooting{\parsearg\evenfootingxxx} \def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} \def\evenfootingyyy #1\|#2\|#3\|#4\finish{% \global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddfooting{\parsearg\oddfootingxxx} \def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} \def\oddfootingyyy #1\|#2\|#3\|#4\finish{% \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% % % Leave some space for the footline. Hopefully ok to assume % @evenfooting will not be used by itself. \global\advance\pageheight by -12pt \global\advance\vsize by -12pt } \parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} % @evenheadingmarks top \thischapter <- chapter at the top of a page % @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page % % The same set of arguments for: % % @oddheadingmarks % @evenfootingmarks % @oddfootingmarks % @everyheadingmarks % @everyfootingmarks \def\evenheadingmarks{\headingmarks{even}{heading}} \def\oddheadingmarks{\headingmarks{odd}{heading}} \def\evenfootingmarks{\headingmarks{even}{footing}} \def\oddfootingmarks{\headingmarks{odd}{footing}} \def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1} \headingmarks{odd}{heading}{#1} } \def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1} \headingmarks{odd}{footing}{#1} } % #1 = even/odd, #2 = heading/footing, #3 = top/bottom. \def\headingmarks#1#2#3 {% \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname \global\expandafter\let\csname get#1#2marks\endcsname \temp } \everyheadingmarks bottom \everyfootingmarks bottom % @headings double turns headings on for double-sided printing. % @headings single turns headings on for single-sided printing. % @headings off turns them off. % @headings on same as @headings double, retained for compatibility. % @headings after turns on double-sided headings after this page. % @headings doubleafter turns on double-sided headings after this page. % @headings singleafter turns on single-sided headings after this page. % By default, they are off at the start of a document, % and turned `on' after @end titlepage. \def\headings #1 {\csname HEADINGS#1\endcsname} \def\HEADINGSoff{% \global\evenheadline={\hfil} \global\evenfootline={\hfil} \global\oddheadline={\hfil} \global\oddfootline={\hfil}} \HEADINGSoff % When we turn headings on, set the page number to 1. % For double-sided printing, put current file name in lower left corner, % chapter name on inside top of right hand pages, document % title on inside top of left hand pages, and page numbers on outside top % edge of all pages. \def\HEADINGSdouble{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \let\contentsalignmacro = \chappager % For single-sided printing, chapter title goes across top left of page, % page number on top right. \def\HEADINGSsingle{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } \def\HEADINGSon{\HEADINGSdouble} \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} \let\HEADINGSdoubleafter=\HEADINGSafter \def\HEADINGSdoublex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} \def\HEADINGSsinglex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } % Subroutines used in generating headings % This produces Day Month Year style of output. % Only define if not already defined, in case a txi-??.tex file has set % up a different format (e.g., txi-cs.tex does this). \ifx\today\undefined \def\today{% \number\day\space \ifcase\month \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec \fi \space\number\year} \fi % @settitle line... specifies the title of the document, for headings. % It generates no output of its own. \def\thistitle{\putwordNoTitle} \def\settitle{\parsearg{\gdef\thistitle}} \message{tables,} % Tables -- @table, @ftable, @vtable, @item(x). % default indentation of table text \newdimen\tableindent \tableindent=.8in % default indentation of @itemize and @enumerate text \newdimen\itemindent \itemindent=.3in % margin between end of table item and start of table text. \newdimen\itemmargin \itemmargin=.1in % used internally for \itemindent minus \itemmargin \newdimen\itemmax % Note @table, @ftable, and @vtable define @item, @itemx, etc., with % these defs. % They also define \itemindex % to index the item name in whatever manner is desired (perhaps none). \newif\ifitemxneedsnegativevskip \def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} \def\internalBitem{\smallbreak \parsearg\itemzzz} \def\internalBitemx{\itemxpar \parsearg\itemzzz} \def\itemzzz #1{\begingroup % \advance\hsize by -\rightskip \advance\hsize by -\tableindent \setbox0=\hbox{\itemindicate{#1}}% \itemindex{#1}% \nobreak % This prevents a break before @itemx. % % If the item text does not fit in the space we have, put it on a line % by itself, and do not allow a page break either before or after that % line. We do not start a paragraph here because then if the next % command is, e.g., @kindex, the whatsit would get put into the % horizontal list on a line by itself, resulting in extra blank space. \ifdim \wd0>\itemmax % % Make this a paragraph so we get the \parskip glue and wrapping, % but leave it ragged-right. \begingroup \advance\leftskip by-\tableindent \advance\hsize by\tableindent \advance\rightskip by0pt plus1fil \leavevmode\unhbox0\par \endgroup % % We're going to be starting a paragraph, but we don't want the % \parskip glue -- logically it's part of the @item we just started. \nobreak \vskip-\parskip % % Stop a page break at the \parskip glue coming up. However, if % what follows is an environment such as @example, there will be no % \parskip glue; then the negative vskip we just inserted would % cause the example and the item to crash together. So we use this % bizarre value of 10001 as a signal to \aboveenvbreak to insert % \parskip glue after all. Section titles are handled this way also. % \penalty 10001 \endgroup \itemxneedsnegativevskipfalse \else % The item text fits into the space. Start a paragraph, so that the % following text (if any) will end up on the same line. \noindent % Do this with kerns and \unhbox so that if there is a footnote in % the item text, it can migrate to the main vertical list and % eventually be printed. \nobreak\kern-\tableindent \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 \unhbox0 \nobreak\kern\dimen0 \endgroup \itemxneedsnegativevskiptrue \fi } \def\item{\errmessage{@item while not in a list environment}} \def\itemx{\errmessage{@itemx while not in a list environment}} % @table, @ftable, @vtable. \envdef\table{% \let\itemindex\gobble \tablecheck{table}% } \envdef\ftable{% \def\itemindex ##1{\doind {fn}{\code{##1}}}% \tablecheck{ftable}% } \envdef\vtable{% \def\itemindex ##1{\doind {vr}{\code{##1}}}% \tablecheck{vtable}% } \def\tablecheck#1{% \ifnum \the\catcode`\^^M=\active \endgroup \errmessage{This command won't work in this context; perhaps the problem is that we are \inenvironment\thisenv}% \def\next{\doignore{#1}}% \else \let\next\tablex \fi \next } \def\tablex#1{% \def\itemindicate{#1}% \parsearg\tabley } \def\tabley#1{% {% \makevalueexpandable \edef\temp{\noexpand\tablez #1\space\space\space}% \expandafter }\temp \endtablez } \def\tablez #1 #2 #3 #4\endtablez{% \aboveenvbreak \ifnum 0#1>0 \advance \leftskip by #1\mil \fi \ifnum 0#2>0 \tableindent=#2\mil \fi \ifnum 0#3>0 \advance \rightskip by #3\mil \fi \itemmax=\tableindent \advance \itemmax by -\itemmargin \advance \leftskip by \tableindent \exdentamount=\tableindent \parindent = 0pt \parskip = \smallskipamount \ifdim \parskip=0pt \parskip=2pt \fi \let\item = \internalBitem \let\itemx = \internalBitemx } \def\Etable{\endgraf\afterenvbreak} \let\Eftable\Etable \let\Evtable\Etable \let\Eitemize\Etable \let\Eenumerate\Etable % This is the counter used by @enumerate, which is really @itemize \newcount \itemno \envdef\itemize{\parsearg\doitemize} \def\doitemize#1{% \aboveenvbreak \itemmax=\itemindent \advance\itemmax by -\itemmargin \advance\leftskip by \itemindent \exdentamount=\itemindent \parindent=0pt \parskip=\smallskipamount \ifdim\parskip=0pt \parskip=2pt \fi % % Try typesetting the item mark that if the document erroneously says % something like @itemize @samp (intending @table), there's an error % right away at the @itemize. It's not the best error message in the % world, but it's better than leaving it to the @item. This means if % the user wants an empty mark, they have to say @w{} not just @w. \def\itemcontents{#1}% \setbox0 = \hbox{\itemcontents}% % % @itemize with no arg is equivalent to @itemize @bullet. \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi % \let\item=\itemizeitem } % Definition of @item while inside @itemize and @enumerate. % \def\itemizeitem{% \advance\itemno by 1 % for enumerations {\let\par=\endgraf \smallbreak}% reasonable place to break {% % If the document has an @itemize directly after a section title, a % \nobreak will be last on the list, and \sectionheading will have % done a \vskip-\parskip. In that case, we don't want to zero % parskip, or the item text will crash with the heading. On the % other hand, when there is normal text preceding the item (as there % usually is), we do want to zero parskip, or there would be too much % space. In that case, we won't have a \nobreak before. At least % that's the theory. \ifnum\lastpenalty<10000 \parskip=0in \fi \noindent \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% % \vadjust{\penalty 1200}}% not good to break after first line of item. \flushcr } % \splitoff TOKENS\endmark defines \first to be the first token in % TOKENS, and \rest to be the remainder. % \def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% % Allow an optional argument of an uppercase letter, lowercase letter, % or number, to specify the first label in the enumerated list. No % argument is the same as `1'. % \envparseargdef\enumerate{\enumeratey #1 \endenumeratey} \def\enumeratey #1 #2\endenumeratey{% % If we were given no argument, pretend we were given `1'. \def\thearg{#1}% \ifx\thearg\empty \def\thearg{1}\fi % % Detect if the argument is a single token. If so, it might be a % letter. Otherwise, the only valid thing it can be is a number. % (We will always have one token, because of the test we just made. % This is a good thing, since \splitoff doesn't work given nothing at % all -- the first parameter is undelimited.) \expandafter\splitoff\thearg\endmark \ifx\rest\empty % Only one token in the argument. It could still be anything. % A ``lowercase letter'' is one whose \lccode is nonzero. % An ``uppercase letter'' is one whose \lccode is both nonzero, and % not equal to itself. % Otherwise, we assume it's a number. % % We need the \relax at the end of the \ifnum lines to stop TeX from % continuing to look for a . % \ifnum\lccode\expandafter`\thearg=0\relax \numericenumerate % a number (we hope) \else % It's a letter. \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax \lowercaseenumerate % lowercase letter \else \uppercaseenumerate % uppercase letter \fi \fi \else % Multiple tokens in the argument. We hope it's a number. \numericenumerate \fi } % An @enumerate whose labels are integers. The starting integer is % given in \thearg. % \def\numericenumerate{% \itemno = \thearg \startenumeration{\the\itemno}% } % The starting (lowercase) letter is in \thearg. \def\lowercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more lowercase letters in @enumerate; get a bigger alphabet}% \fi \char\lccode\itemno }% } % The starting (uppercase) letter is in \thearg. \def\uppercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more uppercase letters in @enumerate; get a bigger alphabet} \fi \char\uccode\itemno }% } % Call \doitemize, adding a period to the first argument and supplying the % common last two arguments. Also subtract one from the initial value in % \itemno, since @item increments \itemno. % \def\startenumeration#1{% \advance\itemno by -1 \doitemize{#1.}\flushcr } % @alphaenumerate and @capsenumerate are abbreviations for giving an arg % to @enumerate. % \def\alphaenumerate{\enumerate{a}} \def\capsenumerate{\enumerate{A}} \def\Ealphaenumerate{\Eenumerate} \def\Ecapsenumerate{\Eenumerate} % @multitable macros % Amy Hendrickson, 8/18/94, 3/6/96 % % @multitable ... @end multitable will make as many columns as desired. % Contents of each column will wrap at width given in preamble. Width % can be specified either with sample text given in a template line, % or in percent of \hsize, the current width of text on page. % Table can continue over pages but will only break between lines. % To make preamble: % % Either define widths of columns in terms of percent of \hsize: % @multitable @columnfractions .25 .3 .45 % @item ... % % Numbers following @columnfractions are the percent of the total % current hsize to be used for each column. You may use as many % columns as desired. % Or use a template: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item ... % using the widest term desired in each column. % Each new table line starts with @item, each subsequent new column % starts with @tab. Empty columns may be produced by supplying @tab's % with nothing between them for as many times as empty columns are needed, % ie, @tab@tab@tab will produce two empty columns. % @item, @tab do not need to be on their own lines, but it will not hurt % if they are. % Sample multitable: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item first col stuff @tab second col stuff @tab third col % @item % first col stuff % @tab % second col stuff % @tab % third col % @item first col stuff @tab second col stuff % @tab Many paragraphs of text may be used in any column. % % They will wrap at the width determined by the template. % @item@tab@tab This will be in third column. % @end multitable % Default dimensions may be reset by user. % @multitableparskip is vertical space between paragraphs in table. % @multitableparindent is paragraph indent in table. % @multitablecolmargin is horizontal space to be left between columns. % @multitablelinespace is space to leave between table items, baseline % to baseline. % 0pt means it depends on current normal line spacing. % \newskip\multitableparskip \newskip\multitableparindent \newdimen\multitablecolspace \newskip\multitablelinespace \multitableparskip=0pt \multitableparindent=6pt \multitablecolspace=12pt \multitablelinespace=0pt % Macros used to set up halign preamble: % \let\endsetuptable\relax \def\xendsetuptable{\endsetuptable} \let\columnfractions\relax \def\xcolumnfractions{\columnfractions} \newif\ifsetpercent % #1 is the @columnfraction, usually a decimal number like .5, but might % be just 1. We just use it, whatever it is. % \def\pickupwholefraction#1 {% \global\advance\colcount by 1 \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% \setuptable } \newcount\colcount \def\setuptable#1{% \def\firstarg{#1}% \ifx\firstarg\xendsetuptable \let\go = \relax \else \ifx\firstarg\xcolumnfractions \global\setpercenttrue \else \ifsetpercent \let\go\pickupwholefraction \else \global\advance\colcount by 1 \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a % separator; typically that is always in the input, anyway. \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% \fi \fi \ifx\go\pickupwholefraction % Put the argument back for the \pickupwholefraction call, so % we'll always have a period there to be parsed. \def\go{\pickupwholefraction#1}% \else \let\go = \setuptable \fi% \fi \go } % multitable-only commands. % % @headitem starts a heading row, which we typeset in bold. % Assignments have to be global since we are inside the implicit group % of an alignment entry. \everycr resets \everytab so we don't have to % undo it ourselves. \def\headitemfont{\b}% for people to use in the template row; not changeable \def\headitem{% \checkenv\multitable \crcr \global\everytab={\bf}% can't use \headitemfont since the parsing differs \the\everytab % for the first item }% % % A \tab used to include \hskip1sp. But then the space in a template % line is not enough. That is bad. So let's go back to just `&' until % we again encounter the problem the 1sp was intended to solve. % --karl, nathan@acm.org, 20apr99. \def\tab{\checkenv\multitable &\the\everytab}% % @multitable ... @end multitable definitions: % \newtoks\everytab % insert after every tab. % \envdef\multitable{% \vskip\parskip \startsavinginserts % % @item within a multitable starts a normal row. % We use \def instead of \let so that if one of the multitable entries % contains an @itemize, we don't choke on the \item (seen as \crcr aka % \endtemplate) expanding \doitemize. \def\item{\crcr}% % \tolerance=9500 \hbadness=9500 \setmultitablespacing \parskip=\multitableparskip \parindent=\multitableparindent \overfullrule=0pt \global\colcount=0 % \everycr = {% \noalign{% \global\everytab={}% \global\colcount=0 % Reset the column counter. % Check for saved footnotes, etc. \checkinserts % Keeps underfull box messages off when table breaks over pages. %\filbreak % Maybe so, but it also creates really weird page breaks when the % table breaks over pages. Wouldn't \vfil be better? Wait until the % problem manifests itself, so it can be fixed for real --karl. }% }% % \parsearg\domultitable } \def\domultitable#1{% % To parse everything between @multitable and @item: \setuptable#1 \endsetuptable % % This preamble sets up a generic column definition, which will % be used as many times as user calls for columns. % \vtop will set a single line and will also let text wrap and % continue for many paragraphs if desired. \halign\bgroup &% \global\advance\colcount by 1 \multistrut \vtop{% % Use the current \colcount to find the correct column width: \hsize=\expandafter\csname col\the\colcount\endcsname % % In order to keep entries from bumping into each other % we will add a \leftskip of \multitablecolspace to all columns after % the first one. % % If a template has been used, we will add \multitablecolspace % to the width of each template entry. % % If the user has set preamble in terms of percent of \hsize we will % use that dimension as the width of the column, and the \leftskip % will keep entries from bumping into each other. Table will start at % left margin and final column will justify at right margin. % % Make sure we don't inherit \rightskip from the outer environment. \rightskip=0pt \ifnum\colcount=1 % The first column will be indented with the surrounding text. \advance\hsize by\leftskip \else \ifsetpercent \else % If user has not set preamble in terms of percent of \hsize % we will advance \hsize by \multitablecolspace. \advance\hsize by \multitablecolspace \fi % In either case we will make \leftskip=\multitablecolspace: \leftskip=\multitablecolspace \fi % Ignoring space at the beginning and end avoids an occasional spurious % blank line, when TeX decides to break the line at the space before the % box from the multistrut, so the strut ends up on a line by itself. % For example: % @multitable @columnfractions .11 .89 % @item @code{#} % @tab Legal holiday which is valid in major parts of the whole country. % Is automatically provided with highlighting sequences respectively % marking characters. \noindent\ignorespaces##\unskip\multistrut }\cr } \def\Emultitable{% \crcr \egroup % end the \halign \global\setpercentfalse } \def\setmultitablespacing{% \def\multistrut{\strut}% just use the standard line spacing % % Compute \multitablelinespace (if not defined by user) for use in % \multitableparskip calculation. We used define \multistrut based on % this, but (ironically) that caused the spacing to be off. % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. \ifdim\multitablelinespace=0pt \setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip \global\advance\multitablelinespace by-\ht0 \fi %% Test to see if parskip is larger than space between lines of %% table. If not, do nothing. %% If so, set to same dimension as multitablelinespace. \ifdim\multitableparskip>\multitablelinespace \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller %% than skip between lines in the table. \fi% \ifdim\multitableparskip=0pt \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller %% than skip between lines in the table. \fi} \message{conditionals,} % @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, % @ifnotxml always succeed. They currently do nothing; we don't % attempt to check whether the conditionals are properly nested. But we % have to remember that they are conditionals, so that @end doesn't % attempt to close an environment group. % \def\makecond#1{% \expandafter\let\csname #1\endcsname = \relax \expandafter\let\csname iscond.#1\endcsname = 1 } \makecond{iftex} \makecond{ifnotdocbook} \makecond{ifnothtml} \makecond{ifnotinfo} \makecond{ifnotplaintext} \makecond{ifnotxml} % Ignore @ignore, @ifhtml, @ifinfo, and the like. % \def\direntry{\doignore{direntry}} \def\documentdescription{\doignore{documentdescription}} \def\docbook{\doignore{docbook}} \def\html{\doignore{html}} \def\ifdocbook{\doignore{ifdocbook}} \def\ifhtml{\doignore{ifhtml}} \def\ifinfo{\doignore{ifinfo}} \def\ifnottex{\doignore{ifnottex}} \def\ifplaintext{\doignore{ifplaintext}} \def\ifxml{\doignore{ifxml}} \def\ignore{\doignore{ignore}} \def\menu{\doignore{menu}} \def\xml{\doignore{xml}} % Ignore text until a line `@end #1', keeping track of nested conditionals. % % A count to remember the depth of nesting. \newcount\doignorecount \def\doignore#1{\begingroup % Scan in ``verbatim'' mode: \obeylines \catcode`\@ = \other \catcode`\{ = \other \catcode`\} = \other % % Make sure that spaces turn into tokens that match what \doignoretext wants. \spaceisspace % % Count number of #1's that we've seen. \doignorecount = 0 % % Swallow text until we reach the matching `@end #1'. \dodoignore{#1}% } { \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. \obeylines % % \gdef\dodoignore#1{% % #1 contains the command name as a string, e.g., `ifinfo'. % % Define a command to find the next `@end #1'. \long\def\doignoretext##1^^M@end #1{% \doignoretextyyy##1^^M@#1\_STOP_}% % % And this command to find another #1 command, at the beginning of a % line. (Otherwise, we would consider a line `@c @ifset', for % example, to count as an @ifset for nesting.) \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% % % And now expand that command. \doignoretext ^^M% }% } \def\doignoreyyy#1{% \def\temp{#1}% \ifx\temp\empty % Nothing found. \let\next\doignoretextzzz \else % Found a nested condition, ... \advance\doignorecount by 1 \let\next\doignoretextyyy % ..., look for another. % If we're here, #1 ends with ^^M\ifinfo (for example). \fi \next #1% the token \_STOP_ is present just after this macro. } % We have to swallow the remaining "\_STOP_". % \def\doignoretextzzz#1{% \ifnum\doignorecount = 0 % We have just found the outermost @end. \let\next\enddoignore \else % Still inside a nested condition. \advance\doignorecount by -1 \let\next\doignoretext % Look for the next @end. \fi \next } % Finish off ignored text. { \obeylines% % Ignore anything after the last `@end #1'; this matters in verbatim % environments, where otherwise the newline after an ignored conditional % would result in a blank line in the output. \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% } % @set VAR sets the variable VAR to an empty value. % @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. % % Since we want to separate VAR from REST-OF-LINE (which might be % empty), we can't just use \parsearg; we have to insert a space of our % own to delimit the rest of the line, and then take it out again if we % didn't need it. % We rely on the fact that \parsearg sets \catcode`\ =10. % \parseargdef\set{\setyyy#1 \endsetyyy} \def\setyyy#1 #2\endsetyyy{% {% \makevalueexpandable \def\temp{#2}% \edef\next{\gdef\makecsname{SET#1}}% \ifx\temp\empty \next{}% \else \setzzz#2\endsetzzz \fi }% } % Remove the trailing space \setxxx inserted. \def\setzzz#1 \endsetzzz{\next{#1}} % @clear VAR clears (i.e., unsets) the variable VAR. % \parseargdef\clear{% {% \makevalueexpandable \global\expandafter\let\csname SET#1\endcsname=\relax }% } % @value{foo} gets the text saved in variable foo. \def\value{\begingroup\makevalueexpandable\valuexxx} \def\valuexxx#1{\expandablevalue{#1}\endgroup} { \catcode`\- = \active \catcode`\_ = \active % \gdef\makevalueexpandable{% \let\value = \expandablevalue % We don't want these characters active, ... \catcode`\-=\other \catcode`\_=\other % ..., but we might end up with active ones in the argument if % we're called from @code, as @code{@value{foo-bar_}}, though. % So \let them to their normal equivalents. \let-\realdash \let_\normalunderscore } } % We have this subroutine so that we can handle at least some @value's % properly in indexes (we call \makevalueexpandable in \indexdummies). % The command has to be fully expandable (if the variable is set), since % the result winds up in the index file. This means that if the % variable's value contains other Texinfo commands, it's almost certain % it will fail (although perhaps we could fix that with sufficient work % to do a one-level expansion on the result, instead of complete). % \def\expandablevalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax {[No value for ``#1'']}% \message{Variable `#1', used in @value, is not set.}% \else \csname SET#1\endcsname \fi } % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. % % To get special treatment of `@end ifset,' call \makeond and the redefine. % \makecond{ifset} \def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} \def\doifset#1#2{% {% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname SET#2\endcsname\relax #1% If not set, redefine \next. \fi \expandafter }\next } \def\ifsetfail{\doignore{ifset}} % @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been % defined with @set, or has been undefined with @clear. % % The `\else' inside the `\doifset' parameter is a trick to reuse the % above code: if the variable is not set, do nothing, if it is set, % then redefine \next to \ifclearfail. % \makecond{ifclear} \def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} \def\ifclearfail{\doignore{ifclear}} % @dircategory CATEGORY -- specify a category of the dir file % which this file should belong to. Ignore this in TeX. \let\dircategory=\comment % @defininfoenclose. \let\definfoenclose=\comment \message{indexing,} % Index generation facilities % Define \newwrite to be identical to plain tex's \newwrite % except not \outer, so it can be used within macros and \if's. \edef\newwrite{\makecsname{ptexnewwrite}} % \newindex {foo} defines an index named foo. % It automatically defines \fooindex such that % \fooindex ...rest of line... puts an entry in the index foo. % It also defines \fooindfile to be the number of the output channel for % the file that accumulates this index. The file's extension is foo. % The name of an index should be no more than 2 characters long % for the sake of vms. % \def\newindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 % Open the file \fi \expandafter\xdef\csname#1index\endcsname{% % Define @#1index \noexpand\doindex{#1}} } % @defindex foo == \newindex{foo} % \def\defindex{\parsearg\newindex} % Define @defcodeindex, like @defindex except put all entries in @code. % \def\defcodeindex{\parsearg\newcodeindex} % \def\newcodeindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 \fi \expandafter\xdef\csname#1index\endcsname{% \noexpand\docodeindex{#1}}% } % @synindex foo bar makes index foo feed into index bar. % Do this instead of @defindex foo if you don't want it as a separate index. % % @syncodeindex foo bar similar, but put all entries made for index foo % inside @code. % \def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} \def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} % #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), % #3 the target index (bar). \def\dosynindex#1#2#3{% % Only do \closeout if we haven't already done it, else we'll end up % closing the target index. \expandafter \ifx\csname donesynindex#2\endcsname \relax % The \closeout helps reduce unnecessary open files; the limit on the % Acorn RISC OS is a mere 16 files. \expandafter\closeout\csname#2indfile\endcsname \expandafter\let\csname donesynindex#2\endcsname = 1 \fi % redefine \fooindfile: \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname \expandafter\let\csname#2indfile\endcsname=\temp % redefine \fooindex: \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% } % Define \doindex, the driver for all \fooindex macros. % Argument #1 is generated by the calling \fooindex macro, % and it is "foo", the name of the index. % \doindex just uses \parsearg; it calls \doind for the actual work. % This is because \doind is more useful to call from other macros. % There is also \dosubind {index}{topic}{subtopic} % which makes an entry in a two-level index such as the operation index. \def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} \def\singleindexer #1{\doind{\indexname}{#1}} % like the previous two, but they put @code around the argument. \def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} % Take care of Texinfo commands that can appear in an index entry. % Since there are some commands we want to expand, and others we don't, % we have to laboriously prevent expansion for those that we don't. % \def\indexdummies{% \escapechar = `\\ % use backslash in output files. \def\@{@}% change to @@ when we switch to @ as escape char in index files. \def\ {\realbackslash\space }% % % Need these in case \tex is in effect and \{ is a \delimiter again. % But can't use \lbracecmd and \rbracecmd because texindex assumes % braces and backslashes are used only as delimiters. \let\{ = \mylbrace \let\} = \myrbrace % % I don't entirely understand this, but when an index entry is % generated from a macro call, the \endinput which \scanmacro inserts % causes processing to be prematurely terminated. This is, % apparently, because \indexsorttmp is fully expanded, and \endinput % is an expandable command. The redefinition below makes \endinput % disappear altogether for that purpose -- although logging shows that % processing continues to some further point. On the other hand, it % seems \endinput does not hurt in the printed index arg, since that % is still getting written without apparent harm. % % Sample source (mac-idx3.tex, reported by Graham Percival to % help-texinfo, 22may06): % @macro funindex {WORD} % @findex xyz % @end macro % ... % @funindex commtest % % The above is not enough to reproduce the bug, but it gives the flavor. % % Sample whatsit resulting: % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}} % % So: \let\endinput = \empty % % Do the redefinitions. \commondummies } % For the aux and toc files, @ is the escape character. So we want to % redefine everything using @ as the escape character (instead of % \realbackslash, still used for index files). When everything uses @, % this will be simpler. % \def\atdummies{% \def\@{@@}% \def\ {@ }% \let\{ = \lbraceatcmd \let\} = \rbraceatcmd % % Do the redefinitions. \commondummies \otherbackslash } % Called from \indexdummies and \atdummies. % \def\commondummies{% % % \definedummyword defines \#1 as \string\#1\space, thus effectively % preventing its expansion. This is used only for control% words, % not control letters, because the \space would be incorrect for % control characters, but is needed to separate the control word % from whatever follows. % % For control letters, we have \definedummyletter, which omits the % space. % % These can be used both for control words that take an argument and % those that do not. If it is followed by {arg} in the input, then % that will dutifully get written to the index (or wherever). % \def\definedummyword ##1{\def##1{\string##1\space}}% \def\definedummyletter##1{\def##1{\string##1}}% \let\definedummyaccent\definedummyletter % \commondummiesnofonts % \definedummyletter\_% % % Non-English letters. \definedummyword\AA \definedummyword\AE \definedummyword\DH \definedummyword\L \definedummyword\O \definedummyword\OE \definedummyword\TH \definedummyword\aa \definedummyword\ae \definedummyword\dh \definedummyword\exclamdown \definedummyword\l \definedummyword\o \definedummyword\oe \definedummyword\ordf \definedummyword\ordm \definedummyword\questiondown \definedummyword\ss \definedummyword\th % % Although these internal commands shouldn't show up, sometimes they do. \definedummyword\bf \definedummyword\gtr \definedummyword\hat \definedummyword\less \definedummyword\sf \definedummyword\sl \definedummyword\tclose \definedummyword\tt % \definedummyword\LaTeX \definedummyword\TeX % % Assorted special characters. \definedummyword\bullet \definedummyword\comma \definedummyword\copyright \definedummyword\registeredsymbol \definedummyword\dots \definedummyword\enddots \definedummyword\equiv \definedummyword\error \definedummyword\euro \definedummyword\guillemetleft \definedummyword\guillemetright \definedummyword\guilsinglleft \definedummyword\guilsinglright \definedummyword\expansion \definedummyword\minus \definedummyword\ogonek \definedummyword\pounds \definedummyword\point \definedummyword\print \definedummyword\quotedblbase \definedummyword\quotedblleft \definedummyword\quotedblright \definedummyword\quoteleft \definedummyword\quoteright \definedummyword\quotesinglbase \definedummyword\result \definedummyword\textdegree % % We want to disable all macros so that they are not expanded by \write. \macrolist % \normalturnoffactive % % Handle some cases of @value -- where it does not contain any % (non-fully-expandable) commands. \makevalueexpandable } % \commondummiesnofonts: common to \commondummies and \indexnofonts. % \def\commondummiesnofonts{% % Control letters and accents. \definedummyletter\!% \definedummyaccent\"% \definedummyaccent\'% \definedummyletter\*% \definedummyaccent\,% \definedummyletter\.% \definedummyletter\/% \definedummyletter\:% \definedummyaccent\=% \definedummyletter\?% \definedummyaccent\^% \definedummyaccent\`% \definedummyaccent\~% \definedummyword\u \definedummyword\v \definedummyword\H \definedummyword\dotaccent \definedummyword\ogonek \definedummyword\ringaccent \definedummyword\tieaccent \definedummyword\ubaraccent \definedummyword\udotaccent \definedummyword\dotless % % Texinfo font commands. \definedummyword\b \definedummyword\i \definedummyword\r \definedummyword\sc \definedummyword\t % % Commands that take arguments. \definedummyword\acronym \definedummyword\cite \definedummyword\code \definedummyword\command \definedummyword\dfn \definedummyword\emph \definedummyword\env \definedummyword\file \definedummyword\kbd \definedummyword\key \definedummyword\math \definedummyword\option \definedummyword\pxref \definedummyword\ref \definedummyword\samp \definedummyword\strong \definedummyword\tie \definedummyword\uref \definedummyword\url \definedummyword\var \definedummyword\verb \definedummyword\w \definedummyword\xref } % \indexnofonts is used when outputting the strings to sort the index % by, and when constructing control sequence names. It eliminates all % control sequences and just writes whatever the best ASCII sort string % would be for a given command (usually its argument). % \def\indexnofonts{% % Accent commands should become @asis. \def\definedummyaccent##1{\let##1\asis}% % We can just ignore other control letters. \def\definedummyletter##1{\let##1\empty}% % Hopefully, all control words can become @asis. \let\definedummyword\definedummyaccent % \commondummiesnofonts % % Don't no-op \tt, since it isn't a user-level command % and is used in the definitions of the active chars like <, >, |, etc. % Likewise with the other plain tex font commands. %\let\tt=\asis % \def\ { }% \def\@{@}% % how to handle braces? \def\_{\normalunderscore}% % % Non-English letters. \def\AA{AA}% \def\AE{AE}% \def\DH{DZZ}% \def\L{L}% \def\OE{OE}% \def\O{O}% \def\TH{ZZZ}% \def\aa{aa}% \def\ae{ae}% \def\dh{dzz}% \def\exclamdown{!}% \def\l{l}% \def\oe{oe}% \def\ordf{a}% \def\ordm{o}% \def\o{o}% \def\questiondown{?}% \def\ss{ss}% \def\th{zzz}% % \def\LaTeX{LaTeX}% \def\TeX{TeX}% % % Assorted special characters. % (The following {} will end up in the sort string, but that's ok.) \def\bullet{bullet}% \def\comma{,}% \def\copyright{copyright}% \def\dots{...}% \def\enddots{...}% \def\equiv{==}% \def\error{error}% \def\euro{euro}% \def\expansion{==>}% \def\guillemetleft{<<}% \def\guillemetright{>>}% \def\guilsinglleft{<}% \def\guilsinglright{>}% \def\minus{-}% \def\point{.}% \def\pounds{pounds}% \def\print{-|}% \def\quotedblbase{"}% \def\quotedblleft{"}% \def\quotedblright{"}% \def\quoteleft{`}% \def\quoteright{'}% \def\quotesinglbase{,}% \def\registeredsymbol{R}% \def\result{=>}% \def\textdegree{o}% % % We need to get rid of all macros, leaving only the arguments (if present). % Of course this is not nearly correct, but it is the best we can do for now. % makeinfo does not expand macros in the argument to @deffn, which ends up % writing an index entry, and texindex isn't prepared for an index sort entry % that starts with \. % % Since macro invocations are followed by braces, we can just redefine them % to take a single TeX argument. The case of a macro invocation that % goes to end-of-line is not handled. % \macrolist } \let\indexbackslash=0 %overridden during \printindex. \let\SETmarginindex=\relax % put index entries in margin (undocumented)? % Most index entries go through here, but \dosubind is the general case. % #1 is the index name, #2 is the entry text. \def\doind#1#2{\dosubind{#1}{#2}{}} % Workhorse for all \fooindexes. % #1 is name of index, #2 is stuff to put there, #3 is subentry -- % empty if called from \doind, as we usually are (the main exception % is with most defuns, which call us directly). % \def\dosubind#1#2#3{% \iflinks {% % Store the main index entry text (including the third arg). \toks0 = {#2}% % If third arg is present, precede it with a space. \def\thirdarg{#3}% \ifx\thirdarg\empty \else \toks0 = \expandafter{\the\toks0 \space #3}% \fi % \edef\writeto{\csname#1indfile\endcsname}% % \safewhatsit\dosubindwrite }% \fi } % Write the entry in \toks0 to the index file: % \def\dosubindwrite{% % Put the index entry in the margin if desired. \ifx\SETmarginindex\relax\else \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% \fi % % Remember, we are within a group. \indexdummies % Must do this here, since \bf, etc expand at this stage \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now % so it will be output as is; and it will print as backslash. % % Process the index entry with all font commands turned off, to % get the string to sort by. {\indexnofonts \edef\temp{\the\toks0}% need full expansion \xdef\indexsorttmp{\temp}% }% % % Set up the complete index entry, with both the sort key and % the original text, including any font commands. We write % three arguments to \entry to the .?? file (four in the % subentry case), texindex reduces to two when writing the .??s % sorted result. \edef\temp{% \write\writeto{% \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% }% \temp } % Take care of unwanted page breaks/skips around a whatsit: % % If a skip is the last thing on the list now, preserve it % by backing up by \lastskip, doing the \write, then inserting % the skip again. Otherwise, the whatsit generated by the % \write or \pdfdest will make \lastskip zero. The result is that % sequences like this: % @end defun % @tindex whatever % @defun ... % will have extra space inserted, because the \medbreak in the % start of the @defun won't see the skip inserted by the @end of % the previous defun. % % But don't do any of this if we're not in vertical mode. We % don't want to do a \vskip and prematurely end a paragraph. % % Avoid page breaks due to these extra skips, too. % % But wait, there is a catch there: % We'll have to check whether \lastskip is zero skip. \ifdim is not % sufficient for this purpose, as it ignores stretch and shrink parts % of the skip. The only way seems to be to check the textual % representation of the skip. % % The following is almost like \def\zeroskipmacro{0.0pt} except that % the ``p'' and ``t'' characters have catcode \other, not 11 (letter). % \edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} % \newskip\whatsitskip \newcount\whatsitpenalty % % ..., ready, GO: % \def\safewhatsit#1{% \ifhmode #1% \else % \lastskip and \lastpenalty cannot both be nonzero simultaneously. \whatsitskip = \lastskip \edef\lastskipmacro{\the\lastskip}% \whatsitpenalty = \lastpenalty % % If \lastskip is nonzero, that means the last item was a % skip. And since a skip is discardable, that means this % -\whatsitskip glue we're inserting is preceded by a % non-discardable item, therefore it is not a potential % breakpoint, therefore no \nobreak needed. \ifx\lastskipmacro\zeroskipmacro \else \vskip-\whatsitskip \fi % #1% % \ifx\lastskipmacro\zeroskipmacro % If \lastskip was zero, perhaps the last item was a penalty, and % perhaps it was >=10000, e.g., a \nobreak. In that case, we want % to re-insert the same penalty (values >10000 are used for various % signals); since we just inserted a non-discardable item, any % following glue (such as a \parskip) would be a breakpoint. For example: % % @deffn deffn-whatever % @vindex index-whatever % Description. % would allow a break between the index-whatever whatsit % and the "Description." paragraph. \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi \else % On the other hand, if we had a nonzero \lastskip, % this make-up glue would be preceded by a non-discardable item % (the whatsit from the \write), so we must insert a \nobreak. \nobreak\vskip\whatsitskip \fi \fi } % The index entry written in the file actually looks like % \entry {sortstring}{page}{topic} % or % \entry {sortstring}{page}{topic}{subtopic} % The texindex program reads in these files and writes files % containing these kinds of lines: % \initial {c} % before the first topic whose initial is c % \entry {topic}{pagelist} % for a topic that is used without subtopics % \primary {topic} % for the beginning of a topic that is used with subtopics % \secondary {subtopic}{pagelist} % for each subtopic. % Define the user-accessible indexing commands % @findex, @vindex, @kindex, @cindex. \def\findex {\fnindex} \def\kindex {\kyindex} \def\cindex {\cpindex} \def\vindex {\vrindex} \def\tindex {\tpindex} \def\pindex {\pgindex} \def\cindexsub {\begingroup\obeylines\cindexsub} {\obeylines % \gdef\cindexsub "#1" #2^^M{\endgroup % \dosubind{cp}{#2}{#1}}} % Define the macros used in formatting output of the sorted index material. % @printindex causes a particular index (the ??s file) to get printed. % It does not print any chapter heading (usually an @unnumbered). % \parseargdef\printindex{\begingroup \dobreak \chapheadingskip{10000}% % \smallfonts \rm \tolerance = 9500 \plainfrenchspacing \everypar = {}% don't want the \kern\-parindent from indentation suppression. % % See if the index file exists and is nonempty. % Change catcode of @ here so that if the index file contains % \initial {@} % as its first line, TeX doesn't complain about mismatched braces % (because it thinks @} is a control sequence). \catcode`\@ = 11 \openin 1 \jobname.#1s \ifeof 1 % \enddoublecolumns gets confused if there is no text in the index, % and it loses the chapter title and the aux file entries for the % index. The easiest way to prevent this problem is to make sure % there is some text. \putwordIndexNonexistent \else % % If the index file exists but is empty, then \openin leaves \ifeof % false. We have to make TeX try to read something from the file, so % it can discover if there is anything in it. \read 1 to \temp \ifeof 1 \putwordIndexIsEmpty \else % Index files are almost Texinfo source, but we use \ as the escape % character. It would be better to use @, but that's too big a change % to make right now. \def\indexbackslash{\backslashcurfont}% \catcode`\\ = 0 \escapechar = `\\ \begindoublecolumns \input \jobname.#1s \enddoublecolumns \fi \fi \closein 1 \endgroup} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. \def\initial#1{{% % Some minor font changes for the special characters. \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt % % Remove any glue we may have, we'll be inserting our own. \removelastskip % % We like breaks before the index initials, so insert a bonus. \nobreak \vskip 0pt plus 3\baselineskip \penalty 0 \vskip 0pt plus -3\baselineskip % % Typeset the initial. Making this add up to a whole number of % baselineskips increases the chance of the dots lining up from column % to column. It still won't often be perfect, because of the stretch % we need before each entry, but it's better. % % No shrink because it confuses \balancecolumns. \vskip 1.67\baselineskip plus .5\baselineskip \leftline{\secbf #1}% % Do our best not to break after the initial. \nobreak \vskip .33\baselineskip plus .1\baselineskip }} % \entry typesets a paragraph consisting of the text (#1), dot leaders, and % then page number (#2) flushed to the right margin. It is used for index % and table of contents entries. The paragraph is indented by \leftskip. % % A straightforward implementation would start like this: % \def\entry#1#2{... % But this freezes the catcodes in the argument, and can cause problems to % @code, which sets - active. This problem was fixed by a kludge--- % ``-'' was active throughout whole index, but this isn't really right. % % The right solution is to prevent \entry from swallowing the whole text. % --kasal, 21nov03 \def\entry{% \begingroup % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par % % Do not fill out the last line with white space. \parfillskip = 0in % % No extra space above this paragraph. \parskip = 0in % % Do not prefer a separate line ending with a hyphen to fewer lines. \finalhyphendemerits = 0 % % \hangindent is only relevant when the entry text and page number % don't both fit on one line. In that case, bob suggests starting the % dots pretty far over on the line. Unfortunately, a large % indentation looks wrong when the entry text itself is broken across % lines. So we use a small indentation and put up with long leaders. % % \hangafter is reset to 1 (which is the value we want) at the start % of each paragraph, so we need not do anything with that. \hangindent = 2em % % When the entry text needs to be broken, just fill out the first line % with blank space. \rightskip = 0pt plus1fil % % A bit of stretch before each entry for the benefit of balancing % columns. \vskip 0pt plus1pt % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = } \def\doentry{% \bgroup % Instead of the swallowed brace. \noindent \aftergroup\finishentry % And now comes the text of the entry. } \def\finishentry#1{% % #1 is the page number. % % The following is kludged to not output a line of dots in the index if % there are no page numbers. The next person who breaks this will be % cursed by a Unix daemon. \setbox\boxA = \hbox{#1}% \ifdim\wd\boxA = 0pt \ % \else % % If we must, put the page number on a line of its own, and fill out % this line with blank space. (The \hfil is overwhelmed with the % fill leaders glue in \indexdotfill if the page number does fit.) \hfil\penalty50 \null\nobreak\indexdotfill % Have leaders before the page number. % % The `\ ' here is removed by the implicit \unskip that TeX does as % part of (the primitive) \par. Without it, a spurious underfull % \hbox ensues. \ifpdf \pdfgettoks#1.% \ \the\toksA \else \ #1% \fi \fi \par \endgroup } % Like plain.tex's \dotfill, except uses up at least 1 em. \def\indexdotfill{\cleaders \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill} \def\primary #1{\line{#1\hfil}} \newskip\secondaryindent \secondaryindent=0.5cm \def\secondary#1#2{{% \parfillskip=0in \parskip=0in \hangindent=1in \hangafter=1 \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill \ifpdf \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \else #2 \fi \par }} % Define two-column mode, which we use to typeset indexes. % Adapted from the TeXbook, page 416, which is to say, % the manmac.tex format used to print the TeXbook itself. \catcode`\@=11 \newbox\partialpage \newdimen\doublecolumnhsize \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns % Grab any single-column material above us. \output = {% % % Here is a possibility not foreseen in manmac: if we accumulate a % whole lot of material, we might end up calling this \output % routine twice in a row (see the doublecol-lose test, which is % essentially a couple of indexes with @setchapternewpage off). In % that case we just ship out what is in \partialpage with the normal % output routine. Generally, \partialpage will be empty when this % runs and this will be a no-op. See the indexspread.tex test case. \ifvoid\partialpage \else \onepageout{\pagecontents\partialpage}% \fi % \global\setbox\partialpage = \vbox{% % Unvbox the main output page. \unvbox\PAGE \kern-\topskip \kern\baselineskip }% }% \eject % run that output routine to set \partialpage % % Use the double-column output routine for subsequent pages. \output = {\doublecolumnout}% % % Change the page size parameters. We could do this once outside this % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 % format, but then we repeat the same computation. Repeating a couple % of assignments once per index is clearly meaningless for the % execution time, so we may as well do it in one place. % % First we halve the line length, less a little for the gutter between % the columns. We compute the gutter based on the line length, so it % changes automatically with the paper format. The magic constant % below is chosen so that the gutter has the same value (well, +-<1pt) % as it did when we hard-coded it. % % We put the result in a separate register, \doublecolumhsize, so we % can restore it in \pagesofar, after \hsize itself has (potentially) % been clobbered. % \doublecolumnhsize = \hsize \advance\doublecolumnhsize by -.04154\hsize \divide\doublecolumnhsize by 2 \hsize = \doublecolumnhsize % % Double the \vsize as well. (We don't need a separate register here, % since nobody clobbers \vsize.) \vsize = 2\vsize } % The double-column output routine for all double-column pages except % the last. % \def\doublecolumnout{% \splittopskip=\topskip \splitmaxdepth=\maxdepth % Get the available space for the double columns -- the normal % (undoubled) page height minus any material left over from the % previous page. \dimen@ = \vsize \divide\dimen@ by 2 \advance\dimen@ by -\ht\partialpage % % box0 will be the left-hand column, box2 the right. \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty } % % Re-output the contents of the output page -- any previous material, % followed by the two boxes we just split, in box0 and box2. \def\pagesofar{% \unvbox\partialpage % \hsize = \doublecolumnhsize \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% } % % All done with double columns. \def\enddoublecolumns{% % The following penalty ensures that the page builder is exercised % _before_ we change the output routine. This is necessary in the % following situation: % % The last section of the index consists only of a single entry. % Before this section, \pagetotal is less than \pagegoal, so no % break occurs before the last section starts. However, the last % section, consisting of \initial and the single \entry, does not % fit on the page and has to be broken off. Without the following % penalty the page builder will not be exercised until \eject % below, and by that time we'll already have changed the output % routine to the \balancecolumns version, so the next-to-last % double-column page will be processed with \balancecolumns, which % is wrong: The two columns will go to the main vertical list, with % the broken-off section in the recent contributions. As soon as % the output routine finishes, TeX starts reconsidering the page % break. The two columns and the broken-off section both fit on the % page, because the two columns now take up only half of the page % goal. When TeX sees \eject from below which follows the final % section, it invokes the new output routine that we've set after % \balancecolumns below; \onepageout will try to fit the two columns % and the final section into the vbox of \pageheight (see % \pagebody), causing an overfull box. % % Note that glue won't work here, because glue does not exercise the % page builder, unlike penalties (see The TeXbook, pp. 280-281). \penalty0 % \output = {% % Split the last of the double-column material. Leave it on the % current page, no automatic page break. \balancecolumns % % If we end up splitting too much material for the current page, % though, there will be another page break right after this \output % invocation ends. Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. (We hope \balancecolumns will never be % called on to balance too much material, but if it is, this makes % the output somewhat more palatable.) \global\output = {\onepageout{\pagecontents\PAGE}}% }% \eject \endgroup % started in \begindoublecolumns % % \pagegoal was set to the doubled \vsize above, since we restarted % the current page. We're now back to normal single-column % typesetting, so reset \pagegoal to the normal \vsize (after the % \endgroup where \vsize got restored). \pagegoal = \vsize } % % Called at the end of the double column material. \def\balancecolumns{% \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip \divide\dimen@ by 2 % target to split to %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% \splittopskip = \topskip % Loop until we get a decent breakpoint. {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ \ifdim\ht3>\dimen@ \global\advance\dimen@ by 1pt \repeat }% %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% \setbox0=\vbox to\dimen@{\unvbox1}% \setbox2=\vbox to\dimen@{\unvbox3}% % \pagesofar } \catcode`\@ = \other \message{sectioning,} % Chapters, sections, etc. % \unnumberedno is an oxymoron, of course. But we count the unnumbered % sections so that we can refer to them unambiguously in the pdf % outlines by their "section number". We avoid collisions with chapter % numbers by starting them at 10000. (If a document ever has 10000 % chapters, we're in trouble anyway, I'm sure.) \newcount\unnumberedno \unnumberedno = 10000 \newcount\chapno \newcount\secno \secno=0 \newcount\subsecno \subsecno=0 \newcount\subsubsecno \subsubsecno=0 % This counter is funny since it counts through charcodes of letters A, B, ... \newcount\appendixno \appendixno = `\@ % % \def\appendixletter{\char\the\appendixno} % We do the following ugly conditional instead of the above simple % construct for the sake of pdftex, which needs the actual % letter in the expansion, not just typeset. % \def\appendixletter{% \ifnum\appendixno=`A A% \else\ifnum\appendixno=`B B% \else\ifnum\appendixno=`C C% \else\ifnum\appendixno=`D D% \else\ifnum\appendixno=`E E% \else\ifnum\appendixno=`F F% \else\ifnum\appendixno=`G G% \else\ifnum\appendixno=`H H% \else\ifnum\appendixno=`I I% \else\ifnum\appendixno=`J J% \else\ifnum\appendixno=`K K% \else\ifnum\appendixno=`L L% \else\ifnum\appendixno=`M M% \else\ifnum\appendixno=`N N% \else\ifnum\appendixno=`O O% \else\ifnum\appendixno=`P P% \else\ifnum\appendixno=`Q Q% \else\ifnum\appendixno=`R R% \else\ifnum\appendixno=`S S% \else\ifnum\appendixno=`T T% \else\ifnum\appendixno=`U U% \else\ifnum\appendixno=`V V% \else\ifnum\appendixno=`W W% \else\ifnum\appendixno=`X X% \else\ifnum\appendixno=`Y Y% \else\ifnum\appendixno=`Z Z% % The \the is necessary, despite appearances, because \appendixletter is % expanded while writing the .toc file. \char\appendixno is not % expandable, thus it is written literally, thus all appendixes come out % with the same letter (or @) in the toc without it. \else\char\the\appendixno \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} % Each @chapter defines these (using marks) as the number+name, number % and name of the chapter. Page headings and footings can use % these. @section does likewise. \def\thischapter{} \def\thischapternum{} \def\thischaptername{} \def\thissection{} \def\thissectionnum{} \def\thissectionname{} \newcount\absseclevel % used to calculate proper heading level \newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count % @raisesections: treat @section as chapter, @subsection as section, etc. \def\raisesections{\global\advance\secbase by -1} \let\up=\raisesections % original BFox name % @lowersections: treat @chapter as section, @section as subsection, etc. \def\lowersections{\global\advance\secbase by 1} \let\down=\lowersections % original BFox name % we only have subsub. \chardef\maxseclevel = 3 % % A numbered section within an unnumbered changes to unnumbered too. % To achive this, remember the "biggest" unnum. sec. we are currently in: \chardef\unmlevel = \maxseclevel % % Trace whether the current chapter is an appendix or not: % \chapheadtype is "N" or "A", unnumbered chapters are ignored. \def\chapheadtype{N} % Choose a heading macro % #1 is heading type % #2 is heading level % #3 is text for heading \def\genhead#1#2#3{% % Compute the abs. sec. level: \absseclevel=#2 \advance\absseclevel by \secbase % Make sure \absseclevel doesn't fall outside the range: \ifnum \absseclevel < 0 \absseclevel = 0 \else \ifnum \absseclevel > 3 \absseclevel = 3 \fi \fi % The heading type: \def\headtype{#1}% \if \headtype U% \ifnum \absseclevel < \unmlevel \chardef\unmlevel = \absseclevel \fi \else % Check for appendix sections: \ifnum \absseclevel = 0 \edef\chapheadtype{\headtype}% \else \if \headtype A\if \chapheadtype N% \errmessage{@appendix... within a non-appendix chapter}% \fi\fi \fi % Check for numbered within unnumbered: \ifnum \absseclevel > \unmlevel \def\headtype{U}% \else \chardef\unmlevel = 3 \fi \fi % Now print the heading: \if \headtype U% \ifcase\absseclevel \unnumberedzzz{#3}% \or \unnumberedseczzz{#3}% \or \unnumberedsubseczzz{#3}% \or \unnumberedsubsubseczzz{#3}% \fi \else \if \headtype A% \ifcase\absseclevel \appendixzzz{#3}% \or \appendixsectionzzz{#3}% \or \appendixsubseczzz{#3}% \or \appendixsubsubseczzz{#3}% \fi \else \ifcase\absseclevel \chapterzzz{#3}% \or \seczzz{#3}% \or \numberedsubseczzz{#3}% \or \numberedsubsubseczzz{#3}% \fi \fi \fi \suppressfirstparagraphindent } % an interface: \def\numhead{\genhead N} \def\apphead{\genhead A} \def\unnmhead{\genhead U} % @chapter, @appendix, @unnumbered. Increment top-level counter, reset % all lower-level sectioning counters to zero. % % Also set \chaplevelprefix, which we prepend to @float sequence numbers % (e.g., figures), q.v. By default (before any chapter), that is empty. \let\chaplevelprefix = \empty % \outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz#1{% % section resetting is \global in case the chapter is in a group, such % as an @include file. \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\chapno by 1 % % Used for \float. \gdef\chaplevelprefix{\the\chapno.}% \resetallfloatnos % % \putwordChapter can contain complex things in translations. \toks0=\expandafter{\putwordChapter}% \message{\the\toks0 \space \the\chapno}% % % Write the actual heading. \chapmacro{#1}{Ynumbered}{\the\chapno}% % % So @section and the like are numbered underneath this chapter. \global\let\section = \numberedsec \global\let\subsection = \numberedsubsec \global\let\subsubsection = \numberedsubsubsec } \outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz % \def\appendixzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\appendixno by 1 \gdef\chaplevelprefix{\appendixletter.}% \resetallfloatnos % % \putwordAppendix can contain complex things in translations. \toks0=\expandafter{\putwordAppendix}% \message{\the\toks0 \space \appendixletter}% % \chapmacro{#1}{Yappendix}{\appendixletter}% % \global\let\section = \appendixsec \global\let\subsection = \appendixsubsec \global\let\subsubsection = \appendixsubsubsec } \outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz \def\unnumberedzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\unnumberedno by 1 % % Since an unnumbered has no number, no prefix for figures. \global\let\chaplevelprefix = \empty \resetallfloatnos % % This used to be simply \message{#1}, but TeX fully expands the % argument to \message. Therefore, if #1 contained @-commands, TeX % expanded them. For example, in `@unnumbered The @cite{Book}', TeX % expanded @cite (which turns out to cause errors because \cite is meant % to be executed, not expanded). % % Anyway, we don't want the fully-expanded definition of @cite to appear % as a result of the \message, we just want `@cite' itself. We use % \the to achieve this: TeX expands \the only once, % simply yielding the contents of . (We also do this for % the toc entries.) \toks0 = {#1}% \message{(\the\toks0)}% % \chapmacro{#1}{Ynothing}{\the\unnumberedno}% % \global\let\section = \unnumberedsec \global\let\subsection = \unnumberedsubsec \global\let\subsubsection = \unnumberedsubsubsec } % @centerchap is like @unnumbered, but the heading is centered. \outer\parseargdef\centerchap{% % Well, we could do the following in a group, but that would break % an assumption that \chapmacro is called at the outermost level. % Thus we are safer this way: --kasal, 24feb04 \let\centerparametersmaybe = \centerparameters \unnmhead0{#1}% \let\centerparametersmaybe = \relax } % @top is like @unnumbered. \let\top\unnumbered % Sections. \outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz \def\seczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% } \outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz \def\appendixsectionzzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% } \let\appendixsec\appendixsection \outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz \def\unnumberedseczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% } % Subsections. \outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz \def\numberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% } \outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz \def\appendixsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno}% } \outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz \def\unnumberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno}% } % Subsubsections. \outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz \def\numberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynumbered}% {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% } \outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz \def\appendixsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% } \outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz \def\unnumberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% } % These macros control what the section commands do, according % to what kind of chapter we are in (ordinary, appendix, or unnumbered). % Define them by default for a numbered chapter. \let\section = \numberedsec \let\subsection = \numberedsubsec \let\subsubsection = \numberedsubsubsec % Define @majorheading, @heading and @subheading % NOTE on use of \vbox for chapter headings, section headings, and such: % 1) We use \vbox rather than the earlier \line to permit % overlong headings to fold. % 2) \hyphenpenalty is set to 10000 because hyphenation in a % heading is obnoxious; this forbids it. % 3) Likewise, headings look best if no \parindent is used, and % if justification is not attempted. Hence \raggedright. \def\majorheading{% {\advance\chapheadingskip by 10pt \chapbreak }% \parsearg\chapheadingzzz } \def\chapheading{\chapbreak \parsearg\chapheadingzzz} \def\chapheadingzzz#1{% {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt\ptexraggedright \rmisbold #1\hfill}}% \bigskip \par\penalty 200\relax \suppressfirstparagraphindent } % @heading, @subheading, @subsubheading. \parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} % These macros generate a chapter, section, etc. heading only % (including whitespace, linebreaking, etc. around it), % given all the information in convenient, parsed form. %%% Args are the skip and penalty (usually negative) \def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} %%% Define plain chapter starts, and page on/off switching for it % Parameter controlling skip before chapter headings (if needed) \newskip\chapheadingskip \def\chapbreak{\dobreak \chapheadingskip {-4000}} \def\chappager{\par\vfill\supereject} % Because \domark is called before \chapoddpage, the filler page will % get the headings for the next chapter, which is wrong. But we don't % care -- we just disable all headings on the filler page. \def\chapoddpage{% \chappager \ifodd\pageno \else \begingroup \evenheadline={\hfil}\evenfootline={\hfil}% \oddheadline={\hfil}\oddfootline={\hfil}% \hbox to 0pt{}% \chappager \endgroup \fi } \def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} \def\CHAPPAGoff{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chapbreak \global\let\pagealignmacro=\chappager} \def\CHAPPAGon{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chappager \global\let\pagealignmacro=\chappager \global\def\HEADINGSon{\HEADINGSsingle}} \def\CHAPPAGodd{% \global\let\contentsalignmacro = \chapoddpage \global\let\pchapsepmacro=\chapoddpage \global\let\pagealignmacro=\chapoddpage \global\def\HEADINGSon{\HEADINGSdouble}} \CHAPPAGon % Chapter opening. % % #1 is the text, #2 is the section type (Ynumbered, Ynothing, % Yappendix, Yomitfromtoc), #3 the chapter number. % % To test against our argument. \def\Ynothingkeyword{Ynothing} \def\Yomitfromtockeyword{Yomitfromtoc} \def\Yappendixkeyword{Yappendix} % \def\chapmacro#1#2#3{% % Insert the first mark before the heading break (see notes for \domark). \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}% \gdef\thissection{}}% % \def\temptype{#2}% \ifx\temptype\Ynothingkeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{\thischaptername}}% \else\ifx\temptype\Yomitfromtockeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{}}% \else\ifx\temptype\Yappendixkeyword \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\appendixletter}% % \noexpand\putwordAppendix avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordAppendix{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \else \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\the\chapno}% % \noexpand\putwordChapter avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordChapter{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \fi\fi\fi % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert the chapter heading break. \pchapsepmacro % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \domark % {% \chapfonts \rmisbold % % Have to define \lastsection before calling \donoderef, because the % xref code eventually uses it. On the other hand, it has to be called % after \pchapsepmacro, or the headline will change too soon. \gdef\lastsection{#1}% % % Only insert the separating space if we have a chapter/appendix % number, and don't print the unnumbered ``number''. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unnchap}% \else\ifx\temptype\Yomitfromtockeyword \setbox0 = \hbox{}% contents like unnumbered, but no toc entry \def\toctype{omit}% \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% \def\toctype{app}% \else \setbox0 = \hbox{#3\enspace}% \def\toctype{numchap}% \fi\fi\fi % % Write the toc entry for this chapter. Must come before the % \donoderef, because we include the current node name in the toc % entry, and \donoderef resets it to empty. \writetocentry{\toctype}{#1}{#3}% % % For pdftex, we have to write out the node definition (aka, make % the pdfdest) after any page break, but before the actual text has % been typeset. If the destination for the pdf outline is after the % text, then jumping from the outline may wind up with the text not % being visible, for instance under high magnification. \donoderef{#2}% % % Typeset the actual heading. \nobreak % Avoid page breaks at the interline glue. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright \hangindent=\wd0 \centerparametersmaybe \unhbox0 #1\par}% }% \nobreak\bigskip % no page break after a chapter title \nobreak } % @centerchap -- centered and unnumbered. \let\centerparametersmaybe = \relax \def\centerparameters{% \advance\rightskip by 3\rightskip \leftskip = \rightskip \parfillskip = 0pt } % I don't think this chapter style is supported any more, so I'm not % updating it with the new noderef stuff. We'll see. --karl, 11aug03. % \def\setchapterstyle #1 {\csname CHAPF#1\endcsname} % \def\unnchfopen #1{% \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt\ptexraggedright \rmisbold #1\hfill}}\bigskip \par\nobreak } \def\chfopen #1#2{\chapoddpage {\chapfonts \vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% \par\penalty 5000 % } \def\centerchfopen #1{% \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt \hfill {\rmisbold #1}\hfill}}\bigskip \par\nobreak } \def\CHAPFopen{% \global\let\chapmacro=\chfopen \global\let\centerchapmacro=\centerchfopen} % Section titles. These macros combine the section number parts and % call the generic \sectionheading to do the printing. % \newskip\secheadingskip \def\secheadingbreak{\dobreak \secheadingskip{-1000}} % Subsection titles. \newskip\subsecheadingskip \def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} % Subsubsection titles. \def\subsubsecheadingskip{\subsecheadingskip} \def\subsubsecheadingbreak{\subsecheadingbreak} % Print any size, any type, section title. % % #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is % the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the % section number. % \def\seckeyword{sec} % \def\sectionheading#1#2#3#4{% {% % Switch to the right set of fonts. \csname #2fonts\endcsname \rmisbold % \def\sectionlevel{#2}% \def\temptype{#3}% % % Insert first mark before the heading break (see notes for \domark). \let\prevsectiondefs=\lastsectiondefs \ifx\temptype\Ynothingkeyword \ifx\sectionlevel\seckeyword \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}% \gdef\thissection{\thissectionname}}% \fi \else\ifx\temptype\Yomitfromtockeyword % Don't redefine \thissection. \else\ifx\temptype\Yappendixkeyword \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \else \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \fi\fi\fi % % Go into vertical mode. Usually we'll already be there, but we % don't want the following whatsit to end up in a preceding paragraph % if the document didn't happen to have a blank line. \par % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert space above the heading. \csname #2headingbreak\endcsname % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevsectiondefs=\lastsectiondefs \domark % % Only insert the space after the number if we have a section number. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unn}% \gdef\lastsection{#1}% \else\ifx\temptype\Yomitfromtockeyword % for @headings -- no section number, don't include in toc, % and don't redefine \lastsection. \setbox0 = \hbox{}% \def\toctype{omit}% \let\sectionlevel=\empty \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{#4\enspace}% \def\toctype{app}% \gdef\lastsection{#1}% \else \setbox0 = \hbox{#4\enspace}% \def\toctype{num}% \gdef\lastsection{#1}% \fi\fi\fi % % Write the toc entry (before \donoderef). See comments in \chapmacro. \writetocentry{\toctype\sectionlevel}{#1}{#4}% % % Write the node reference (= pdf destination for pdftex). % Again, see comments in \chapmacro. \donoderef{#3}% % % Interline glue will be inserted when the vbox is completed. % That glue will be a valid breakpoint for the page, since it'll be % preceded by a whatsit (usually from the \donoderef, or from the % \writetocentry if there was no node). We don't want to allow that % break, since then the whatsits could end up on page n while the % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. \nobreak % % Output the actual section heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright \hangindent=\wd0 % zero if no section number \unhbox0 #1}% }% % Add extra space after the heading -- half of whatever came above it. % Don't allow stretch, though. \kern .5 \csname #2headingskip\endcsname % % Do not let the kern be a potential breakpoint, as it would be if it % was followed by glue. \nobreak % % We'll almost certainly start a paragraph next, so don't let that % glue accumulate. (Not a breakpoint because it's preceded by a % discardable item.) \vskip-\parskip % % This is purely so the last item on the list is a known \penalty > % 10000. This is so \startdefun can avoid allowing breakpoints after % section headings. Otherwise, it would insert a valid breakpoint between: % % @section sec-whatever % @deffn def-whatever \penalty 10001 } \message{toc,} % Table of contents. \newwrite\tocfile % Write an entry to the toc file, opening it if necessary. % Called from @chapter, etc. % % Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} % We append the current node name (if any) and page number as additional % arguments for the \{chap,sec,...}entry macros which will eventually % read this. The node name is used in the pdf outlines as the % destination to jump to. % % We open the .toc file for writing here instead of at @setfilename (or % any other fixed time) so that @contents can be anywhere in the document. % But if #1 is `omit', then we don't do anything. This is used for the % table of contents chapter openings themselves. % \newif\iftocfileopened \def\omitkeyword{omit}% % \def\writetocentry#1#2#3{% \edef\writetoctype{#1}% \ifx\writetoctype\omitkeyword \else \iftocfileopened\else \immediate\openout\tocfile = \jobname.toc \global\tocfileopenedtrue \fi % \iflinks {\atdummies \edef\temp{% \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% \temp }% \fi \fi % % Tell \shipout to create a pdf destination on each page, if we're % writing pdf. These are used in the table of contents. We can't % just write one on every page because the title pages are numbered % 1 and 2 (the page numbers aren't printed), and so are the first % two pages of the document. Thus, we'd have two destinations named % `1', and two named `2'. \ifpdf \global\pdfmakepagedesttrue \fi } % These characters do not print properly in the Computer Modern roman % fonts, so we must take special care. This is more or less redundant % with the Texinfo input format setup at the end of this file. % \def\activecatcodes{% \catcode`\"=\active \catcode`\$=\active \catcode`\<=\active \catcode`\>=\active \catcode`\\=\active \catcode`\^=\active \catcode`\_=\active \catcode`\|=\active \catcode`\~=\active } % Read the toc file, which is essentially Texinfo input. \def\readtocfile{% \setupdatafile \activecatcodes \input \tocreadfilename } \newskip\contentsrightmargin \contentsrightmargin=1in \newcount\savepageno \newcount\lastnegativepageno \lastnegativepageno = -1 % Prepare to read what we've written to \tocfile. % \def\startcontents#1{% % If @setchapternewpage on, and @headings double, the contents should % start on an odd page, unlike chapters. Thus, we maintain % \contentsalignmacro in parallel with \pagealignmacro. % From: Torbjorn Granlund \contentsalignmacro \immediate\closeout\tocfile % % Don't need to put `Contents' or `Short Contents' in the headline. % It is abundantly clear what they are. \chapmacro{#1}{Yomitfromtoc}{}% % \savepageno = \pageno \begingroup % Set up to handle contents files properly. \raggedbottom % Worry more about breakpoints than the bottom. \advance\hsize by -\contentsrightmargin % Don't use the full line length. % % Roman numerals for page numbers. \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi } % redefined for the two-volume lispref. We always output on % \jobname.toc even if this is redefined. % \def\tocreadfilename{\jobname.toc} % Normal (long) toc. % \def\contents{% \startcontents{\putwordTOC}% \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \ifeof 1 \else \pdfmakeoutlines \fi \closein 1 \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } % And just the chapters. \def\summarycontents{% \startcontents{\putwordShortTOC}% % \let\numchapentry = \shortchapentry \let\appentry = \shortchapentry \let\unnchapentry = \shortunnchapentry % We want a true roman here for the page numbers. \secfonts \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl \let\tt=\shortconttt \rm \hyphenpenalty = 10000 \advance\baselineskip by 1pt % Open it up a little. \def\numsecentry##1##2##3##4{} \let\appsecentry = \numsecentry \let\unnsecentry = \numsecentry \let\numsubsecentry = \numsecentry \let\appsubsecentry = \numsecentry \let\unnsubsecentry = \numsecentry \let\numsubsubsecentry = \numsecentry \let\appsubsubsecentry = \numsecentry \let\unnsubsubsecentry = \numsecentry \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \closein 1 \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } \let\shortcontents = \summarycontents % Typeset the label for a chapter or appendix for the short contents. % The arg is, e.g., `A' for an appendix, or `3' for a chapter. % \def\shortchaplabel#1{% % This space should be enough, since a single number is .5em, and the % widest letter (M) is 1em, at least in the Computer Modern fonts. % But use \hss just in case. % (This space doesn't include the extra space that gets added after % the label; that gets put in by \shortchapentry above.) % % We'd like to right-justify chapter numbers, but that looks strange % with appendix letters. And right-justifying numbers and % left-justifying letters looks strange when there is less than 10 % chapters. Have to read the whole toc once to know how many chapters % there are before deciding ... \hbox to 1em{#1\hss}% } % These macros generate individual entries in the table of contents. % The first argument is the chapter or section name. % The last argument is the page number. % The arguments in between are the chapter number, section number, ... % Chapters, in the main contents. \def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} % % Chapters, in the short toc. % See comments in \dochapentry re vbox and related settings. \def\shortchapentry#1#2#3#4{% \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% } % Appendices, in the main contents. % Need the word Appendix, and a fixed-size box. % \def\appendixbox#1{% % We use M since it's probably the widest letter. \setbox0 = \hbox{\putwordAppendix{} M}% \hbox to \wd0{\putwordAppendix{} #1\hss}} % \def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} % Unnumbered chapters. \def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} \def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} % Sections. \def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} \let\appsecentry=\numsecentry \def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} % Subsections. \def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} \let\appsubsecentry=\numsubsecentry \def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} % And subsubsections. \def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} \let\appsubsubsecentry=\numsubsubsecentry \def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} % This parameter controls the indentation of the various levels. % Same as \defaultparindent. \newdimen\tocindent \tocindent = 15pt % Now for the actual typesetting. In all these, #1 is the text and #2 is the % page number. % % If the toc has to be broken over pages, we want it to be at chapters % if at all possible; hence the \penalty. \def\dochapentry#1#2{% \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip \begingroup \chapentryfonts \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup \nobreak\vskip .25\baselineskip plus.1\baselineskip } \def\dosecentry#1#2{\begingroup \secentryfonts \leftskip=\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsecentry#1#2{\begingroup \subsecentryfonts \leftskip=2\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsubsecentry#1#2{\begingroup \subsubsecentryfonts \leftskip=3\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} % We use the same \entry macro as for the index entries. \let\tocentry = \entry % Space between chapter (or whatever) number and the title. \def\labelspace{\hskip1em \relax} \def\dopageno#1{{\rm #1}} \def\doshortpageno#1{{\rm #1}} \def\chapentryfonts{\secfonts \rm} \def\secentryfonts{\textfonts} \def\subsecentryfonts{\textfonts} \def\subsubsecentryfonts{\textfonts} \message{environments,} % @foo ... @end foo. % @tex ... @end tex escapes into raw Tex temporarily. % One exception: @ is still an escape character, so that @end tex works. % But \@ or @@ will get a plain tex @ character. \envdef\tex{% \setupmarkupstyle{tex}% \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie \catcode `\%=14 \catcode `\+=\other \catcode `\"=\other \catcode `\|=\other \catcode `\<=\other \catcode `\>=\other \catcode`\`=\other \catcode`\'=\other \escapechar=`\\ % \let\b=\ptexb \let\bullet=\ptexbullet \let\c=\ptexc \let\,=\ptexcomma \let\.=\ptexdot \let\dots=\ptexdots \let\equiv=\ptexequiv \let\!=\ptexexclam \let\i=\ptexi \let\indent=\ptexindent \let\noindent=\ptexnoindent \let\{=\ptexlbrace \let\+=\tabalign \let\}=\ptexrbrace \let\/=\ptexslash \let\*=\ptexstar \let\t=\ptext \expandafter \let\csname top\endcsname=\ptextop % outer \let\frenchspacing=\plainfrenchspacing % \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% \def\@{@}% } % There is no need to define \Etex. % Define @lisp ... @end lisp. % @lisp environment forms a group so it can rebind things, % including the definition of @end lisp (which normally is erroneous). % Amount to narrow the margins by for @lisp. \newskip\lispnarrowing \lispnarrowing=0.4in % This is the definition that ^^M gets inside @lisp, @example, and other % such environments. \null is better than a space, since it doesn't % have any width. \def\lisppar{\null\endgraf} % This space is always present above and below environments. \newskip\envskipamount \envskipamount = 0pt % Make spacing and below environment symmetrical. We use \parskip here % to help in doing that, since in @example-like environments \parskip % is reset to zero; thus the \afterenvbreak inserts no space -- but the % start of the next paragraph will insert \parskip. % \def\aboveenvbreak{{% % =10000 instead of <10000 because of a special case in \itemzzz and % \sectionheading, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip % it's not a good place to break if the last penalty was \nobreak % or better ... \ifnum\lastpenalty<10000 \penalty-50 \fi \vskip\envskipamount \fi \fi }} \let\afterenvbreak = \aboveenvbreak % \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will % also clear it, so that its embedded environments do the narrowing again. \let\nonarrowing=\relax % @cartouche ... @end cartouche: draw rectangle w/rounded corners around % environment contents. \font\circle=lcircle10 \newdimen\circthick \newdimen\cartouter\newdimen\cartinner \newskip\normbskip\newskip\normpskip\newskip\normlskip \circthick=\fontdimen8\circle % \def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth \def\ctr{{\hskip 6pt\circle\char'010}} \def\cbl{{\circle\char'012\hskip -6pt}} \def\cbr{{\hskip 6pt\circle\char'011}} \def\carttop{\hbox to \cartouter{\hskip\lskip \ctl\leaders\hrule height\circthick\hfil\ctr \hskip\rskip}} \def\cartbot{\hbox to \cartouter{\hskip\lskip \cbl\leaders\hrule height\circthick\hfil\cbr \hskip\rskip}} % \newskip\lskip\newskip\rskip \envdef\cartouche{% \ifhmode\par\fi % can't be in the midst of a paragraph. \startsavinginserts \lskip=\leftskip \rskip=\rightskip \leftskip=0pt\rightskip=0pt % we want these *outside*. \cartinner=\hsize \advance\cartinner by-\lskip \advance\cartinner by-\rskip \cartouter=\hsize \advance\cartouter by 18.4pt % allow for 3pt kerns on either % side, and for 6pt waste from % each corner char, and rule thickness \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip % Flag to tell @lisp, etc., not to narrow margin. \let\nonarrowing = t% \vbox\bgroup \baselineskip=0pt\parskip=0pt\lineskip=0pt \carttop \hbox\bgroup \hskip\lskip \vrule\kern3pt \vbox\bgroup \kern3pt \hsize=\cartinner \baselineskip=\normbskip \lineskip=\normlskip \parskip=\normpskip \vskip -\parskip \comment % For explanation, see the end of \def\group. } \def\Ecartouche{% \ifhmode\par\fi \kern3pt \egroup \kern3pt\vrule \hskip\rskip \egroup \cartbot \egroup \checkinserts } % This macro is called at the beginning of all the @example variants, % inside a group. \newdimen\nonfillparindent \def\nonfillstart{% \aboveenvbreak \hfuzz = 12pt % Don't be fussy \sepspaces % Make spaces be word-separators rather than space tokens. \let\par = \lisppar % don't ignore blank lines \obeylines % each line of input is a line of output \parskip = 0pt % Turn off paragraph indentation but redefine \indent to emulate % the normal \indent. \nonfillparindent=\parindent \parindent = 0pt \let\indent\nonfillindent % \emergencystretch = 0pt % don't try to avoid overfull boxes \ifx\nonarrowing\relax \advance \leftskip by \lispnarrowing \exdentamount=\lispnarrowing \else \let\nonarrowing = \relax \fi \let\exdent=\nofillexdent } \begingroup \obeyspaces % We want to swallow spaces (but not other tokens) after the fake % @indent in our nonfill-environments, where spaces are normally % active and set to @tie, resulting in them not being ignored after % @indent. \gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}% \gdef\nonfillindentcheck{% \ifx\temp % \expandafter\nonfillindentgobble% \else% \leavevmode\nonfillindentbox% \fi% }% \endgroup \def\nonfillindentgobble#1{\nonfillindent} \def\nonfillindentbox{\hbox to \nonfillparindent{\hss}} % If you want all examples etc. small: @set dispenvsize small. % If you want even small examples the full size: @set dispenvsize nosmall. % This affects the following displayed environments: % @example, @display, @format, @lisp % \def\smallword{small} \def\nosmallword{nosmall} \let\SETdispenvsize\relax \def\setnormaldispenv{% \ifx\SETdispenvsize\smallword % end paragraph for sake of leading, in case document has no blank % line. This is redundant with what happens in \aboveenvbreak, but % we need to do it before changing the fonts, and it's inconvenient % to change the fonts afterward. \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } \def\setsmalldispenv{% \ifx\SETdispenvsize\nosmallword \else \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } % We often define two environments, @foo and @smallfoo. % Let's do it by one command: \def\makedispenv #1#2{ \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2} \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2} \expandafter\let\csname E#1\endcsname \afterenvbreak \expandafter\let\csname Esmall#1\endcsname \afterenvbreak } % Define two synonyms: \def\maketwodispenvs #1#2#3{ \makedispenv{#1}{#3} \makedispenv{#2}{#3} } % @lisp: indented, narrowed, typewriter font; @example: same as @lisp. % % @smallexample and @smalllisp: use smaller fonts. % Originally contributed by Pavel@xerox. % \maketwodispenvs {lisp}{example}{% \nonfillstart \tt\setupmarkupstyle{example}% \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. \gobble % eat return } % @display/@smalldisplay: same as @lisp except keep current font. % \makedispenv {display}{% \nonfillstart \gobble } % @format/@smallformat: same as @display except don't narrow margins. % \makedispenv{format}{% \let\nonarrowing = t% \nonfillstart \gobble } % @flushleft: same as @format, but doesn't obey \SETdispenvsize. \envdef\flushleft{% \let\nonarrowing = t% \nonfillstart \gobble } \let\Eflushleft = \afterenvbreak % @flushright. % \envdef\flushright{% \let\nonarrowing = t% \nonfillstart \advance\leftskip by 0pt plus 1fill \gobble } \let\Eflushright = \afterenvbreak % @raggedright does more-or-less normal line breaking but no right % justification. From plain.tex. \envdef\raggedright{% \rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax } \let\Eraggedright\par \envdef\raggedleft{% \parindent=0pt \leftskip0pt plus2em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedleft\par \envdef\raggedcenter{% \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedcenter\par % @quotation does normal linebreaking (hence we can't use \nonfillstart) % and narrows the margins. We keep \parskip nonzero in general, since % we're doing normal filling. So, when using \aboveenvbreak and % \afterenvbreak, temporarily make \parskip 0. % \def\quotationstart{% {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip \parindent=0pt % % @cartouche defines \nonarrowing to inhibit narrowing at next level down. \ifx\nonarrowing\relax \advance\leftskip by \lispnarrowing \advance\rightskip by \lispnarrowing \exdentamount = \lispnarrowing \else \let\nonarrowing = \relax \fi \parsearg\quotationlabel } \envdef\quotation{% \setnormaldispenv \quotationstart } \envdef\smallquotation{% \setsmalldispenv \quotationstart } \let\Esmallquotation = \Equotation % We have retained a nonzero parskip for the environment, since we're % doing normal filling. % \def\Equotation{% \par \ifx\quotationauthor\undefined\else % indent a bit. \leftline{\kern 2\leftskip \sl ---\quotationauthor}% \fi {\parskip=0pt \afterenvbreak}% } % If we're given an argument, typeset it in bold with a colon after. \def\quotationlabel#1{% \def\temp{#1}% \ifx\temp\empty \else {\bf #1: }% \fi } % LaTeX-like @verbatim...@end verbatim and @verb{...} % If we want to allow any as delimiter, % we need the curly braces so that makeinfo sees the @verb command, eg: % `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org % % [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. % % [Knuth] p.344; only we need to do the other characters Texinfo sets % active too. Otherwise, they get lost as the first character on a % verbatim line. \def\dospecials{% \do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% \do\<\do\>\do\|\do\@\do+\do\"% % Don't do the quotes -- if we do, @set txicodequoteundirected and % @set txicodequotebacktick will not have effect on @verb and % @verbatim, and ?` and !` ligatures won't get disabled. %\do\`\do\'% } % % [Knuth] p. 380 \def\uncatcodespecials{% \def\do##1{\catcode`##1=\other}\dospecials} % % Setup for the @verb command. % % Eight spaces for a tab \begingroup \catcode`\^^I=\active \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} \endgroup % \def\setupverb{% \tt % easiest (and conventionally used) font for verbatim \def\par{\leavevmode\endgraf}% \setupmarkupstyle{verb}% \tabeightspaces % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces } % Setup for the @verbatim environment % % Real tab expansion \newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount % \def\starttabbox{\setbox0=\hbox\bgroup} % \begingroup \catcode`\^^I=\active \gdef\tabexpand{% \catcode`\^^I=\active \def^^I{\leavevmode\egroup \dimen0=\wd0 % the width so far, or since the previous tab \divide\dimen0 by\tabw \multiply\dimen0 by\tabw % compute previous multiple of \tabw \advance\dimen0 by\tabw % advance to next multiple of \tabw \wd0=\dimen0 \box0 \starttabbox }% } \endgroup % start the verbatim environment. \def\setupverbatim{% \let\nonarrowing = t% \nonfillstart % Easiest (and conventionally used) font for verbatim \tt \def\par{\leavevmode\egroup\box0\endgraf}% \tabexpand \setupmarkupstyle{verbatim}% % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces \everypar{\starttabbox}% } % Do the @verb magic: verbatim text is quoted by unique % delimiter characters. Before first delimiter expect a % right brace, after last delimiter expect closing brace: % % \def\doverb'{'#1'}'{#1} % % [Knuth] p. 382; only eat outer {} \begingroup \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] \endgroup % \def\verb{\begingroup\setupverb\doverb} % % % Do the @verbatim magic: define the macro \doverbatim so that % the (first) argument ends when '@end verbatim' is reached, ie: % % \def\doverbatim#1@end verbatim{#1} % % For Texinfo it's a lot easier than for LaTeX, % because texinfo's \verbatim doesn't stop at '\end{verbatim}': % we need not redefine '\', '{' and '}'. % % Inspired by LaTeX's verbatim command set [latex.ltx] % \begingroup \catcode`\ =\active \obeylines % % ignore everything up to the first ^^M, that's the newline at the end % of the @verbatim input line itself. Otherwise we get an extra blank % line in the output. \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% % We really want {...\end verbatim} in the body of the macro, but % without the active space; thus we have to use \xdef and \gobble. \endgroup % \envdef\verbatim{% \setupverbatim\doverbatim } \let\Everbatim = \afterenvbreak % @verbatiminclude FILE - insert text of file in verbatim environment. % \def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} % \def\doverbatiminclude#1{% {% \makevalueexpandable \setupverbatim \indexnofonts % Allow `@@' and other weird things in file names. \input #1 \afterenvbreak }% } % @copying ... @end copying. % Save the text away for @insertcopying later. % % We save the uninterpreted tokens, rather than creating a box. % Saving the text in a box would be much easier, but then all the % typesetting commands (@smallbook, font changes, etc.) have to be done % beforehand -- and a) we want @copying to be done first in the source % file; b) letting users define the frontmatter in as flexible order as % possible is very desirable. % \def\copying{\checkenv{}\begingroup\scanargctxt\docopying} \def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} % \def\insertcopying{% \begingroup \parindent = 0pt % paragraph indentation looks wrong on title page \scanexp\copyingtext \endgroup } \message{defuns,} % @defun etc. \newskip\defbodyindent \defbodyindent=.4in \newskip\defargsindent \defargsindent=50pt \newskip\deflastargmargin \deflastargmargin=18pt \newcount\defunpenalty % Start the processing of @deffn: \def\startdefun{% \ifnum\lastpenalty<10000 \medbreak \defunpenalty=10003 % Will keep this @deffn together with the % following @def command, see below. \else % If there are two @def commands in a row, we'll have a \nobreak, % which is there to keep the function description together with its % header. But if there's nothing but headers, we need to allow a % break somewhere. Check specifically for penalty 10002, inserted % by \printdefunline, instead of 10000, since the sectioning % commands also insert a nobreak penalty, and we don't want to allow % a break between a section heading and a defun. % % As a minor refinement, we avoid "club" headers by signalling % with penalty of 10003 after the very first @deffn in the % sequence (see above), and penalty of 10002 after any following % @def command. \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi % % Similarly, after a section heading, do not allow a break. % But do insert the glue. \medskip % preceded by discardable penalty, so not a breakpoint \fi % \parindent=0in \advance\leftskip by \defbodyindent \exdentamount=\defbodyindent } \def\dodefunx#1{% % First, check whether we are in the right environment: \checkenv#1% % % As above, allow line break if we have multiple x headers in a row. % It's not a great place, though. \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi % % And now, it's time to reuse the body of the original defun: \expandafter\gobbledefun#1% } \def\gobbledefun#1\startdefun{} % \printdefunline \deffnheader{text} % \def\printdefunline#1#2{% \begingroup % call \deffnheader: #1#2 \endheader % common ending: \interlinepenalty = 10000 \advance\rightskip by 0pt plus 1fil \endgraf \nobreak\vskip -\parskip \penalty\defunpenalty % signal to \startdefun and \dodefunx % Some of the @defun-type tags do not enable magic parentheses, % rendering the following check redundant. But we don't optimize. \checkparencounts \endgroup } \def\Edefun{\endgraf\medbreak} % \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; % the only thing remaining is to define \deffnheader. % \def\makedefun#1{% \expandafter\let\csname E#1\endcsname = \Edefun \edef\temp{\noexpand\domakedefun \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% \temp } % \domakedefun \deffn \deffnx \deffnheader % % Define \deffn and \deffnx, without parameters. % \deffnheader has to be defined explicitly. % \def\domakedefun#1#2#3{% \envdef#1{% \startdefun \parseargusing\activeparens{\printdefunline#3}% }% \def#2{\dodefunx#1}% \def#3% } %%% Untyped functions: % @deffn category name args \makedefun{deffn}{\deffngeneral{}} % @deffn category class name args \makedefun{defop}#1 {\defopon{#1\ \putwordon}} % \defopon {category on}class name args \def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deffngeneral {subind}category name args % \def\deffngeneral#1#2 #3 #4\endheader{% % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. \dosubind{fn}{\code{#3}}{#1}% \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% } %%% Typed functions: % @deftypefn category type name args \makedefun{deftypefn}{\deftypefngeneral{}} % @deftypeop category class type name args \makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} % \deftypeopon {category on}class type name args \def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deftypefngeneral {subind}category type name args % \def\deftypefngeneral#1#2 #3 #4 #5\endheader{% \dosubind{fn}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } %%% Typed variables: % @deftypevr category type var args \makedefun{deftypevr}{\deftypecvgeneral{}} % @deftypecv category class type var args \makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} % \deftypecvof {category of}class type var args \def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } % \deftypecvgeneral {subind}category type var args % \def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% \dosubind{vr}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } %%% Untyped variables: % @defvr category var args \makedefun{defvr}#1 {\deftypevrheader{#1} {} } % @defcv category class var args \makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} % \defcvof {category of}class var args \def\defcvof#1#2 {\deftypecvof{#1}#2 {} } %%% Type: % @deftp category name args \makedefun{deftp}#1 #2 #3\endheader{% \doind{tp}{\code{#2}}% \defname{#1}{}{#2}\defunargs{#3\unskip}% } % Remaining @defun-like shortcuts: \makedefun{defun}{\deffnheader{\putwordDeffunc} } \makedefun{defmac}{\deffnheader{\putwordDefmac} } \makedefun{defspec}{\deffnheader{\putwordDefspec} } \makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } \makedefun{defvar}{\defvrheader{\putwordDefvar} } \makedefun{defopt}{\defvrheader{\putwordDefopt} } \makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } \makedefun{defmethod}{\defopon\putwordMethodon} \makedefun{deftypemethod}{\deftypeopon\putwordMethodon} \makedefun{defivar}{\defcvof\putwordInstanceVariableof} \makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} % \defname, which formats the name of the @def (not the args). % #1 is the category, such as "Function". % #2 is the return type, if any. % #3 is the function name. % % We are followed by (but not passed) the arguments, if any. % \def\defname#1#2#3{% % Get the values of \leftskip and \rightskip as they were outside the @def... \advance\leftskip by -\defbodyindent % % How we'll format the type name. Putting it in brackets helps % distinguish it from the body text that may end up on the next line % just below it. \def\temp{#1}% \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} % % Figure out line sizes for the paragraph shape. % The first line needs space for \box0; but if \rightskip is nonzero, % we need only space for the part of \box0 which exceeds it: \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip % The continuations: \dimen2=\hsize \advance\dimen2 by -\defargsindent % (plain.tex says that \dimen1 should be used only as global.) \parshape 2 0in \dimen0 \defargsindent \dimen2 % % Put the type name to the right margin. \noindent \hbox to 0pt{% \hfil\box0 \kern-\hsize % \hsize has to be shortened this way: \kern\leftskip % Intentionally do not respect \rightskip, since we need the space. }% % % Allow all lines to be underfull without complaint: \tolerance=10000 \hbadness=10000 \exdentamount=\defbodyindent {% % defun fonts. We use typewriter by default (used to be bold) because: % . we're printing identifiers, they should be in tt in principle. % . in languages with many accents, such as Czech or French, it's % common to leave accents off identifiers. The result looks ok in % tt, but exceedingly strange in rm. % . we don't want -- and --- to be treated as ligatures. % . this still does not fix the ?` and !` ligatures, but so far no % one has made identifiers using them :). \df \tt \def\temp{#2}% return value type \ifx\temp\empty\else \tclose{\temp} \fi #3% output function name }% {\rm\enskip}% hskip 0.5 em of \tenrm % \boldbrax % arguments will be output next, if any. } % Print arguments in slanted roman (not ttsl), inconsistently with using % tt for the name. This is because literal text is sometimes needed in % the argument list (groff manual), and ttsl and tt are not very % distinguishable. Prevent hyphenation at `-' chars. % \def\defunargs#1{% % use sl by default (not ttsl), % tt for the names. \df \sl \hyphenchar\font=0 % % On the other hand, if an argument has two dashes (for instance), we % want a way to get ttsl. Let's try @var for that. \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}% #1% \sl\hyphenchar\font=45 } % We want ()&[] to print specially on the defun line. % \def\activeparens{% \catcode`\(=\active \catcode`\)=\active \catcode`\[=\active \catcode`\]=\active \catcode`\&=\active } % Make control sequences which act like normal parenthesis chars. \let\lparen = ( \let\rparen = ) % Be sure that we always have a definition for `(', etc. For example, % if the fn name has parens in it, \boldbrax will not be in effect yet, % so TeX would otherwise complain about undefined control sequence. { \activeparens \global\let(=\lparen \global\let)=\rparen \global\let[=\lbrack \global\let]=\rbrack \global\let& = \& \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} \gdef\magicamp{\let&=\amprm} } \newcount\parencount % If we encounter &foo, then turn on ()-hacking afterwards \newif\ifampseen \def\amprm#1 {\ampseentrue{\bf\ }} \def\parenfont{% \ifampseen % At the first level, print parens in roman, % otherwise use the default font. \ifnum \parencount=1 \rm \fi \else % The \sf parens (in \boldbrax) actually are a little bolder than % the contained text. This is especially needed for [ and ] . \sf \fi } \def\infirstlevel#1{% \ifampseen \ifnum\parencount=1 #1% \fi \fi } \def\bfafterword#1 {#1 \bf} \def\opnr{% \global\advance\parencount by 1 {\parenfont(}% \infirstlevel \bfafterword } \def\clnr{% {\parenfont)}% \infirstlevel \sl \global\advance\parencount by -1 } \newcount\brackcount \def\lbrb{% \global\advance\brackcount by 1 {\bf[}% } \def\rbrb{% {\bf]}% \global\advance\brackcount by -1 } \def\checkparencounts{% \ifnum\parencount=0 \else \badparencount \fi \ifnum\brackcount=0 \else \badbrackcount \fi } % these should not use \errmessage; the glibc manual, at least, actually % has such constructs (when documenting function pointers). \def\badparencount{% \message{Warning: unbalanced parentheses in @def...}% \global\parencount=0 } \def\badbrackcount{% \message{Warning: unbalanced square brackets in @def...}% \global\brackcount=0 } \message{macros,} % @macro. % To do this right we need a feature of e-TeX, \scantokens, % which we arrange to emulate with a temporary file in ordinary TeX. \ifx\eTeXversion\undefined \newwrite\macscribble \def\scantokens#1{% \toks0={#1}% \immediate\openout\macscribble=\jobname.tmp \immediate\write\macscribble{\the\toks0}% \immediate\closeout\macscribble \input \jobname.tmp } \fi \def\scanmacro#1{% \begingroup \newlinechar`\^^M \let\xeatspaces\eatspaces % Undo catcode changes of \startcontents and \doprintindex % When called from @insertcopying or (short)caption, we need active % backslash to get it printed correctly. Previously, we had % \catcode`\\=\other instead. We'll see whether a problem appears % with macro expansion. --kasal, 19aug04 \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ % ... and \example \spaceisspace % % Append \endinput to make sure that TeX does not see the ending newline. % I've verified that it is necessary both for e-TeX and for ordinary TeX % --kasal, 29nov03 \scantokens{#1\endinput}% \endgroup } \def\scanexp#1{% \edef\temp{\noexpand\scanmacro{#1}}% \temp } \newcount\paramno % Count of parameters \newtoks\macname % Macro name \newif\ifrecursive % Is it recursive? % List of all defined macros in the form % \definedummyword\macro1\definedummyword\macro2... % Currently is also contains all @aliases; the list can be split % if there is a need. \def\macrolist{} % Add the macro to \macrolist \def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} \def\addtomacrolistxxx#1{% \toks0 = \expandafter{\macrolist\definedummyword#1}% \xdef\macrolist{\the\toks0}% } % Utility routines. % This does \let #1 = #2, with \csnames; that is, % \let \csname#1\endcsname = \csname#2\endcsname % (except of course we have to play expansion games). % \def\cslet#1#2{% \expandafter\let \csname#1\expandafter\endcsname \csname#2\endcsname } % Trim leading and trailing spaces off a string. % Concepts from aro-bend problem 15 (see CTAN). {\catcode`\@=11 \gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} \gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} \gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} \def\unbrace#1{#1} \unbrace{\gdef\trim@@@ #1 } #2@{#1} } % Trim a single trailing ^^M off a string. {\catcode`\^^M=\other \catcode`\Q=3% \gdef\eatcr #1{\eatcra #1Q^^MQ}% \gdef\eatcra#1^^MQ{\eatcrb#1Q}% \gdef\eatcrb#1Q#2Q{#1}% } % Macro bodies are absorbed as an argument in a context where % all characters are catcode 10, 11 or 12, except \ which is active % (as in normal texinfo). It is necessary to change the definition of \. % Non-ASCII encodings make 8-bit characters active, so un-activate % them to avoid their expansion. Must do this non-globally, to % confine the change to the current group. % It's necessary to have hard CRs when the macro is executed. This is % done by making ^^M (\endlinechar) catcode 12 when reading the macro % body, and then making it the \newlinechar in \scanmacro. \def\scanctxt{% \catcode`\"=\other \catcode`\+=\other \catcode`\<=\other \catcode`\>=\other \catcode`\@=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\~=\other \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi } \def\scanargctxt{% \scanctxt \catcode`\\=\other \catcode`\^^M=\other } \def\macrobodyctxt{% \scanctxt \catcode`\{=\other \catcode`\}=\other \catcode`\^^M=\other \usembodybackslash } \def\macroargctxt{% \scanctxt \catcode`\\=\other } % \mbodybackslash is the definition of \ in @macro bodies. % It maps \foo\ => \csname macarg.foo\endcsname => #N % where N is the macro parameter number. % We define \csname macarg.\endcsname to be \realbackslash, so % \\ in macro replacement text gets you a backslash. {\catcode`@=0 @catcode`@\=@active @gdef@usembodybackslash{@let\=@mbodybackslash} @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} } \expandafter\def\csname macarg.\endcsname{\realbackslash} \def\macro{\recursivefalse\parsearg\macroxxx} \def\rmacro{\recursivetrue\parsearg\macroxxx} \def\macroxxx#1{% \getargs{#1}% now \macname is the macname and \argl the arglist \ifx\argl\empty % no arguments \paramno=0% \else \expandafter\parsemargdef \argl;% \fi \if1\csname ismacro.\the\macname\endcsname \message{Warning: redefining \the\macname}% \else \expandafter\ifx\csname \the\macname\endcsname \relax \else \errmessage{Macro name \the\macname\space already defined}\fi \global\cslet{macsave.\the\macname}{\the\macname}% \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% \addtomacrolist{\the\macname}% \fi \begingroup \macrobodyctxt \ifrecursive \expandafter\parsermacbody \else \expandafter\parsemacbody \fi} \parseargdef\unmacro{% \if1\csname ismacro.#1\endcsname \global\cslet{#1}{macsave.#1}% \global\expandafter\let \csname ismacro.#1\endcsname=0% % Remove the macro name from \macrolist: \begingroup \expandafter\let\csname#1\endcsname \relax \let\definedummyword\unmacrodo \xdef\macrolist{\macrolist}% \endgroup \else \errmessage{Macro #1 not defined}% \fi } % Called by \do from \dounmacro on each macro. The idea is to omit any % macro definitions that have been changed to \relax. % \def\unmacrodo#1{% \ifx #1\relax % remove this \else \noexpand\definedummyword \noexpand#1% \fi } % This makes use of the obscure feature that if the last token of a % is #, then the preceding argument is delimited by % an opening brace, and that opening brace is not consumed. \def\getargs#1{\getargsxxx#1{}} \def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} \def\getmacname #1 #2\relax{\macname={#1}} \def\getmacargs#1{\def\argl{#1}} % Parse the optional {params} list. Set up \paramno and \paramlist % so \defmacro knows what to do. Define \macarg.blah for each blah % in the params list, to be ##N where N is the position in that list. % That gets used by \mbodybackslash (above). % We need to get `macro parameter char #' into several definitions. % The technique used is stolen from LaTeX: let \hash be something % unexpandable, insert that wherever you need a #, and then redefine % it to # just before using the token list produced. % % The same technique is used to protect \eatspaces till just before % the macro is used. \def\parsemargdef#1;{\paramno=0\def\paramlist{}% \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} \def\parsemargdefxxx#1,{% \if#1;\let\next=\relax \else \let\next=\parsemargdefxxx \advance\paramno by 1% \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname {\xeatspaces{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} % These two commands read recursive and nonrecursive macro bodies. % (They're different since rec and nonrec macros end differently.) \long\def\parsemacbody#1@end macro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \long\def\parsermacbody#1@end rmacro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% % This defines the macro itself. There are six cases: recursive and % nonrecursive macros of zero, one, and many arguments. % Much magic with \expandafter here. % \xdef is used so that macro definitions will survive the file % they're defined in; @include reads the file inside a group. \def\defmacro{% \let\hash=##% convert placeholders to macro parameter chars \ifrecursive \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\scanmacro{\temp}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup\noexpand\scanmacro{\temp}}% \else % many \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{\egroup\noexpand\scanmacro{\temp}}% \fi \else \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % many \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \expandafter\noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \fi \fi} \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} % \braceorline decides whether the next nonwhitespace character is a % {. If so it reads up to the closing }, if not, it reads the whole % line. Whatever was read is then fed to the next control sequence % as an argument (by \parsebrace or \parsearg) \def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} \def\braceorlinexxx{% \ifx\nchar\bgroup\else \expandafter\parsearg \fi \macnamexxx} % @alias. % We need some trickery to remove the optional spaces around the equal % sign. Just make them active and then expand them all to nothing. \def\alias{\parseargusing\obeyspaces\aliasxxx} \def\aliasxxx #1{\aliasyyy#1\relax} \def\aliasyyy #1=#2\relax{% {% \expandafter\let\obeyedspace=\empty \addtomacrolist{#1}% \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% }% \next } \message{cross references,} \newwrite\auxfile \newif\ifhavexrefs % True if xref values are known. \newif\ifwarnedxrefs % True if we warned once that they aren't known. % @inforef is relatively simple. \def\inforef #1{\inforefzzz #1,,,,**} \def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, node \samp{\ignorespaces#1{}}} % @node's only job in TeX is to define \lastnode, which is used in % cross-references. The @node line might or might not have commas, and % might or might not have spaces before the first comma, like: % @node foo , bar , ... % We don't want such trailing spaces in the node name. % \parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} % % also remove a trailing comma, in case of something like this: % @node Help-Cross, , , Cross-refs \def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} \def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} \let\nwnode=\node \let\lastnode=\empty % Write a cross-reference definition for the current node. #1 is the % type (Ynumbered, Yappendix, Ynothing). % \def\donoderef#1{% \ifx\lastnode\empty\else \setref{\lastnode}{#1}% \global\let\lastnode=\empty \fi } % @anchor{NAME} -- define xref target at arbitrary point. % \newcount\savesfregister % \def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} \def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} \def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} % \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an % anchor), which consists of three parts: % 1) NAME-title - the current sectioning name taken from \lastsection, % or the anchor name. % 2) NAME-snt - section number and type, passed as the SNT arg, or % empty for anchors. % 3) NAME-pg - the page number. % % This is called from \donoderef, \anchor, and \dofloat. In the case of % floats, there is an additional part, which is not written here: % 4) NAME-lof - the text as it should appear in a @listoffloats. % \def\setref#1#2{% \pdfmkdest{#1}% \iflinks {% \atdummies % preserve commands, but don't expand them \edef\writexrdef##1##2{% \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef ##1}{##2}}% these are parameters of \writexrdef }% \toks0 = \expandafter{\lastsection}% \immediate \writexrdef{title}{\the\toks0 }% \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, during \shipout }% \fi } % @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is % the node name, #2 the name of the Info cross-reference, #3 the printed % node name, #4 the name of the Info file, #5 the name of the printed % manual. All but the node name can be omitted. % \def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} \def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} \def\ref#1{\xrefX[#1,,,,,,,]} \def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup \unsepspaces \def\printedmanual{\ignorespaces #5}% \def\printedrefname{\ignorespaces #3}% \setbox1=\hbox{\printedmanual\unskip}% \setbox0=\hbox{\printedrefname\unskip}% \ifdim \wd0 = 0pt % No printed node name was explicitly given. \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax % Use the node name inside the square brackets. \def\printedrefname{\ignorespaces #1}% \else % Use the actual chapter/section title appear inside % the square brackets. Use the real section title if we have it. \ifdim \wd1 > 0pt % It is in another manual, so we don't have it. \def\printedrefname{\ignorespaces #1}% \else \ifhavexrefs % We know the real title if we have the xref values. \def\printedrefname{\refx{#1-title}{}}% \else % Otherwise just copy the Info node name. \def\printedrefname{\ignorespaces #1}% \fi% \fi \fi \fi % % Make link in pdf output. \ifpdf {\indexnofonts \turnoffactive % This expands tokens, so do it after making catcode changes, so _ % etc. don't get their TeX definitions. \getfilename{#4}% % % See comments at \activebackslashdouble. {\activebackslashdouble \xdef\pdfxrefdest{#1}% \backslashparens\pdfxrefdest}% % \leavevmode \startlink attr{/Border [0 0 0]}% \ifnum\filenamelength>0 goto file{\the\filename.pdf} name{\pdfxrefdest}% \else goto name{\pdfmkpgn{\pdfxrefdest}}% \fi }% \setcolor{\linkcolor}% \fi % % Float references are printed completely differently: "Figure 1.2" % instead of "[somenode], p.3". We distinguish them by the % LABEL-title being set to a magic string. {% % Have to otherify everything special to allow the \csname to % include an _ in the xref name, etc. \indexnofonts \turnoffactive \expandafter\global\expandafter\let\expandafter\Xthisreftitle \csname XR#1-title\endcsname }% \iffloat\Xthisreftitle % If the user specified the print name (third arg) to the ref, % print it instead of our usual "Figure 1.2". \ifdim\wd0 = 0pt \refx{#1-snt}{}% \else \printedrefname \fi % % if the user also gave the printed manual name (fifth arg), append % "in MANUALNAME". \ifdim \wd1 > 0pt \space \putwordin{} \cite{\printedmanual}% \fi \else % node/anchor (non-float) references. % % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not % insert empty discretionaries after hyphens, which means that it will % not find a line break at a hyphen in a node names. Since some manuals % are best written with fairly long node names, containing hyphens, this % is a loss. Therefore, we give the text of the node name again, so it % is as if TeX is seeing it for the first time. \ifdim \wd1 > 0pt \putwordSection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}% \else % _ (for example) has to be the character _ for the purposes of the % control sequence corresponding to the node, but it has to expand % into the usual \leavevmode...\vrule stuff for purposes of % printing. So we \turnoffactive for the \refx-snt, back on for the % printing, back off for the \refx-pg. {\turnoffactive % Only output a following space if the -snt ref is nonempty; for % @unnumbered and @anchor, it won't be. \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi }% % output the `[mynode]' via a macro so it can be overridden. \xrefprintnodename\printedrefname % % But we always want a comma and a space: ,\space % % output the `page 3'. \turnoffactive \putwordpage\tie\refx{#1-pg}{}% \fi \fi \endlink \endgroup} % This macro is called from \xrefX for the `[nodename]' part of xref % output. It's a separate macro only so it can be changed more easily, % since square brackets don't work well in some documents. Particularly % one that Bob is working on :). % \def\xrefprintnodename#1{[#1]} % Things referred to by \setref. % \def\Ynothing{} \def\Yomitfromtoc{} \def\Ynumbered{% \ifnum\secno=0 \putwordChapter@tie \the\chapno \else \ifnum\subsecno=0 \putwordSection@tie \the\chapno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie \the\chapno.\the\secno.\the\subsecno \else \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } \def\Yappendix{% \ifnum\secno=0 \putwordAppendix@tie @char\the\appendixno{}% \else \ifnum\subsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno \else \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } % Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. % If its value is nonempty, SUFFIX is output afterward. % \def\refx#1#2{% {% \indexnofonts \otherbackslash \expandafter\global\expandafter\let\expandafter\thisrefX \csname XR#1\endcsname }% \ifx\thisrefX\relax % If not defined, say something at least. \angleleft un\-de\-fined\angleright \iflinks \ifhavexrefs \message{\linenumber Undefined cross reference `#1'.}% \else \ifwarnedxrefs\else \global\warnedxrefstrue \message{Cross reference values unknown; you must run TeX again.}% \fi \fi \fi \else % It's defined, so just use it. \thisrefX \fi #2% Output the suffix in any case. } % This is the macro invoked by entries in the aux file. Usually it's % just a \def (we prepend XR to the control sequence name to avoid % collisions). But if this is a float type, we have more work to do. % \def\xrdef#1#2{% {% The node name might contain 8-bit characters, which in our current % implementation are changed to commands like @'e. Don't let these % mess up the control sequence name. \indexnofonts \turnoffactive \xdef\safexrefname{#1}% }% % \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref % % Was that xref control sequence that we just defined for a float? \expandafter\iffloat\csname XR\safexrefname\endcsname % it was a float, and we have the (safe) float type in \iffloattype. \expandafter\let\expandafter\floatlist \csname floatlist\iffloattype\endcsname % % Is this the first time we've seen this float type? \expandafter\ifx\floatlist\relax \toks0 = {\do}% yes, so just \do \else % had it before, so preserve previous elements in list. \toks0 = \expandafter{\floatlist\do}% \fi % % Remember this xref in the control sequence \floatlistFLOATTYPE, % for later use in \listoffloats. \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 {\safexrefname}}% \fi } % Read the last existing aux file, if any. No error if none exists. % \def\tryauxfile{% \openin 1 \jobname.aux \ifeof 1 \else \readdatafile{aux}% \global\havexrefstrue \fi \closein 1 } \def\setupdatafile{% \catcode`\^^@=\other \catcode`\^^A=\other \catcode`\^^B=\other \catcode`\^^C=\other \catcode`\^^D=\other \catcode`\^^E=\other \catcode`\^^F=\other \catcode`\^^G=\other \catcode`\^^H=\other \catcode`\^^K=\other \catcode`\^^L=\other \catcode`\^^N=\other \catcode`\^^P=\other \catcode`\^^Q=\other \catcode`\^^R=\other \catcode`\^^S=\other \catcode`\^^T=\other \catcode`\^^U=\other \catcode`\^^V=\other \catcode`\^^W=\other \catcode`\^^X=\other \catcode`\^^Z=\other \catcode`\^^[=\other \catcode`\^^\=\other \catcode`\^^]=\other \catcode`\^^^=\other \catcode`\^^_=\other % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. % in xref tags, i.e., node names. But since ^^e4 notation isn't % supported in the main text, it doesn't seem desirable. Furthermore, % that is not enough: for node names that actually contain a ^ % character, we would end up writing a line like this: 'xrdef {'hat % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first % argument, and \hat is not an expandable control sequence. It could % all be worked out, but why? Either we support ^^ or we don't. % % The other change necessary for this was to define \auxhat: % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter % and then to call \auxhat in \setq. % \catcode`\^=\other % % Special characters. Should be turned off anyway, but... \catcode`\~=\other \catcode`\[=\other \catcode`\]=\other \catcode`\"=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\$=\other \catcode`\#=\other \catcode`\&=\other \catcode`\%=\other \catcode`+=\other % avoid \+ for paranoia even though we've turned it off % % This is to support \ in node names and titles, since the \ % characters end up in a \csname. It's easier than % leaving it active and making its active definition an actual \ % character. What I don't understand is why it works in the *value* % of the xrdef. Seems like it should be a catcode12 \, and that % should not typeset properly. But it works, so I'm moving on for % now. --karl, 15jan04. \catcode`\\=\other % % Make the characters 128-255 be printing characters. {% \count1=128 \def\loop{% \catcode\count1=\other \advance\count1 by 1 \ifnum \count1<256 \loop \fi }% }% % % @ is our escape character in .aux files, and we need braces. \catcode`\{=1 \catcode`\}=2 \catcode`\@=0 } \def\readdatafile#1{% \begingroup \setupdatafile \input\jobname.#1 \endgroup} \message{insertions,} % including footnotes. \newcount \footnoteno % The trailing space in the following definition for supereject is % vital for proper filling; pages come out unaligned when you do a % pagealignmacro call if that space before the closing brace is % removed. (Generally, numeric constants should always be followed by a % space to prevent strange expansion errors.) \def\supereject{\par\penalty -20000\footnoteno =0 } % @footnotestyle is meaningful for info output only. \let\footnotestyle=\comment {\catcode `\@=11 % % Auto-number footnotes. Otherwise like plain. \gdef\footnote{% \let\indent=\ptexindent \let\noindent=\ptexnoindent \global\advance\footnoteno by \@ne \edef\thisfootno{$^{\the\footnoteno}$}% % % In case the footnote comes at the end of a sentence, preserve the % extra spacing after we do the footnote number. \let\@sf\empty \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi % % Remove inadvertent blank space before typesetting the footnote number. \unskip \thisfootno\@sf \dofootnote }% % Don't bother with the trickery in plain.tex to not require the % footnote text as a parameter. Our footnotes don't need to be so general. % % Oh yes, they do; otherwise, @ifset (and anything else that uses % \parseargline) fails inside footnotes because the tokens are fixed when % the footnote is read. --karl, 16nov96. % \gdef\dofootnote{% \insert\footins\bgroup % We want to typeset this text as a normal paragraph, even if the % footnote reference occurs in (for example) a display environment. % So reset some parameters. \hsize=\pagewidth \interlinepenalty\interfootnotelinepenalty \splittopskip\ht\strutbox % top baseline for broken footnotes \splitmaxdepth\dp\strutbox \floatingpenalty\@MM \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip \parindent\defaultparindent % \smallfonts \rm % % Because we use hanging indentation in footnotes, a @noindent appears % to exdent this text, so make it be a no-op. makeinfo does not use % hanging indentation so @noindent can still be needed within footnote % text after an @example or the like (not that this is good style). \let\noindent = \relax % % Hang the footnote text off the number. Use \everypar in case the % footnote extends for more than one paragraph. \everypar = {\hang}% \textindent{\thisfootno}% % % Don't crash into the line above the footnote text. Since this % expands into a box, it must come within the paragraph, lest it % provide a place where TeX can split the footnote. \footstrut \futurelet\next\fo@t } }%end \catcode `\@=11 % In case a @footnote appears in a vbox, save the footnote text and create % the real \insert just after the vbox finished. Otherwise, the insertion % would be lost. % Similarly, if a @footnote appears inside an alignment, save the footnote % text to a box and make the \insert when a row of the table is finished. % And the same can be done for other insert classes. --kasal, 16nov03. % Replace the \insert primitive by a cheating macro. % Deeper inside, just make sure that the saved insertions are not spilled % out prematurely. % \def\startsavinginserts{% \ifx \insert\ptexinsert \let\insert\saveinsert \else \let\checkinserts\relax \fi } % This \insert replacement works for both \insert\footins{foo} and % \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. % \def\saveinsert#1{% \edef\next{\noexpand\savetobox \makeSAVEname#1}% \afterassignment\next % swallow the left brace \let\temp = } \def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} \def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} \def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} \def\placesaveins#1{% \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname {\box#1}% } % eat @SAVE -- beware, all of them have catcode \other: { \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) \gdef\gobblesave @SAVE{} } % initialization: \def\newsaveins #1{% \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% \next } \def\newsaveinsX #1{% \csname newbox\endcsname #1% \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts \checksaveins #1}% } % initialize: \let\checkinserts\empty \newsaveins\footins \newsaveins\margin % @image. We use the macros from epsf.tex to support this. % If epsf.tex is not installed and @image is used, we complain. % % Check for and read epsf.tex up front. If we read it only at @image % time, we might be inside a group, and then its definitions would get % undone and the next image would fail. \openin 1 = epsf.tex \ifeof 1 \else % Do not bother showing banner with epsf.tex v2.7k (available in % doc/epsf.tex and on ctan). \def\epsfannounce{\toks0 = }% \input epsf.tex \fi \closein 1 % % We will only complain once about lack of epsf.tex. \newif\ifwarnednoepsf \newhelp\noepsfhelp{epsf.tex must be installed for images to work. It is also included in the Texinfo distribution, or you can get it from ftp://tug.org/tex/epsf.tex.} % \def\image#1{% \ifx\epsfbox\undefined \ifwarnednoepsf \else \errhelp = \noepsfhelp \errmessage{epsf.tex not found, images will be ignored}% \global\warnednoepsftrue \fi \else \imagexxx #1,,,,,\finish \fi } % % Arguments to @image: % #1 is (mandatory) image filename; we tack on .eps extension. % #2 is (optional) width, #3 is (optional) height. % #4 is (ignored optional) html alt text. % #5 is (ignored optional) extension. % #6 is just the usual extra ignored arg for parsing this stuff. \newif\ifimagevmode \def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup \catcode`\^^M = 5 % in case we're inside an example \normalturnoffactive % allow _ et al. in names % If the image is by itself, center it. \ifvmode \imagevmodetrue \nobreak\medskip % Usually we'll have text after the image which will insert % \parskip glue, so insert it here too to equalize the space % above and below. \nobreak\vskip\parskip \nobreak \fi % % Leave vertical mode so that indentation from an enclosing % environment such as @quotation is respected. On the other hand, if % it's at the top level, we don't want the normal paragraph indentation. \noindent % % Output the image. \ifpdf \dopdfimage{#1}{#2}{#3}% \else % \epsfbox itself resets \epsf?size at each figure. \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi \epsfbox{#1.eps}% \fi % \ifimagevmode \medskip \fi % space after the standalone image \endgroup} % @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, % etc. We don't actually implement floating yet, we always include the % float "here". But it seemed the best name for the future. % \envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} % There may be a space before second and/or third parameter; delete it. \def\eatcommaspace#1, {#1,} % #1 is the optional FLOATTYPE, the text label for this float, typically % "Figure", "Table", "Example", etc. Can't contain commas. If omitted, % this float will not be numbered and cannot be referred to. % % #2 is the optional xref label. Also must be present for the float to % be referable. % % #3 is the optional positioning argument; for now, it is ignored. It % will somehow specify the positions allowed to float to (here, top, bottom). % % We keep a separate counter for each FLOATTYPE, which we reset at each % chapter-level command. \let\resetallfloatnos=\empty % \def\dofloat#1,#2,#3,#4\finish{% \let\thiscaption=\empty \let\thisshortcaption=\empty % % don't lose footnotes inside @float. % % BEWARE: when the floats start float, we have to issue warning whenever an % insert appears inside a float which could possibly float. --kasal, 26may04 % \startsavinginserts % % We can't be used inside a paragraph. \par % \vtop\bgroup \def\floattype{#1}% \def\floatlabel{#2}% \def\floatloc{#3}% we do nothing with this yet. % \ifx\floattype\empty \let\safefloattype=\empty \else {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% \fi % % If label is given but no type, we handle that as the empty type. \ifx\floatlabel\empty \else % We want each FLOATTYPE to be numbered separately (Figure 1, % Table 1, Figure 2, ...). (And if no label, no number.) % \expandafter\getfloatno\csname\safefloattype floatno\endcsname \global\advance\floatno by 1 % {% % This magic value for \lastsection is output by \setref as the % XREFLABEL-title value. \xrefX uses it to distinguish float % labels (which have a completely different output format) from % node and anchor labels. And \xrdef uses it to construct the % lists of floats. % \edef\lastsection{\floatmagic=\safefloattype}% \setref{\floatlabel}{Yfloat}% }% \fi % % start with \parskip glue, I guess. \vskip\parskip % % Don't suppress indentation if a float happens to start a section. \restorefirstparagraphindent } % we have these possibilities: % @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap % @float Foo,lbl & no caption: Foo 1.1 % @float Foo & @caption{Cap}: Foo: Cap % @float Foo & no caption: Foo % @float ,lbl & Caption{Cap}: 1.1: Cap % @float ,lbl & no caption: 1.1 % @float & @caption{Cap}: Cap % @float & no caption: % \def\Efloat{% \let\floatident = \empty % % In all cases, if we have a float type, it comes first. \ifx\floattype\empty \else \def\floatident{\floattype}\fi % % If we have an xref label, the number comes next. \ifx\floatlabel\empty \else \ifx\floattype\empty \else % if also had float type, need tie first. \appendtomacro\floatident{\tie}% \fi % the number. \appendtomacro\floatident{\chaplevelprefix\the\floatno}% \fi % % Start the printed caption with what we've constructed in % \floatident, but keep it separate; we need \floatident again. \let\captionline = \floatident % \ifx\thiscaption\empty \else \ifx\floatident\empty \else \appendtomacro\captionline{: }% had ident, so need a colon between \fi % % caption text. \appendtomacro\captionline{\scanexp\thiscaption}% \fi % % If we have anything to print, print it, with space before. % Eventually this needs to become an \insert. \ifx\captionline\empty \else \vskip.5\parskip \captionline % % Space below caption. \vskip\parskip \fi % % If have an xref label, write the list of floats info. Do this % after the caption, to avoid chance of it being a breakpoint. \ifx\floatlabel\empty \else % Write the text that goes in the lof to the aux file as % \floatlabel-lof. Besides \floatident, we include the short % caption if specified, else the full caption if specified, else nothing. {% \atdummies % % since we read the caption text in the macro world, where ^^M % is turned into a normal character, we have to scan it back, so % we don't write the literal three characters "^^M" into the aux file. \scanexp{% \xdef\noexpand\gtemp{% \ifx\thisshortcaption\empty \thiscaption \else \thisshortcaption \fi }% }% \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident \ifx\gtemp\empty \else : \gtemp \fi}}% }% \fi \egroup % end of \vtop % % place the captured inserts % % BEWARE: when the floats start floating, we have to issue warning % whenever an insert appears inside a float which could possibly % float. --kasal, 26may04 % \checkinserts } % Append the tokens #2 to the definition of macro #1, not expanding either. % \def\appendtomacro#1#2{% \expandafter\def\expandafter#1\expandafter{#1#2}% } % @caption, @shortcaption % \def\caption{\docaption\thiscaption} \def\shortcaption{\docaption\thisshortcaption} \def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} \def\defcaption#1#2{\egroup \def#1{#2}} % The parameter is the control sequence identifying the counter we are % going to use. Create it if it doesn't exist and assign it to \floatno. \def\getfloatno#1{% \ifx#1\relax % Haven't seen this figure type before. \csname newcount\endcsname #1% % % Remember to reset this floatno at the next chap. \expandafter\gdef\expandafter\resetallfloatnos \expandafter{\resetallfloatnos #1=0 }% \fi \let\floatno#1% } % \setref calls this to get the XREFLABEL-snt value. We want an @xref % to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we % first read the @float command. % \def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% % Magic string used for the XREFLABEL-title value, so \xrefX can % distinguish floats from other xref types. \def\floatmagic{!!float!!} % #1 is the control sequence we are passed; we expand into a conditional % which is true if #1 represents a float ref. That is, the magic % \lastsection value which we \setref above. % \def\iffloat#1{\expandafter\doiffloat#1==\finish} % % #1 is (maybe) the \floatmagic string. If so, #2 will be the % (safe) float type for this float. We set \iffloattype to #2. % \def\doiffloat#1=#2=#3\finish{% \def\temp{#1}% \def\iffloattype{#2}% \ifx\temp\floatmagic } % @listoffloats FLOATTYPE - print a list of floats like a table of contents. % \parseargdef\listoffloats{% \def\floattype{#1}% floattype {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% % % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax \ifhavexrefs % if the user said @listoffloats foo but never @float foo. \message{\linenumber No `\safefloattype' floats to list.}% \fi \else \begingroup \leftskip=\tocindent % indent these entries like a toc \let\do=\listoffloatsdo \csname floatlist\safefloattype\endcsname \endgroup \fi } % This is called on each entry in a list of floats. We're passed the % xref label, in the form LABEL-title, which is how we save it in the % aux file. We strip off the -title and look up \XRLABEL-lof, which % has the text we're supposed to typeset here. % % Figures without xref labels will not be included in the list (since % they won't appear in the aux file). % \def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} \def\listoffloatsdoentry#1-title\finish{{% % Can't fully expand XR#1-lof because it can contain anything. Just % pass the control sequence. On the other hand, XR#1-pg is just the % page number, and we want to fully expand that so we can get a link % in pdf output. \toksA = \expandafter{\csname XR#1-lof\endcsname}% % % use the same \entry macro we use to generate the TOC and index. \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% \writeentry }} \message{localization,} % For single-language documents, @documentlanguage is usually given very % early, just after @documentencoding. Single argument is the language % (de) or locale (de_DE) abbreviation. % { \catcode`\_ = \active \globaldefs=1 \parseargdef\documentlanguage{\begingroup \let_=\normalunderscore % normal _ character for filenames \tex % read txi-??.tex file in plain TeX. % Read the file by the name they passed if it exists. \openin 1 txi-#1.tex \ifeof 1 \documentlanguagetrywithoutunderscore{#1_\finish}% \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 \endgroup % end raw TeX \endgroup} % % If they passed de_DE, and txi-de_DE.tex doesn't exist, % try txi-de.tex. % \gdef\documentlanguagetrywithoutunderscore#1_#2\finish{% \openin 1 txi-#1.tex \ifeof 1 \errhelp = \nolanghelp \errmessage{Cannot read language file txi-#1.tex}% \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 } }% end of special _ catcode % \newhelp\nolanghelp{The given language definition file cannot be found or is empty. Maybe you need to install it? Putting it in the current directory should work if nowhere else does.} % This macro is called from txi-??.tex files; the first argument is the % \language name to set (without the "\lang@" prefix), the second and % third args are \{left,right}hyphenmin. % % The language names to pass are determined when the format is built. % See the etex.log file created at that time, e.g., % /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log. % % With TeX Live 2008, etex now includes hyphenation patterns for all % available languages. This means we can support hyphenation in % Texinfo, at least to some extent. (This still doesn't solve the % accented characters problem.) % \catcode`@=11 \def\txisetlanguage#1#2#3{% % do not set the language if the name is undefined in the current TeX. \expandafter\ifx\csname lang@#1\endcsname \relax \message{no patterns for #1}% \else \global\language = \csname lang@#1\endcsname \fi % but there is no harm in adjusting the hyphenmin values regardless. \global\lefthyphenmin = #2\relax \global\righthyphenmin = #3\relax } % Helpers for encodings. % Set the catcode of characters 128 through 255 to the specified number. % \def\setnonasciicharscatcode#1{% \count255=128 \loop\ifnum\count255<256 \global\catcode\count255=#1\relax \advance\count255 by 1 \repeat } \def\setnonasciicharscatcodenonglobal#1{% \count255=128 \loop\ifnum\count255<256 \catcode\count255=#1\relax \advance\count255 by 1 \repeat } % @documentencoding sets the definition of non-ASCII characters % according to the specified encoding. % \parseargdef\documentencoding{% % Encoding being declared for the document. \def\declaredencoding{\csname #1.enc\endcsname}% % % Supported encodings: names converted to tokens in order to be able % to compare them with \ifx. \def\ascii{\csname US-ASCII.enc\endcsname}% \def\latnine{\csname ISO-8859-15.enc\endcsname}% \def\latone{\csname ISO-8859-1.enc\endcsname}% \def\lattwo{\csname ISO-8859-2.enc\endcsname}% \def\utfeight{\csname UTF-8.enc\endcsname}% % \ifx \declaredencoding \ascii \asciichardefs % \else \ifx \declaredencoding \lattwo \setnonasciicharscatcode\active \lattwochardefs % \else \ifx \declaredencoding \latone \setnonasciicharscatcode\active \latonechardefs % \else \ifx \declaredencoding \latnine \setnonasciicharscatcode\active \latninechardefs % \else \ifx \declaredencoding \utfeight \setnonasciicharscatcode\active \utfeightchardefs % \else \message{Unknown document encoding #1, ignoring.}% % \fi % utfeight \fi % latnine \fi % latone \fi % lattwo \fi % ascii } % A message to be logged when using a character that isn't available % the default font encoding (OT1). % \def\missingcharmsg#1{\message{Character missing in OT1 encoding: #1.}} % Take account of \c (plain) vs. \, (Texinfo) difference. \def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} % First, make active non-ASCII characters in order for them to be % correctly categorized when TeX reads the replacement text of % macros containing the character definitions. \setnonasciicharscatcode\active % % Latin1 (ISO-8859-1) character definitions. \def\latonechardefs{% \gdef^^a0{~} \gdef^^a1{\exclamdown} \gdef^^a2{\missingcharmsg{CENT SIGN}} \gdef^^a3{{\pounds}} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\missingcharmsg{YEN SIGN}} \gdef^^a6{\missingcharmsg{BROKEN BAR}} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\copyright} \gdef^^aa{\ordf} \gdef^^ab{\guillemetleft} \gdef^^ac{$\lnot$} \gdef^^ad{\-} \gdef^^ae{\registeredsymbol} \gdef^^af{\={}} % \gdef^^b0{\textdegree} \gdef^^b1{$\pm$} \gdef^^b2{$^2$} \gdef^^b3{$^3$} \gdef^^b4{\'{}} \gdef^^b5{$\mu$} \gdef^^b6{\P} % \gdef^^b7{$^.$} \gdef^^b8{\cedilla\ } \gdef^^b9{$^1$} \gdef^^ba{\ordm} % \gdef^^bb{\guilletright} \gdef^^bc{$1\over4$} \gdef^^bd{$1\over2$} \gdef^^be{$3\over4$} \gdef^^bf{\questiondown} % \gdef^^c0{\`A} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\~A} \gdef^^c4{\"A} \gdef^^c5{\ringaccent A} \gdef^^c6{\AE} \gdef^^c7{\cedilla C} \gdef^^c8{\`E} \gdef^^c9{\'E} \gdef^^ca{\^E} \gdef^^cb{\"E} \gdef^^cc{\`I} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\"I} % \gdef^^d0{\DH} \gdef^^d1{\~N} \gdef^^d2{\`O} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\~O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\O} \gdef^^d9{\`U} \gdef^^da{\'U} \gdef^^db{\^U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\TH} \gdef^^df{\ss} % \gdef^^e0{\`a} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\~a} \gdef^^e4{\"a} \gdef^^e5{\ringaccent a} \gdef^^e6{\ae} \gdef^^e7{\cedilla c} \gdef^^e8{\`e} \gdef^^e9{\'e} \gdef^^ea{\^e} \gdef^^eb{\"e} \gdef^^ec{\`{\dotless i}} \gdef^^ed{\'{\dotless i}} \gdef^^ee{\^{\dotless i}} \gdef^^ef{\"{\dotless i}} % \gdef^^f0{\dh} \gdef^^f1{\~n} \gdef^^f2{\`o} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\~o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\o} \gdef^^f9{\`u} \gdef^^fa{\'u} \gdef^^fb{\^u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\th} \gdef^^ff{\"y} } % Latin9 (ISO-8859-15) encoding character definitions. \def\latninechardefs{% % Encoding is almost identical to Latin1. \latonechardefs % \gdef^^a4{\euro} \gdef^^a6{\v S} \gdef^^a8{\v s} \gdef^^b4{\v Z} \gdef^^b8{\v z} \gdef^^bc{\OE} \gdef^^bd{\oe} \gdef^^be{\"Y} } % Latin2 (ISO-8859-2) character definitions. \def\lattwochardefs{% \gdef^^a0{~} \gdef^^a1{\ogonek{A}} \gdef^^a2{\u{}} \gdef^^a3{\L} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\v L} \gdef^^a6{\'S} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\v S} \gdef^^aa{\cedilla S} \gdef^^ab{\v T} \gdef^^ac{\'Z} \gdef^^ad{\-} \gdef^^ae{\v Z} \gdef^^af{\dotaccent Z} % \gdef^^b0{\textdegree} \gdef^^b1{\ogonek{a}} \gdef^^b2{\ogonek{ }} \gdef^^b3{\l} \gdef^^b4{\'{}} \gdef^^b5{\v l} \gdef^^b6{\'s} \gdef^^b7{\v{}} \gdef^^b8{\cedilla\ } \gdef^^b9{\v s} \gdef^^ba{\cedilla s} \gdef^^bb{\v t} \gdef^^bc{\'z} \gdef^^bd{\H{}} \gdef^^be{\v z} \gdef^^bf{\dotaccent z} % \gdef^^c0{\'R} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\u A} \gdef^^c4{\"A} \gdef^^c5{\'L} \gdef^^c6{\'C} \gdef^^c7{\cedilla C} \gdef^^c8{\v C} \gdef^^c9{\'E} \gdef^^ca{\ogonek{E}} \gdef^^cb{\"E} \gdef^^cc{\v E} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\v D} % \gdef^^d0{\DH} \gdef^^d1{\'N} \gdef^^d2{\v N} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\H O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\v R} \gdef^^d9{\ringaccent U} \gdef^^da{\'U} \gdef^^db{\H U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\cedilla T} \gdef^^df{\ss} % \gdef^^e0{\'r} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\u a} \gdef^^e4{\"a} \gdef^^e5{\'l} \gdef^^e6{\'c} \gdef^^e7{\cedilla c} \gdef^^e8{\v c} \gdef^^e9{\'e} \gdef^^ea{\ogonek{e}} \gdef^^eb{\"e} \gdef^^ec{\v e} \gdef^^ed{\'\i} \gdef^^ee{\^\i} \gdef^^ef{\v d} % \gdef^^f0{\dh} \gdef^^f1{\'n} \gdef^^f2{\v n} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\H o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\v r} \gdef^^f9{\ringaccent u} \gdef^^fa{\'u} \gdef^^fb{\H u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\cedilla t} \gdef^^ff{\dotaccent{}} } % UTF-8 character definitions. % % This code to support UTF-8 is based on LaTeX's utf8.def, with some % changes for Texinfo conventions. It is included here under the GPL by % permission from Frank Mittelbach and the LaTeX team. % \newcount\countUTFx \newcount\countUTFy \newcount\countUTFz \gdef\UTFviiiTwoOctets#1#2{\expandafter \UTFviiiDefined\csname u8:#1\string #2\endcsname} % \gdef\UTFviiiThreeOctets#1#2#3{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} % \gdef\UTFviiiFourOctets#1#2#3#4{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} \gdef\UTFviiiDefined#1{% \ifx #1\relax \message{\linenumber Unicode char \string #1 not defined for Texinfo}% \else \expandafter #1% \fi } \begingroup \catcode`\~13 \catcode`\"12 \def\UTFviiiLoop{% \global\catcode\countUTFx\active \uccode`\~\countUTFx \uppercase\expandafter{\UTFviiiTmp}% \advance\countUTFx by 1 \ifnum\countUTFx < \countUTFy \expandafter\UTFviiiLoop \fi} \countUTFx = "C2 \countUTFy = "E0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiTwoOctets\string~}} \UTFviiiLoop \countUTFx = "E0 \countUTFy = "F0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiThreeOctets\string~}} \UTFviiiLoop \countUTFx = "F0 \countUTFy = "F4 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiFourOctets\string~}} \UTFviiiLoop \endgroup \begingroup \catcode`\"=12 \catcode`\<=12 \catcode`\.=12 \catcode`\,=12 \catcode`\;=12 \catcode`\!=12 \catcode`\~=13 \gdef\DeclareUnicodeCharacter#1#2{% \countUTFz = "#1\relax \wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% \begingroup \parseXMLCharref \def\UTFviiiTwoOctets##1##2{% \csname u8:##1\string ##2\endcsname}% \def\UTFviiiThreeOctets##1##2##3{% \csname u8:##1\string ##2\string ##3\endcsname}% \def\UTFviiiFourOctets##1##2##3##4{% \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter \gdef\UTFviiiTmp{#2}% \endgroup} \gdef\parseXMLCharref{% \ifnum\countUTFz < "A0\relax \errhelp = \EMsimple \errmessage{Cannot define Unicode char value < 00A0}% \else\ifnum\countUTFz < "800\relax \parseUTFviiiA,% \parseUTFviiiB C\UTFviiiTwoOctets.,% \else\ifnum\countUTFz < "10000\relax \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% \else \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiA!% \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% \fi\fi\fi } \gdef\parseUTFviiiA#1{% \countUTFx = \countUTFz \divide\countUTFz by 64 \countUTFy = \countUTFz \multiply\countUTFz by 64 \advance\countUTFx by -\countUTFz \advance\countUTFx by 128 \uccode `#1\countUTFx \countUTFz = \countUTFy} \gdef\parseUTFviiiB#1#2#3#4{% \advance\countUTFz by "#10\relax \uccode `#3\countUTFz \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} \endgroup \def\utfeightchardefs{% \DeclareUnicodeCharacter{00A0}{\tie} \DeclareUnicodeCharacter{00A1}{\exclamdown} \DeclareUnicodeCharacter{00A3}{\pounds} \DeclareUnicodeCharacter{00A8}{\"{ }} \DeclareUnicodeCharacter{00A9}{\copyright} \DeclareUnicodeCharacter{00AA}{\ordf} \DeclareUnicodeCharacter{00AB}{\guillemetleft} \DeclareUnicodeCharacter{00AD}{\-} \DeclareUnicodeCharacter{00AE}{\registeredsymbol} \DeclareUnicodeCharacter{00AF}{\={ }} \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} \DeclareUnicodeCharacter{00B4}{\'{ }} \DeclareUnicodeCharacter{00B8}{\cedilla{ }} \DeclareUnicodeCharacter{00BA}{\ordm} \DeclareUnicodeCharacter{00BB}{\guillemetright} \DeclareUnicodeCharacter{00BF}{\questiondown} \DeclareUnicodeCharacter{00C0}{\`A} \DeclareUnicodeCharacter{00C1}{\'A} \DeclareUnicodeCharacter{00C2}{\^A} \DeclareUnicodeCharacter{00C3}{\~A} \DeclareUnicodeCharacter{00C4}{\"A} \DeclareUnicodeCharacter{00C5}{\AA} \DeclareUnicodeCharacter{00C6}{\AE} \DeclareUnicodeCharacter{00C7}{\cedilla{C}} \DeclareUnicodeCharacter{00C8}{\`E} \DeclareUnicodeCharacter{00C9}{\'E} \DeclareUnicodeCharacter{00CA}{\^E} \DeclareUnicodeCharacter{00CB}{\"E} \DeclareUnicodeCharacter{00CC}{\`I} \DeclareUnicodeCharacter{00CD}{\'I} \DeclareUnicodeCharacter{00CE}{\^I} \DeclareUnicodeCharacter{00CF}{\"I} \DeclareUnicodeCharacter{00D0}{\DH} \DeclareUnicodeCharacter{00D1}{\~N} \DeclareUnicodeCharacter{00D2}{\`O} \DeclareUnicodeCharacter{00D3}{\'O} \DeclareUnicodeCharacter{00D4}{\^O} \DeclareUnicodeCharacter{00D5}{\~O} \DeclareUnicodeCharacter{00D6}{\"O} \DeclareUnicodeCharacter{00D8}{\O} \DeclareUnicodeCharacter{00D9}{\`U} \DeclareUnicodeCharacter{00DA}{\'U} \DeclareUnicodeCharacter{00DB}{\^U} \DeclareUnicodeCharacter{00DC}{\"U} \DeclareUnicodeCharacter{00DD}{\'Y} \DeclareUnicodeCharacter{00DE}{\TH} \DeclareUnicodeCharacter{00DF}{\ss} \DeclareUnicodeCharacter{00E0}{\`a} \DeclareUnicodeCharacter{00E1}{\'a} \DeclareUnicodeCharacter{00E2}{\^a} \DeclareUnicodeCharacter{00E3}{\~a} \DeclareUnicodeCharacter{00E4}{\"a} \DeclareUnicodeCharacter{00E5}{\aa} \DeclareUnicodeCharacter{00E6}{\ae} \DeclareUnicodeCharacter{00E7}{\cedilla{c}} \DeclareUnicodeCharacter{00E8}{\`e} \DeclareUnicodeCharacter{00E9}{\'e} \DeclareUnicodeCharacter{00EA}{\^e} \DeclareUnicodeCharacter{00EB}{\"e} \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} \DeclareUnicodeCharacter{00F0}{\dh} \DeclareUnicodeCharacter{00F1}{\~n} \DeclareUnicodeCharacter{00F2}{\`o} \DeclareUnicodeCharacter{00F3}{\'o} \DeclareUnicodeCharacter{00F4}{\^o} \DeclareUnicodeCharacter{00F5}{\~o} \DeclareUnicodeCharacter{00F6}{\"o} \DeclareUnicodeCharacter{00F8}{\o} \DeclareUnicodeCharacter{00F9}{\`u} \DeclareUnicodeCharacter{00FA}{\'u} \DeclareUnicodeCharacter{00FB}{\^u} \DeclareUnicodeCharacter{00FC}{\"u} \DeclareUnicodeCharacter{00FD}{\'y} \DeclareUnicodeCharacter{00FE}{\th} \DeclareUnicodeCharacter{00FF}{\"y} \DeclareUnicodeCharacter{0100}{\=A} \DeclareUnicodeCharacter{0101}{\=a} \DeclareUnicodeCharacter{0102}{\u{A}} \DeclareUnicodeCharacter{0103}{\u{a}} \DeclareUnicodeCharacter{0104}{\ogonek{A}} \DeclareUnicodeCharacter{0105}{\ogonek{a}} \DeclareUnicodeCharacter{0106}{\'C} \DeclareUnicodeCharacter{0107}{\'c} \DeclareUnicodeCharacter{0108}{\^C} \DeclareUnicodeCharacter{0109}{\^c} \DeclareUnicodeCharacter{0118}{\ogonek{E}} \DeclareUnicodeCharacter{0119}{\ogonek{e}} \DeclareUnicodeCharacter{010A}{\dotaccent{C}} \DeclareUnicodeCharacter{010B}{\dotaccent{c}} \DeclareUnicodeCharacter{010C}{\v{C}} \DeclareUnicodeCharacter{010D}{\v{c}} \DeclareUnicodeCharacter{010E}{\v{D}} \DeclareUnicodeCharacter{0112}{\=E} \DeclareUnicodeCharacter{0113}{\=e} \DeclareUnicodeCharacter{0114}{\u{E}} \DeclareUnicodeCharacter{0115}{\u{e}} \DeclareUnicodeCharacter{0116}{\dotaccent{E}} \DeclareUnicodeCharacter{0117}{\dotaccent{e}} \DeclareUnicodeCharacter{011A}{\v{E}} \DeclareUnicodeCharacter{011B}{\v{e}} \DeclareUnicodeCharacter{011C}{\^G} \DeclareUnicodeCharacter{011D}{\^g} \DeclareUnicodeCharacter{011E}{\u{G}} \DeclareUnicodeCharacter{011F}{\u{g}} \DeclareUnicodeCharacter{0120}{\dotaccent{G}} \DeclareUnicodeCharacter{0121}{\dotaccent{g}} \DeclareUnicodeCharacter{0124}{\^H} \DeclareUnicodeCharacter{0125}{\^h} \DeclareUnicodeCharacter{0128}{\~I} \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} \DeclareUnicodeCharacter{012A}{\=I} \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} \DeclareUnicodeCharacter{012C}{\u{I}} \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} \DeclareUnicodeCharacter{0130}{\dotaccent{I}} \DeclareUnicodeCharacter{0131}{\dotless{i}} \DeclareUnicodeCharacter{0132}{IJ} \DeclareUnicodeCharacter{0133}{ij} \DeclareUnicodeCharacter{0134}{\^J} \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} \DeclareUnicodeCharacter{0139}{\'L} \DeclareUnicodeCharacter{013A}{\'l} \DeclareUnicodeCharacter{0141}{\L} \DeclareUnicodeCharacter{0142}{\l} \DeclareUnicodeCharacter{0143}{\'N} \DeclareUnicodeCharacter{0144}{\'n} \DeclareUnicodeCharacter{0147}{\v{N}} \DeclareUnicodeCharacter{0148}{\v{n}} \DeclareUnicodeCharacter{014C}{\=O} \DeclareUnicodeCharacter{014D}{\=o} \DeclareUnicodeCharacter{014E}{\u{O}} \DeclareUnicodeCharacter{014F}{\u{o}} \DeclareUnicodeCharacter{0150}{\H{O}} \DeclareUnicodeCharacter{0151}{\H{o}} \DeclareUnicodeCharacter{0152}{\OE} \DeclareUnicodeCharacter{0153}{\oe} \DeclareUnicodeCharacter{0154}{\'R} \DeclareUnicodeCharacter{0155}{\'r} \DeclareUnicodeCharacter{0158}{\v{R}} \DeclareUnicodeCharacter{0159}{\v{r}} \DeclareUnicodeCharacter{015A}{\'S} \DeclareUnicodeCharacter{015B}{\'s} \DeclareUnicodeCharacter{015C}{\^S} \DeclareUnicodeCharacter{015D}{\^s} \DeclareUnicodeCharacter{015E}{\cedilla{S}} \DeclareUnicodeCharacter{015F}{\cedilla{s}} \DeclareUnicodeCharacter{0160}{\v{S}} \DeclareUnicodeCharacter{0161}{\v{s}} \DeclareUnicodeCharacter{0162}{\cedilla{t}} \DeclareUnicodeCharacter{0163}{\cedilla{T}} \DeclareUnicodeCharacter{0164}{\v{T}} \DeclareUnicodeCharacter{0168}{\~U} \DeclareUnicodeCharacter{0169}{\~u} \DeclareUnicodeCharacter{016A}{\=U} \DeclareUnicodeCharacter{016B}{\=u} \DeclareUnicodeCharacter{016C}{\u{U}} \DeclareUnicodeCharacter{016D}{\u{u}} \DeclareUnicodeCharacter{016E}{\ringaccent{U}} \DeclareUnicodeCharacter{016F}{\ringaccent{u}} \DeclareUnicodeCharacter{0170}{\H{U}} \DeclareUnicodeCharacter{0171}{\H{u}} \DeclareUnicodeCharacter{0174}{\^W} \DeclareUnicodeCharacter{0175}{\^w} \DeclareUnicodeCharacter{0176}{\^Y} \DeclareUnicodeCharacter{0177}{\^y} \DeclareUnicodeCharacter{0178}{\"Y} \DeclareUnicodeCharacter{0179}{\'Z} \DeclareUnicodeCharacter{017A}{\'z} \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} \DeclareUnicodeCharacter{017C}{\dotaccent{z}} \DeclareUnicodeCharacter{017D}{\v{Z}} \DeclareUnicodeCharacter{017E}{\v{z}} \DeclareUnicodeCharacter{01C4}{D\v{Z}} \DeclareUnicodeCharacter{01C5}{D\v{z}} \DeclareUnicodeCharacter{01C6}{d\v{z}} \DeclareUnicodeCharacter{01C7}{LJ} \DeclareUnicodeCharacter{01C8}{Lj} \DeclareUnicodeCharacter{01C9}{lj} \DeclareUnicodeCharacter{01CA}{NJ} \DeclareUnicodeCharacter{01CB}{Nj} \DeclareUnicodeCharacter{01CC}{nj} \DeclareUnicodeCharacter{01CD}{\v{A}} \DeclareUnicodeCharacter{01CE}{\v{a}} \DeclareUnicodeCharacter{01CF}{\v{I}} \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} \DeclareUnicodeCharacter{01D1}{\v{O}} \DeclareUnicodeCharacter{01D2}{\v{o}} \DeclareUnicodeCharacter{01D3}{\v{U}} \DeclareUnicodeCharacter{01D4}{\v{u}} \DeclareUnicodeCharacter{01E2}{\={\AE}} \DeclareUnicodeCharacter{01E3}{\={\ae}} \DeclareUnicodeCharacter{01E6}{\v{G}} \DeclareUnicodeCharacter{01E7}{\v{g}} \DeclareUnicodeCharacter{01E8}{\v{K}} \DeclareUnicodeCharacter{01E9}{\v{k}} \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} \DeclareUnicodeCharacter{01F1}{DZ} \DeclareUnicodeCharacter{01F2}{Dz} \DeclareUnicodeCharacter{01F3}{dz} \DeclareUnicodeCharacter{01F4}{\'G} \DeclareUnicodeCharacter{01F5}{\'g} \DeclareUnicodeCharacter{01F8}{\`N} \DeclareUnicodeCharacter{01F9}{\`n} \DeclareUnicodeCharacter{01FC}{\'{\AE}} \DeclareUnicodeCharacter{01FD}{\'{\ae}} \DeclareUnicodeCharacter{01FE}{\'{\O}} \DeclareUnicodeCharacter{01FF}{\'{\o}} \DeclareUnicodeCharacter{021E}{\v{H}} \DeclareUnicodeCharacter{021F}{\v{h}} \DeclareUnicodeCharacter{0226}{\dotaccent{A}} \DeclareUnicodeCharacter{0227}{\dotaccent{a}} \DeclareUnicodeCharacter{0228}{\cedilla{E}} \DeclareUnicodeCharacter{0229}{\cedilla{e}} \DeclareUnicodeCharacter{022E}{\dotaccent{O}} \DeclareUnicodeCharacter{022F}{\dotaccent{o}} \DeclareUnicodeCharacter{0232}{\=Y} \DeclareUnicodeCharacter{0233}{\=y} \DeclareUnicodeCharacter{0237}{\dotless{j}} \DeclareUnicodeCharacter{02DB}{\ogonek{ }} \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} \DeclareUnicodeCharacter{1E20}{\=G} \DeclareUnicodeCharacter{1E21}{\=g} \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} \DeclareUnicodeCharacter{1E26}{\"H} \DeclareUnicodeCharacter{1E27}{\"h} \DeclareUnicodeCharacter{1E30}{\'K} \DeclareUnicodeCharacter{1E31}{\'k} \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} \DeclareUnicodeCharacter{1E3E}{\'M} \DeclareUnicodeCharacter{1E3F}{\'m} \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} \DeclareUnicodeCharacter{1E54}{\'P} \DeclareUnicodeCharacter{1E55}{\'p} \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} \DeclareUnicodeCharacter{1E7C}{\~V} \DeclareUnicodeCharacter{1E7D}{\~v} \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} \DeclareUnicodeCharacter{1E80}{\`W} \DeclareUnicodeCharacter{1E81}{\`w} \DeclareUnicodeCharacter{1E82}{\'W} \DeclareUnicodeCharacter{1E83}{\'w} \DeclareUnicodeCharacter{1E84}{\"W} \DeclareUnicodeCharacter{1E85}{\"w} \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} \DeclareUnicodeCharacter{1E8C}{\"X} \DeclareUnicodeCharacter{1E8D}{\"x} \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} \DeclareUnicodeCharacter{1E90}{\^Z} \DeclareUnicodeCharacter{1E91}{\^z} \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} \DeclareUnicodeCharacter{1E97}{\"t} \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} \DeclareUnicodeCharacter{1EBC}{\~E} \DeclareUnicodeCharacter{1EBD}{\~e} \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} \DeclareUnicodeCharacter{1EF2}{\`Y} \DeclareUnicodeCharacter{1EF3}{\`y} \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} \DeclareUnicodeCharacter{1EF8}{\~Y} \DeclareUnicodeCharacter{1EF9}{\~y} \DeclareUnicodeCharacter{2013}{--} \DeclareUnicodeCharacter{2014}{---} \DeclareUnicodeCharacter{2018}{\quoteleft} \DeclareUnicodeCharacter{2019}{\quoteright} \DeclareUnicodeCharacter{201A}{\quotesinglbase} \DeclareUnicodeCharacter{201C}{\quotedblleft} \DeclareUnicodeCharacter{201D}{\quotedblright} \DeclareUnicodeCharacter{201E}{\quotedblbase} \DeclareUnicodeCharacter{2022}{\bullet} \DeclareUnicodeCharacter{2026}{\dots} \DeclareUnicodeCharacter{2039}{\guilsinglleft} \DeclareUnicodeCharacter{203A}{\guilsinglright} \DeclareUnicodeCharacter{20AC}{\euro} \DeclareUnicodeCharacter{2192}{\expansion} \DeclareUnicodeCharacter{21D2}{\result} \DeclareUnicodeCharacter{2212}{\minus} \DeclareUnicodeCharacter{2217}{\point} \DeclareUnicodeCharacter{2261}{\equiv} }% end of \utfeightchardefs % US-ASCII character definitions. \def\asciichardefs{% nothing need be done \relax } % Make non-ASCII characters printable again for compatibility with % existing Texinfo documents that may use them, even without declaring a % document encoding. % \setnonasciicharscatcode \other \message{formatting,} \newdimen\defaultparindent \defaultparindent = 15pt \chapheadingskip = 15pt plus 4pt minus 2pt \secheadingskip = 12pt plus 3pt minus 2pt \subsecheadingskip = 9pt plus 2pt minus 2pt % Prevent underfull vbox error messages. \vbadness = 10000 % Don't be so finicky about underfull hboxes, either. \hbadness = 2000 % Following George Bush, get rid of widows and orphans. \widowpenalty=10000 \clubpenalty=10000 % Use TeX 3.0's \emergencystretch to help line breaking, but if we're % using an old version of TeX, don't do anything. We want the amount of % stretch added to depend on the line length, hence the dependence on % \hsize. We call this whenever the paper size is set. % \def\setemergencystretch{% \ifx\emergencystretch\thisisundefined % Allow us to assign to \emergencystretch anyway. \def\emergencystretch{\dimen0}% \else \emergencystretch = .15\hsize \fi } % Parameters in order: 1) textheight; 2) textwidth; % 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; % 7) physical page height; 8) physical page width. % % We also call \setleading{\textleading}, so the caller should define % \textleading. The caller should also set \parskip. % \def\internalpagesizes#1#2#3#4#5#6#7#8{% \voffset = #3\relax \topskip = #6\relax \splittopskip = \topskip % \vsize = #1\relax \advance\vsize by \topskip \outervsize = \vsize \advance\outervsize by 2\topandbottommargin \pageheight = \vsize % \hsize = #2\relax \outerhsize = \hsize \advance\outerhsize by 0.5in \pagewidth = \hsize % \normaloffset = #4\relax \bindingoffset = #5\relax % \ifpdf \pdfpageheight #7\relax \pdfpagewidth #8\relax % if we don't reset these, they will remain at "1 true in" of % whatever layout pdftex was dumped with. \pdfhorigin = 1 true in \pdfvorigin = 1 true in \fi % \setleading{\textleading} % \parindent = \defaultparindent \setemergencystretch } % @letterpaper (the default). \def\letterpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % If page is nothing but text, make it come out even. \internalpagesizes{607.2pt}{6in}% that's 46 lines {\voffset}{.25in}% {\bindingoffset}{36pt}% {11in}{8.5in}% }} % Use @smallbook to reset parameters for 7x9.25 trim size. \def\smallbook{{\globaldefs = 1 \parskip = 2pt plus 1pt \textleading = 12pt % \internalpagesizes{7.5in}{5in}% {-.2in}{0in}% {\bindingoffset}{16pt}% {9.25in}{7in}% % \lispnarrowing = 0.3in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .5cm }} % Use @smallerbook to reset parameters for 6x9 trim size. % (Just testing, parameters still in flux.) \def\smallerbook{{\globaldefs = 1 \parskip = 1.5pt plus 1pt \textleading = 12pt % \internalpagesizes{7.4in}{4.8in}% {-.2in}{-.4in}% {0pt}{14pt}% {9in}{6in}% % \lispnarrowing = 0.25in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .4cm }} % Use @afourpaper to print on European A4 paper. \def\afourpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % Double-side printing via postscript on Laserjet 4050 % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. % To change the settings for a different printer or situation, adjust % \normaloffset until the front-side and back-side texts align. Then % do the same for \bindingoffset. You can set these for testing in % your texinfo source file like this: % @tex % \global\normaloffset = -6mm % \global\bindingoffset = 10mm % @end tex \internalpagesizes{673.2pt}{160mm}% that's 51 lines {\voffset}{\hoffset}% {\bindingoffset}{44pt}% {297mm}{210mm}% % \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = 5mm }} % Use @afivepaper to print on European A5 paper. % From romildo@urano.iceb.ufop.br, 2 July 2000. % He also recommends making @example and @lisp be small. \def\afivepaper{{\globaldefs = 1 \parskip = 2pt plus 1pt minus 0.1pt \textleading = 12.5pt % \internalpagesizes{160mm}{120mm}% {\voffset}{\hoffset}% {\bindingoffset}{8pt}% {210mm}{148mm}% % \lispnarrowing = 0.2in \tolerance = 800 \hfuzz = 1.2pt \contentsrightmargin = 0pt \defbodyindent = 2mm \tableindent = 12mm }} % A specific text layout, 24x15cm overall, intended for A4 paper. \def\afourlatex{{\globaldefs = 1 \afourpaper \internalpagesizes{237mm}{150mm}% {\voffset}{4.6mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% % % Must explicitly reset to 0 because we call \afourpaper. \globaldefs = 0 }} % Use @afourwide to print on A4 paper in landscape format. \def\afourwide{{\globaldefs = 1 \afourpaper \internalpagesizes{241mm}{165mm}% {\voffset}{-2.95mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% \globaldefs = 0 }} % @pagesizes TEXTHEIGHT[,TEXTWIDTH] % Perhaps we should allow setting the margins, \topskip, \parskip, % and/or leading, also. Or perhaps we should compute them somehow. % \parseargdef\pagesizes{\pagesizesyyy #1,,\finish} \def\pagesizesyyy#1,#2,#3\finish{{% \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi \globaldefs = 1 % \parskip = 3pt plus 2pt minus 1pt \setleading{\textleading}% % \dimen0 = #1\relax \advance\dimen0 by \voffset % \dimen2 = \hsize \advance\dimen2 by \normaloffset % \internalpagesizes{#1}{\hsize}% {\voffset}{\normaloffset}% {\bindingoffset}{44pt}% {\dimen0}{\dimen2}% }} % Set default to letter. % \letterpaper \message{and turning on texinfo input format.} % DEL is a comment character, in case @c does not suffice. \catcode`\^^? = 14 % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \catcode`\~=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\+=\other \catcode`\$=\other \def\normaldoublequote{"} \def\normaltilde{~} \def\normalcaret{^} \def\normalunderscore{_} \def\normalverticalbar{|} \def\normalless{<} \def\normalgreater{>} \def\normalplus{+} \def\normaldollar{$}%$ font-lock fix % This macro is used to make a character print one way in \tt % (where it can probably be output as-is), and another way in other fonts, % where something hairier probably needs to be done. % % #1 is what to print if we are indeed using \tt; #2 is what to print % otherwise. Since all the Computer Modern typewriter fonts have zero % interword stretch (and shrink), and it is reasonable to expect all % typewriter fonts to have this, we can check that font parameter. % \def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} % Same as above, but check for italic font. Actually this also catches % non-italic slanted fonts since it is impossible to distinguish them from % italic fonts. But since this is only used by $ and it uses \sl anyway % this is not a problem. \def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} % Turn off all special characters except @ % (and those which the user can use as if they were ordinary). % Most of these we simply print from the \tt font, but for some, we can % use math or other variants that look better in normal text. \catcode`\"=\active \def\activedoublequote{{\tt\char34}} \let"=\activedoublequote \catcode`\~=\active \def~{{\tt\char126}} \chardef\hat=`\^ \catcode`\^=\active \def^{{\tt \hat}} \catcode`\_=\active \def_{\ifusingtt\normalunderscore\_} \let\realunder=_ % Subroutine for the previous macro. \def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } \catcode`\|=\active \def|{{\tt\char124}} \chardef \less=`\< \catcode`\<=\active \def<{{\tt \less}} \chardef \gtr=`\> \catcode`\>=\active \def>{{\tt \gtr}} \catcode`\+=\active \def+{{\tt \char 43}} \catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix % If a .fmt file is being used, characters that might appear in a file % name cannot be active until we have parsed the command line. % So turn them off again, and have \everyjob (or @setfilename) turn them on. % \otherifyactive is called near the end of this file. \def\otherifyactive{\catcode`+=\other \catcode`\_=\other} % Used sometimes to turn off (effectively) the active characters even after % parsing them. \def\turnoffactive{% \normalturnoffactive \otherbackslash } \catcode`\@=0 % \backslashcurfont outputs one backslash character in current font, % as in \char`\\. \global\chardef\backslashcurfont=`\\ \global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work % \realbackslash is an actual character `\' with catcode other, and % \doublebackslash is two of them (for the pdf outlines). {\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} % In texinfo, backslash is an active character; it prints the backslash % in fixed width font. \catcode`\\=\active @def@normalbackslash{{@tt@backslashcurfont}} % On startup, @fixbackslash assigns: % @let \ = @normalbackslash % \rawbackslash defines an active \ to do \backslashcurfont. % \otherbackslash defines an active \ to be a literal `\' character with % catcode other. @gdef@rawbackslash{@let\=@backslashcurfont} @gdef@otherbackslash{@let\=@realbackslash} % Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of % the literal character `\'. % @def@normalturnoffactive{% @let\=@normalbackslash @let"=@normaldoublequote @let~=@normaltilde @let^=@normalcaret @let_=@normalunderscore @let|=@normalverticalbar @let<=@normalless @let>=@normalgreater @let+=@normalplus @let$=@normaldollar %$ font-lock fix @markupsetuplqdefault @markupsetuprqdefault @unsepspaces } % Make _ and + \other characters, temporarily. % This is canceled by @fixbackslash. @otherifyactive % If a .fmt file is being used, we don't want the `\input texinfo' to show up. % That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. % @gdef@eatinput input texinfo{@fixbackslash} @global@let\ = @eatinput % On the other hand, perhaps the file did not have a `\input texinfo'. Then % the first `\' in the file would cause an error. This macro tries to fix % that, assuming it is called before the first `\' could plausibly occur. % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. % @gdef@fixbackslash{% @ifx\@eatinput @let\ = @normalbackslash @fi @catcode`+=@active @catcode`@_=@active } % Say @foo, not \foo, in error messages. @escapechar = `@@ % These look ok in all fonts, so just make them not special. @catcode`@& = @other @catcode`@# = @other @catcode`@% = @other @c Finally, make ` and ' active, so that txicodequoteundirected and @c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}. If we @c don't make ` and ' active, @code will not get them as active chars. @c Do this last of all since we use ` in the previous @catcode assignments. @catcode`@'=@active @catcode`@`=@active @markupsetuplqdefault @markupsetuprqdefault @c Gnulib now utterly and painfully insists on no trailing whitespace. @c So we have to nuke it. @c Local variables: @c eval: (add-hook 'write-file-hooks 'time-stamp) @c eval: (add-hook 'write-file-hooks 'nuke-trailing-whitespace) @c page-delimiter: "^\\\\message" @c time-stamp-start: "def\\\\texinfoversion{" @c time-stamp-format: "%:y-%02m-%02d.%02H" @c time-stamp-end: "}" @c End: @c vim:sw=2: @ignore arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 @end ignore udunits-2.2.0/ANNOUNCEMENT0000644000175000017500000000456012260406756016172 0ustar amckinstryamckinstryDear UDUNITS user, Version 2 of the UDUNITS package is now available from the UDUNITS homepage at . The UDUNITS-2 package differs from the previous UDUNITS package in the following ways: Support for non-ASCII characters. The original UDUNITS package only supports the ASCII character set. The UDUNITS-2 package supports the following character sets: ASCII, ISO 8859-1 (Latin 1), and the UTF-8 encoding of ISO 10646 (Unicode). This means that unit string specifications like "µ°F·Ω⁻¹" are now supported (your viewer must support UTF-8 to display this string correctly). Support for logarithmic units. The unit string specification "0.1 lg(re 1 mW)" specifies a deciBel unit with a one milliwatt reference level. Meteorologists should note that the unit "dBZ" (i.e., "0.1 lg(re um^3)") is now supported. Persistent value converters. It is now possible to obtain a converter data-object, which can be used to convert numeric values in one unit to numeric values in another, compatible unit. The values can be float, double, or one-dimensional arrays of floats or doubles. Improved API. Due to the above changes, it was not possible to keep the application programming interface of the original UDUNITS package. Beginning with version 2.1.0, however, the package contains a thin UDUNITS API to the UDUNITS-2 library, so code written to the original API can simply be recompiled and relinked against the new package. Because the original UDUNITS API uses the "utUnit" data-structure and the UDUNITS-2 API uses pointers to "ut_unit" data-structures, a small memory-leak is possible in code that creates many units. This leak can be avoided by calling the new method utFree(utUnit*) when the unit is no longer needed. XML unit database. The unit database is encoded using human-readable XML rather than a custom format. The XML parser included in the package supports an element to allow easy and convenient customization. One thing that has not changed is that all unit string specifications understood by the original UDUNITS package are also understood by the new UDUNITS-2 package. Please visit the webpage or email if you have questions or comments. Regards, Steve Emmerson UDUNITS-2 Developer udunits-2.2.0/acceptance_test_linux.sh0000755000175000017500000000560512260406756021261 0ustar amckinstryamckinstry# Performs an acceptance-test of a package on a Linux system. Creates a binary # distribution file and a documentation distribution file. # # Usage: # $0 sourceDistro vmName pkgFileName generator ext install # # where: # sourceDistro Glob pattern of the compressed tar file of the source # distribution # vmName Name of the virtual machine (e.g., "centos64_64", "precise32") # pkgFileName Value for the variable CPACK_PACKAGE_FILE_NAME (e.g., # "udunits-2.2.0-3.x86_64") # generator Name of the CPack package generator (e.g., "RPM", "DEB") # ext Extension of the package file (e.g., "rpm", "deb") # install Command to install from the package file (e.g., "rpm --install", # "dpkg --install") set -e sourceDistro=${1:?Pathname of source-distribution not specified} vmName=${2:?Name of virtual machine not specified} pkgFileName=${3:?Package filename not specified} generator=${4:?Name of CPack package generator not specified} ext=${5:?Package extension not specified} install=${6:?Installation command not specified} prefix=/usr/local sourceDistro=`ls $sourceDistro` # # Remove any leftover artifacts from an earlier job. # rm -rf * # # Unpack the source distribution. # pax -zr <$sourceDistro # # Make the source directory the current working directory. # cd `basename $sourceDistro .tar.gz` # # Start the virtual machine. Ensure that each virtual machine is started # separately because vagrant(1) doesn't support concurrent "vagrant up" # invocations. # type vagrant trap "vagrant destroy --force $vmName; `trap -p EXIT`" EXIT flock "$sourceDistro" -c "vagrant up \"$vmName\"" # # On the virtual machine, build the package from source, test it, install it, # test the installation, and create a binary distribution. # vagrant ssh $vmName -c "cmake --version" vagrant ssh $vmName -c \ "cmake -DCMAKE_INSTALL_PREFIX=$prefix -DCPACK_PACKAGE_FILE_NAME=$pkgFileName -DCPACK_GENERATOR=$generator /vagrant" vagrant ssh $vmName -c "make all test" vagrant ssh $vmName -c "sudo make install install_test package" # # Copy the binary distribution to the host machine. # rm -rf *.$ext vagrant ssh $vmName -c "cp *.$ext /vagrant" # # Restart the virtual machine. # vagrant destroy --force $vmName vagrant up $vmName # # Verify that the package installs correctly from the binary distribution. # vagrant ssh $vmName -c "sudo $install /vagrant/*.$ext" vagrant ssh $vmName -c "$prefix/bin/udunits2 -A -H km -W m" # # Create a distribution of the documentation in case it's needed by a # subsequent job. NB: The first component of all pathnames in the distribution # is "share/". # pkgId=`basename $sourceDistro .tar.gz | sed 's/^\([^-]*-[0-9.]*\).*/\1/'` vagrant ssh $vmName -c \ "pax -zw -s ';$prefix/;;' $prefix/share/doc/udunits $prefix/share/udunits >$pkgId-doc.tar.gz" vagrant ssh $vmName -c "cp $pkgId-doc.tar.gz /vagrant"udunits-2.2.0/compile0000755000175000017500000000717312260406756015736 0ustar amckinstryamckinstry#! /bin/sh # Wrapper for compilers which do not understand `-c -o'. scriptversion=2009-04-28.21; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009 Free Software # Foundation, Inc. # Written by Tom Tromey . # # This program 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, or (at your option) # any later version. # # 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand `-c -o'. Remove `-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file `INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; esac ofile= cfile= eat= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as `compile cc -o foo foo.c'. # So we strip `-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no `-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # `.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use `[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: udunits-2.2.0/lib/0000755000175000017500000000000012260406756015116 5ustar amckinstryamckinstryudunits-2.2.0/lib/ut_free_system.c0000644000175000017500000000150712260406756020322 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include "udunits2.h" #include "idToUnitMap.h" #include "unitToIdMap.h" extern void coreFreeSystem(ut_system* system); /* * Frees a unit-system. All unit-to-identifier and identifier-to-unit mappings * will be removed. * * Arguments: * system Pointer to the unit-system to be freed. Use of "system" * upon return results in undefined behavior. */ void ut_free_system( ut_system* system) { if (system != NULL) { itumFreeSystem(system); utimFreeSystem(system); coreFreeSystem(system); } } udunits-2.2.0/lib/Makefile.am0000644000175000017500000000657112260406756017163 0ustar amckinstryamckinstry# Copyright 2013 University Corporation for Atmospheric Research # # This file is part of the UDUNITS-2 package. See the file COPYRIGHT # in the top-level source-directory of the package for copying and # redistribution conditions. # ## Process this file with automake to produce Makefile.in SUBDIRS = xmlFailures xmlSuccesses lib_LTLIBRARIES = libudunits2.la libudunits2_la_SOURCES = unitcore.c converter.c formatter.c \ idToUnitMap.c idToUnitMap.h \ unitToIdMap.c unitToIdMap.h \ unitAndId.c unitAndId.h \ systemMap.c systemMap.h \ prefix.c \ parser.y \ status.c \ xml.c \ error.c \ ut_free_system.c BUILT_SOURCES = parser.c scanner.c pkgdata_DATA = \ udunits2.xml \ udunits2-accepted.xml \ udunits2-base.xml \ udunits2-common.xml \ udunits2-derived.xml \ udunits2-prefixes.xml TEXINFO_TEX = ../texinfo.tex info_TEXINFOS = udunits2lib.texi #html_DATA = udunits2lib.html #pdf_DATA = udunits2lib.pdf AM_MAKEINFOFLAGS = -I $(top_srcdir) AM_MAKEINFOHTMLFLAGS = --no-split -I $(top_srcdir) libudunits2_la_LDFLAGS = -version-number 0:1:0 lex_prefix = ut LEX_OUTPUT_ROOT = lex.$(lex_prefix) LFLAGS = -d -P$(lex_prefix) include_HEADERS = udunits2.h converter.h EXTRA_DIST = \ CMakeLists.txt \ parser.c \ scanner.l \ scanner.c \ udunits2.xml \ udunits2-accepted.xml \ udunits2-base.xml \ udunits2-common.xml \ udunits2-derived.xml \ udunits2-prefixes.xml \ udunits2lib.html \ udunits2lib.pdf AM_YFLAGS = -t -p ut if HAVE_CUNIT LDADD = \ libudunits2.la \ @LD_CUNIT@ \ @LIBS_COVERAGE@ \ @LIBS@ check_PROGRAMS = testUnits TESTS_ENVIRONMENT = UDUNITS2_XML_PATH='$(srcdir)/udunits2.xml' TESTS = testUnits endif if ENABLE_UDUNITS_1 libudunits2_la_SOURCES += udunits-1.c include_HEADERS += udunits.h if HAVE_CUNIT check_PROGRAMS += testUnits-1 TESTS += testUnits-1 endif endif DISTCLEANFILES = *.log MOSTLYCLEANFILES = lint.log *.ln *.i core core.[0-9]* *.gcov *.gcda *.gcno TAGS_FILES = parser.c LINTFLAGS = -u LINT = lint # Allow HTML documentation access to the units database by creating symbolic # links in the webpage directory to the database files. $(DESTDIR)$(htmldir): mkdir -p $@ install-data-hook: $(DESTDIR)$(htmldir) cd $(DESTDIR)$(htmldir) && \ rm -rf $(PACKAGE)*.xml && \ ln -s ../../$(PACKAGE)/*.xml . SUFFIXES = .c .l .c.ln: $(LINT.c) $(AM_CPPFLAGS) $(CPPFLAGS) -c $< .c.i: $(CPP) $(AM_CPPFLAGS) $(CPPFLAGS) $< >$@ .c.gcov: gcov -o .libs/libudunits2_la-$<.o $<.c if HAVE_CUNIT check-2: testUnits UDUNITS2_XML_PATH='$(srcdir)/udunits2.xml' ./testUnits check-1: testUnits-1 UDUNITS2_XML_PATH='$(srcdir)/udunits2.xml' ./testUnits-1 debug: debug-2 debug-2: testUnits UDUNITS2_XML_PATH='$(srcdir)/udunits2.xml' \ $(LIBTOOL) --mode=execute gdb testUnits debug-1: testUnits-1 UDUNITS2_XML_PATH='$(srcdir)/udunits2.xml' \ $(LIBTOOL) --mode=execute gdb testUnits-1 debug-decode-time: test_decode_time UDUNITS2_XML_PATH='$(srcdir)/udunits2.xml' \ $(LIBTOOL) --mode=execute gdb test_decode_time valgrind-2: testUnits UDUNITS2_XML_PATH='$(srcdir)/udunits2.xml' \ $(LIBTOOL) --mode=execute valgrind --leak-check=yes testUnits valgrind-1: testUnits-1 UDUNITS2_XML_PATH='$(srcdir)/udunits2.xml' \ $(LIBTOOL) --mode=execute valgrind --leak-check=yes testUnits-1 .PHONY: check-1 check-2 debug debug-1 debug-2 valgrind-1 valgrind-2 endif parser.o: scanner.c udunits-2.2.0/lib/prefix.c0000644000175000017500000003046712260406756016571 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Module for handling unit prefixes -- both names and symbols. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include "udunits2.h" #include "systemMap.h" typedef struct { void* tree; int (*compare)(const void*, const void*); } PrefixToValueMap; typedef struct { void* nextTree; double value; size_t position; /* origin-0 index of character in prefix */ int character; } PrefixSearchEntry; static SystemMap* systemToNameToValue = NULL; static SystemMap* systemToSymbolToValue = NULL; /****************************************************************************** * Prefix Search Entry: ******************************************************************************/ static PrefixSearchEntry* pseNew( int character, size_t position) { PrefixSearchEntry* entry = malloc(sizeof(PrefixSearchEntry)); if (entry == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "Couldn't allocate %lu-byte prefix-search-entry", sizeof(PrefixSearchEntry)); } else { entry->character = character; entry->position = position; entry->value = 0; entry->nextTree = NULL; } return entry; } static void pseFree( PrefixSearchEntry* const entry) { free(entry); } static int pseSensitiveCompare( const void* const entry1, const void* const entry2) { int char1 = ((const PrefixSearchEntry*)entry1)->character; int char2 = ((const PrefixSearchEntry*)entry2)->character; return char1 < char2 ? -1 : char1 == char2 ? 0 : 1; } static int pseInsensitiveCompare( const void* const entry1, const void* const entry2) { int char1 = tolower(((const PrefixSearchEntry*)entry1)->character); int char2 = tolower(((const PrefixSearchEntry*)entry2)->character); return char1 < char2 ? -1 : char1 == char2 ? 0 : 1; } /****************************************************************************** * Prefix-to-Value Map: ******************************************************************************/ static PrefixToValueMap* ptvmNew( int (*compare)(const void*, const void*)) { PrefixToValueMap* map = (PrefixToValueMap*)malloc(sizeof(PrefixToValueMap)); if (map != NULL) { map->tree = NULL; map->compare = compare; } return map; } /* * Returns the prefix search-entry that matches an identifier. Inserts a * new prefix search-entry if no matching element is found. Note that the * returned entry might have a different prefix value if it was previously * inserted. * * Arguments: * map Pointer to the prefix-to-value map. * id The prefix identifier. May be freed upon return. * value The prefix value. * Returns: * NULL "map" is NULL. * NULL "id" is NULL or the empty string. * NULL "value" is 0. * NULL Insufficient storage space is available. * else Pointer to the prefix-search-entry that matches "id". */ static const PrefixSearchEntry* ptvmSearch( PrefixToValueMap* map, const char* const id, const double value) { PrefixSearchEntry* entry = NULL; /* failure */ if (id != NULL && map != NULL && value != 0) { size_t len = strlen(id); if (len > 0) { size_t i; PrefixSearchEntry* const* treeEntry = NULL; void** tree = &map->tree; for (i = 0; i < len; i++) { PrefixSearchEntry* const newEntry = pseNew(id[i], i); if (newEntry == NULL) break; treeEntry = tsearch(newEntry, tree, map->compare); if (treeEntry == NULL) { pseFree(newEntry); break; } tree = &(*treeEntry)->nextTree; /* next binary-search tree */ if (newEntry != *treeEntry) pseFree(newEntry); } if (i >= len) { entry = *treeEntry; if (entry->value == 0) entry->value = value; } } } return entry; } /* * Returns the prefix search-entry that matches the beginning of a string. * * Arguments: * map Pointer to the prefix-to-value map. * string Pointer to the string to be examined for a prefix. * Returns: * NULL "map" is NULL. * NULL "string" is NULL or the empty string. * NULL "value" is 0. * else Pointer to the prefix-search-entry that matches the * beginning of "string". */ static const PrefixSearchEntry* ptvmFind( PrefixToValueMap* const map, const char* const string) { PrefixSearchEntry* entry = NULL; /* failure */ if (string != NULL && map != NULL && strlen(string) > 0) { size_t len = strlen(string); if (len > 0) { size_t i; PrefixSearchEntry* lastEntry = NULL; void** tree = &map->tree; for (i = 0; i < len; i++) { PrefixSearchEntry targetEntry; PrefixSearchEntry* const* treeEntry; targetEntry.character = string[i]; treeEntry = tfind(&targetEntry, tree, map->compare); if (treeEntry == NULL) break; lastEntry = *treeEntry; tree = &(*treeEntry)->nextTree; /* next binary-search tree */ } if (lastEntry != NULL && lastEntry->value != 0) entry = lastEntry; } } return entry; } /****************************************************************************** * Public API: ******************************************************************************/ /* * Adds a prefix to a unit-system. * * Arguments: * system Pointer to the unit-system. * prefix Pointer to the prefix (e.g., "mega", "M"). May be freed * upon return. * value The value of the prefix (e.g., 1e6). * systemMap Pointer to system-map. * compare Prefix comparison function. * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" is NULL, "prefix" is NULL or empty, or "value" * is 0. * UT_EXISTS "prefix" already maps to a different value. * UT_OS Operating-system failure. See "errno". */ static ut_status addPrefix( ut_system* const system, const char* const prefix, const double value, SystemMap** const systemMap, int (*compare)(const void*, const void*)) { ut_status status; if (system == NULL) { status = UT_BAD_ARG; } else if (prefix == NULL || strlen(prefix) == 0) { status = UT_BAD_ARG; } else if (value == 0) { status = UT_BAD_ARG; } else { if (*systemMap == NULL) { *systemMap = smNew(); if (*systemMap == NULL) status = UT_OS; } if (*systemMap != NULL) { PrefixToValueMap** const prefixToValue = (PrefixToValueMap**)smSearch(*systemMap, system); if (prefixToValue == NULL) { status = UT_OS; } else { if (*prefixToValue == NULL) { *prefixToValue = ptvmNew(compare); if (*prefixToValue == NULL) status = UT_OS; } if (*prefixToValue != NULL) { const PrefixSearchEntry* entry = ptvmSearch(*prefixToValue, prefix, value); status = entry == NULL ? UT_OS : (entry->value == value) ? UT_SUCCESS : UT_EXISTS; } } /* have system-map entry */ } /* have system-map */ } /* valid arguments */ return status; } /* * Adds a name-prefix to a unit-system. A name-prefix is something like "mega" * or "milli". Comparisons between name-prefixes are case-insensitive. * * Arguments: * system Pointer to the unit-system. * name Pointer to the name-prefix (e.g., "mega"). May be freed * upon return. * value The value of the prefix (e.g., 1e6). * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" or "name" is NULL, or "value" is 0. * UT_EXISTS "name" already maps to a different value. * UT_OS Operating-system failure. See "errno". */ ut_status ut_add_name_prefix( ut_system* const system, const char* const name, const double value) { ut_set_status(addPrefix(system, name, value, &systemToNameToValue, pseInsensitiveCompare)); return ut_get_status(); } /* * Adds a symbol-prefix to a unit-system. A symbol-prefix is something like * "M" or "y". Comparisons between symbol-prefixes are case-sensitive. * * Arguments: * system Pointer to the unit-system. * symbol Pointer to the symbol-prefix (e.g., "M"). May be freed * upon return. * value The value of the prefix (e.g., 1e6). * Returns: * UT_SUCCESS Success. * UT_BADSYSTEM "system" or "symbol" is NULL. * UT_BAD_ARG "value" is 0. * UT_EXISTS "symbol" already maps to a different value. * UT_OS Operating-system failure. See "errno". */ ut_status ut_add_symbol_prefix( ut_system* const system, const char* const symbol, const double value) { ut_set_status(addPrefix(system, symbol, value, &systemToSymbolToValue, pseSensitiveCompare)); return ut_get_status(); } /* * Finds a prefix of a unit-system. * * Arguments: * system Pointer to the unit-system. * systemMap Pointer to system-map. * string Pointer to the string to be examined for a prefix. * compare Prefix comparison function. * value NULL or pointer to the memory location to receive the * value of the name-prefix, if one is discovered. * len NULL or pointer to the memory location to receive the * number of characters in the name-prefix, if one is * discovered. * * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" is NULL, "systemMap" is NULL, "compare" is * NULL, "string" is NULL or empty, or "value" is 0. * UT_OS Operating-system failure. See "errno". * UT_UNKNOWN No prefix-to-value map is associated with "system". * UT_UNKNOWN No prefix found in the prefix-to-value map associated * with "system". */ static ut_status findPrefix( ut_system* const system, SystemMap* const systemMap, const char* const string, double* const value, size_t* const len) { ut_status status; if (system == NULL) { status = UT_BAD_ARG; } else if (systemMap == NULL) { status = UT_BAD_ARG; } else if (string == NULL || strlen(string) == 0) { status = UT_BAD_ARG; } else { PrefixToValueMap** const prefixToValue = (PrefixToValueMap**)smFind(systemMap, system); if (prefixToValue == NULL) { status = UT_UNKNOWN; } else { const PrefixSearchEntry* entry = ptvmFind(*prefixToValue, string); if (entry == NULL) { status = UT_UNKNOWN; } else { if (value != NULL) *value = entry->value; if (len != NULL) *len = entry->position + 1; status = UT_SUCCESS; } /* have prefix entry */ } /* have system-map entry */ } /* valid arguments */ return status; } /* * Examines a string for a name-prefix and returns the length of the name-prefix * and its value if one is discovered. * * Arguments: * system Pointer to the unit-system. * string Pointer to the string to be examined for a name-prefix. * value NULL or pointer to the memory location to receive the value of * the name-prefix, if one is discovered. * len NULL or pointer to the memory location to receive the number of * characters in the name-prefix, if one is discovered. * Returns: * UT_BAD_ARG "string" is NULL. * UT_UNKNOWN A name-prefix was not discovered. * UT_SUCCESS Success. "*value" and "*len" will be set if non-NULL. */ ut_status utGetPrefixByName( ut_system* const system, const char* const string, double* const value, size_t* const len) { return string == NULL ? UT_BAD_ARG : findPrefix(system, systemToNameToValue, string, value, len); } /* * Examines a string for a symbol-prefix and returns the length of the * symbol-prefix and its value if one is discovered. * * Arguments: * system Pointer to the unit-system. * string Pointer to the string to be examined for a symbol-prefix. * value NULL or pointer to the memory location to receive the value of * the symbol-prefix, if one is discovered. * len NULL or pointer to the memory location to receive the number of * characters in the symbol-prefix, if one is discovered. * Returns: * UT_BAD_ARG "string" is NULL. * UT_UNKNOWN A symbol-prefix was not discovered. * UT_SUCCESS Success. "*value" and "*len" will be set if non-NULL. */ ut_status utGetPrefixBySymbol( ut_system* const system, const char* const string, double* const value, size_t* const len) { return string == NULL ? UT_BAD_ARG : findPrefix(system, systemToSymbolToValue, string, value, len); } udunits-2.2.0/lib/converter.c0000644000175000017500000007076712260406756017312 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Value converters for the udunits(3) library. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include "converter.h" /* this module's API */ typedef struct { cv_converter* (*clone)(cv_converter*); double (*convertDouble) (const cv_converter*, double); float* (*convertFloats) (const cv_converter*, const float*, size_t, float*); double* (*convertDoubles) (const cv_converter*, const double*, size_t, double*); int (*getExpression) (const cv_converter*, char* buf, size_t, const char*); void (*free)(cv_converter*); } ConverterOps; typedef struct { ConverterOps* ops; } ReciprocalConverter; typedef struct { ConverterOps* ops; double value; } ScaleConverter; typedef struct { ConverterOps* ops; double value; } OffsetConverter; typedef struct { ConverterOps* ops; double slope; double intercept; } GalileanConverter; typedef struct { ConverterOps* ops; double logE; } LogConverter; typedef struct { ConverterOps* ops; double base; } ExpConverter; typedef struct { ConverterOps* ops; cv_converter* first; cv_converter* second; } CompositeConverter; union cv_converter { ConverterOps* ops; ScaleConverter scale; OffsetConverter offset; GalileanConverter galilean; LogConverter log; ExpConverter exp; CompositeConverter composite; }; #define CV_CLONE(conv) ((conv)->ops->clone(conv)) #define IS_TRIVIAL(conv) ((conv)->ops == &trivialOps) #define IS_RECIPROCAL(conv) ((conv)->ops == &reciprocalOps) #define IS_SCALE(conv) ((conv)->ops == &scaleOps) #define IS_OFFSET(conv) ((conv)->ops == &offsetOps) #define IS_GALILEAN(conv) ((conv)->ops == &galileanOps) #define IS_LOG(conv) ((conv)->ops == &logOps) static void nonFree( cv_converter* const conv) { } static void cvSimpleFree( cv_converter* const conv) { free(conv); } static int cvNeedsParentheses( const char* const string) { return strpbrk(string, " \t") != NULL && (string[0] != '(' || string[strlen(string)-1] != ')'); } /******************************************************************************* * Trivial Converter: ******************************************************************************/ static cv_converter* trivialClone( cv_converter* const conv) { return cv_get_trivial(); } static double trivialConvertDouble( const cv_converter* const conv, const double value) { return value; } static float* trivialConvertFloats( const cv_converter* const conv, const float* const in, const size_t count, float* out) { if (in == NULL || out == NULL) { out = NULL; } else { (void)memmove(out, in, count*sizeof(float)); } return out; } static double* trivialConvertDoubles( const cv_converter* const conv, const double* const in, const size_t count, double* out) { if (in == NULL || out == NULL) { out = NULL; } else { (void)memmove(out, in, count*sizeof(double)); } return out; } static int trivialGetExpression( const cv_converter* const conv, char* const buf, const size_t max, const char* const variable) { return snprintf(buf, max, "%s", variable); } static ConverterOps trivialOps = { trivialClone, trivialConvertDouble, trivialConvertFloats, trivialConvertDoubles, trivialGetExpression, nonFree}; static cv_converter trivialConverter = {&trivialOps}; /******************************************************************************* * Reciprocal Converter: ******************************************************************************/ static cv_converter* reciprocalClone( cv_converter* const conv) { return cv_get_inverse(); } static double reciprocalConvertDouble( const cv_converter* const conv, const double value) { return 1.0 / value; } static float* reciprocalConvertFloats( const cv_converter* const conv, const float* const in, const size_t count, float* out) { if (in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = (float)(1.0f / in[i]); } else { for (i = 0; i < count; i++) out[i] = (float)(1.0f / in[i]); } } return out; } static double* reciprocalConvertDoubles( const cv_converter* const conv, const double* const in, const size_t count, double* out) { if (in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = 1.0 / in[i]; } else { for (i = 0; i < count; i++) out[i] = 1.0 / in[i]; } } return out; } static int reciprocalGetExpression( const cv_converter* const conv, char* const buf, const size_t max, const char* const variable) { return cvNeedsParentheses(variable) ? snprintf(buf, max, "1/(%s)", variable) : snprintf(buf, max, "1/%s", variable); } static ConverterOps reciprocalOps = { reciprocalClone, reciprocalConvertDouble, reciprocalConvertFloats, reciprocalConvertDoubles, reciprocalGetExpression, nonFree}; static cv_converter reciprocalConverter = {&reciprocalOps}; /******************************************************************************* * Scale Converter: ******************************************************************************/ static cv_converter* scaleClone( cv_converter* const conv) { return cv_get_scale(conv->scale.value); } static double scaleConvertDouble( const cv_converter* const conv, const double value) { return conv->scale.value * value; } static float* scaleConvertFloats( const cv_converter* const conv, const float* const in, const size_t count, float* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = (float)(conv->scale.value * in[i]); } else { for (i = 0; i < count; i++) out[i] = (float)(conv->scale.value * in[i]); } } return out; } static double* scaleConvertDoubles( const cv_converter* const conv, const double* const in, const size_t count, double* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = conv->scale.value * in[i]; } else { for (i = 0; i < count; i++) out[i] = conv->scale.value * in[i]; } } return out; } static int scaleGetExpression( const cv_converter* const conv, char* const buf, const size_t max, const char* const variable) { return cvNeedsParentheses(variable) ? snprintf(buf, max, "%g*(%s)", conv->scale.value, variable) : snprintf(buf, max, "%g*%s", conv->scale.value, variable); } static ConverterOps scaleOps = { scaleClone, scaleConvertDouble, scaleConvertFloats, scaleConvertDoubles, scaleGetExpression, cvSimpleFree}; /******************************************************************************* * Offset Converter: ******************************************************************************/ static cv_converter* offsetClone( cv_converter* const conv) { return cv_get_offset(conv->offset.value); } static double offsetConvertDouble( const cv_converter* const conv, const double value) { return conv->offset.value + value; } static float* offsetConvertFloats( const cv_converter* const conv, const float* const in, const size_t count, float* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = (float)(conv->offset.value + in[i]); } else { for (i = 0; i < count; i++) out[i] = (float)(conv->offset.value + in[i]); } } return out; } static double* offsetConvertDoubles( const cv_converter* const conv, const double* const in, const size_t count, double* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = conv->offset.value + in[i]; } else { for (i = 0; i < count; i++) out[i] = conv->offset.value + in[i]; } } return out; } static int offsetGetExpression( const cv_converter* const conv, char* const buf, const size_t max, const char* const variable) { const int oper = conv->offset.value < 0 ? '-' : '+'; return cvNeedsParentheses(variable) ? snprintf(buf, max, "(%s) %c %g", variable, oper, fabs(conv->offset.value)) : snprintf(buf, max, "%s %c %g", variable, oper, fabs(conv->offset.value)); } static ConverterOps offsetOps = { offsetClone, offsetConvertDouble, offsetConvertFloats, offsetConvertDoubles, offsetGetExpression, cvSimpleFree}; /******************************************************************************* * Galilean Converter: ******************************************************************************/ static cv_converter* cvGalileanClone( cv_converter* const conv) { return cv_get_galilean(conv->galilean.slope, conv->galilean.intercept); } static double galileanConvertDouble( const cv_converter* const conv, const double value) { return conv->galilean.slope * value + conv->galilean.intercept; } static float* galileanConvertFloats( const cv_converter* const conv, const float* const in, const size_t count, float* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = (float)(conv->galilean.slope * in[i] + conv->galilean.intercept); } else { for (i = 0; i < count; i++) out[i] = (float)(conv->galilean.slope * in[i] + conv->galilean.intercept); } } return out; } static double* galileanConvertDoubles( const cv_converter* const conv, const double* const in, const size_t count, double* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = conv->galilean.slope * in[i] + conv->galilean.intercept; } else { for (i = 0; i < count; i++) out[i] = conv->galilean.slope * in[i] + conv->galilean.intercept; } } return out; } static int galileanGetExpression( const cv_converter* const conv, char* const buf, const size_t max, const char* const variable) { const int oper = conv->galilean.intercept < 0 ? '-' : '+'; return cvNeedsParentheses(variable) ? snprintf(buf, max, "%g*(%s) %c %g", conv->galilean.slope, variable, oper, fabs(conv->galilean.intercept)) : snprintf(buf, max, "%g*%s %c %g", conv->galilean.slope, variable, oper, fabs(conv->galilean.intercept)); } static ConverterOps galileanOps = { cvGalileanClone, galileanConvertDouble, galileanConvertFloats, galileanConvertDoubles, galileanGetExpression, cvSimpleFree}; /******************************************************************************* * Logarithmic Converter: ******************************************************************************/ static cv_converter* cvLogClone( cv_converter* const conv) { return cv_get_log( conv->log.logE == M_LOG2E ? 2 : conv->log.logE == 1 ? M_E : conv->log.logE == M_LOG10E ? 10 : exp(conv->log.logE)); } static double logConvertDouble( const cv_converter* const conv, const double value) { return log(value) * conv->log.logE; } static float* logConvertFloats( const cv_converter* const conv, const float* const in, const size_t count, float* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = (float)(log(in[i]) * conv->log.logE); } else { for (i = 0; i < count; i++) out[i] = (float)(log(in[i]) * conv->log.logE); } } return out; } static double* logConvertDoubles( const cv_converter* const conv, const double* const in, const size_t count, double* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = log(in[i]) * conv->log.logE; } else { for (i = 0; i < count; i++) out[i] = log(in[i]) * conv->log.logE; } } return out; } static int logGetExpression( const cv_converter* const conv, char* const buf, const size_t max, const char* const variable) { return conv->log.logE == M_LOG2E ? snprintf(buf, max, "lb(%s)", variable) : conv->log.logE == 1 ? snprintf(buf, max, "ln(%s)", variable) : conv->log.logE == M_LOG10E ? snprintf(buf, max, "lg(%s)", variable) : snprintf(buf, max, "%g*ln(%s)", conv->log.logE, variable); } static ConverterOps logOps = { cvLogClone, logConvertDouble, logConvertFloats, logConvertDoubles, logGetExpression, cvSimpleFree}; /******************************************************************************* * Exponential Converter: ******************************************************************************/ static cv_converter* expClone( cv_converter* const conv) { return cv_get_pow(conv->exp.base); } static double expConvertDouble( const cv_converter* const conv, const double value) { return pow(conv->exp.base, value); } static float* expConvertFloats( const cv_converter* const conv, const float* const in, const size_t count, float* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = (float)(pow(conv->exp.base, in[i])); } else { for (i = 0; i < count; i++) out[i] = (float)(pow(conv->exp.base, in[i])); } } return out; } static double* expConvertDoubles( const cv_converter* const conv, const double* const in, const size_t count, double* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { size_t i; if (in < out) { for (i = count; i-- > 0;) out[i] = pow(conv->exp.base, in[i]); } else { for (i = 0; i < count; i++) out[i] = pow(conv->exp.base, in[i]); } } return out; } static int expGetExpression( const cv_converter* const conv, char* const buf, const size_t max, const char* const variable) { return cvNeedsParentheses(variable) ? snprintf(buf, max, "pow(%g, (%s))", conv->exp.base, variable) : snprintf(buf, max, "pow(%g, %s)", conv->exp.base, variable); } static ConverterOps expOps = { expClone, expConvertDouble, expConvertFloats, expConvertDoubles, expGetExpression, cvSimpleFree}; /******************************************************************************* * Composite Converter: ******************************************************************************/ static cv_converter* compositeClone( cv_converter* const conv) { return cv_combine(conv->composite.first, conv->composite.second); } static double compositeConvertDouble( const cv_converter* const conv, const double value) { return cv_convert_double(conv->composite.second, cv_convert_double(((CompositeConverter*)conv)->first, value)); } static float* compositeConvertFloats( const cv_converter* const conv, const float* const in, const size_t count, float* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { out = cv_convert_floats( conv->composite.second, cv_convert_floats(conv->composite.first, in, count, out), count, out); } return out; } static double* compositeConvertDoubles( const cv_converter* const conv, const double* const in, const size_t count, double* out) { if (conv == NULL || in == NULL || out == NULL) { out = NULL; } else { out = cv_convert_doubles( conv->composite.second, cv_convert_doubles(conv->composite.first, in, count, out), count, out); } return out; } static void compositeFree( cv_converter* const conv) { cv_free(conv->composite.first); cv_free(conv->composite.second); free(conv); } static int compositeGetExpression( const cv_converter* const conv, char* const buf, const size_t max, const char* const variable) { char tmpBuf[132]; int nchar = cv_get_expression(conv->composite.first, buf, max, variable); if (nchar >= 0) { buf[max-1] = 0; if (cvNeedsParentheses(buf)) { nchar = snprintf(tmpBuf, sizeof(tmpBuf), "(%s)", buf); } else { (void)strncpy(tmpBuf, buf, sizeof(tmpBuf)); tmpBuf[sizeof(tmpBuf)-1] = 0; } nchar = cv_get_expression(conv->composite.second, buf, max, tmpBuf); } return nchar; } static ConverterOps compositeOps = { compositeClone, compositeConvertDouble, compositeConvertFloats, compositeConvertDoubles, compositeGetExpression, compositeFree}; /******************************************************************************* * Public API: ******************************************************************************/ /* * Returns the trivial converter (i.e., y = x). * When finished with the converter, the client should pass the converter to * cv_free(). * * Returns: * The trivial converter. */ cv_converter* cv_get_trivial() { return &trivialConverter; } /* * Returns the reciprocal converter (i.e., y = 1/x). * When finished with the converter, the client should pass the converter to * cv_free(). * * Returns: * The reciprocal converter. */ cv_converter* cv_get_inverse() { return &reciprocalConverter; } /* * Returns a converter that multiplies values by a number (i.e., y = ax). * When finished with the converter, the client should pass the converter to * cv_free(). * * Arguments: * slope The number by which to multiply values. * Returns: * NULL Necessary memory couldn't be allocated. * else A converter that will multiply values by the given number. */ cv_converter* cv_get_scale( const double slope) { cv_converter* conv; if (slope == 1) { conv = &trivialConverter; } else { conv = malloc(sizeof(ScaleConverter)); if (conv != NULL) { conv->ops = &scaleOps; conv->scale.value = slope; } } return conv; } /* * Returns a converter that adds a number to values (i.e., y = x + b). * When finished with the converter, the client should pass the converter to * cv_free(). * * Arguments: * offset The number to be added. * Returns: * NULL Necessary memory couldn't be allocated. * else A converter that adds the given number to values. */ cv_converter* cv_get_offset( const double offset) { cv_converter* conv; if (offset == 0) { conv = &trivialConverter; } else { conv = malloc(sizeof(OffsetConverter)); if (conv != NULL) { conv->ops = &offsetOps; conv->offset.value = offset; } } return conv; } /* * Returns a Galilean converter (i.e., y = ax + b). * When finished with the converter, the client should pass the converter to * cv_free(). * * Arguments: * slope The number by which to multiply values. * offset The number to be added. * Returns: * NULL Necessary memory couldn't be allocated. * else A Galilean converter corresponding to the inputs. */ cv_converter* cv_get_galilean( const double slope, const double intercept) { cv_converter* conv; if (slope == 1) { conv = cv_get_offset(intercept); } else if (intercept == 0) { conv = cv_get_scale(slope); } else { cv_converter* tmp = malloc(sizeof(GalileanConverter)); if (tmp != NULL) { tmp->ops = &galileanOps; tmp->galilean.slope = slope; tmp->galilean.intercept = intercept; conv = tmp; } } return conv; } /* * Returns a logarithmic converter (i.e., y = log(x/x0) in some base). * When finished with the converter, the client should pass the converter to * cv_free(). * * Arguments: * base The logarithmic base (e.g., 2, M_E, 10). Must be * greater than one. * Returns: * NULL "base" is invalid or necessary memory couldn't be * allocated. * else A logarithmic converter corresponding to the inputs. */ cv_converter* cv_get_log( const double base) { cv_converter* conv; if (base <= 1) { conv = NULL; } else { conv = malloc(sizeof(LogConverter)); if (conv != NULL) { conv->ops = &logOps; conv->log.logE = base == 2 ? M_LOG2E : base == M_E ? 1 : base == 10 ? M_LOG10E : 1/log(base); } } return conv; } /* * Returns an exponential converter (i.e., y = pow(b, x) in some base "b"). * When finished with the converter, the client should pass the converter to * cv_free(). * * Arguments: * base The desired base. Must be positive. * Returns: * NULL "base" is invalid or necessary memory couldn't be * allocated. * else An exponential converter corresponding to the inputs. */ cv_converter* cv_get_pow( const double base) { cv_converter* conv; if (base <= 0) { conv = NULL; } else { conv = malloc(sizeof(ExpConverter)); if (conv != NULL) { conv->ops = &expOps; conv->exp.base = base; } } return conv; } /* * Returns a converter corresponding to the sequential application of two * other converters. The returned converter should be passed to cv_free() when * it is no longer needed. * * Arguments: * first The converter to be applied first. May be passed to cv_free() * upon return. * second The converter to be applied second. May be passed to cv_free() * upon return. * Returns: * NULL Either "first" or "second" is NULL or necessary memory couldn't * be allocated. * else A converter corresponding to the sequential application of the * given converters. If one of the input converters is the trivial * converter, then the returned converter will be the other input * converter. */ cv_converter* cv_combine( cv_converter* const first, cv_converter* const second) { cv_converter* conv; if (first == NULL || second == NULL) { conv = NULL; } else if (IS_TRIVIAL(first)) { conv = CV_CLONE(second); } else if (IS_TRIVIAL(second)) { conv = CV_CLONE(first); } else { conv = NULL; if (IS_RECIPROCAL(first)) { if (IS_RECIPROCAL(second)) { conv = cv_get_trivial(); } } else if (IS_SCALE(first)) { if (IS_SCALE(second)) { conv = cv_get_scale(first->scale.value * second->scale.value); } else if (IS_OFFSET(second)) { conv = cv_get_galilean(first->scale.value, second->offset.value); } else if (IS_GALILEAN(second)) { conv = cv_get_galilean( first->scale.value * second->galilean.slope, second->galilean.intercept); } } else if (IS_OFFSET(first)) { if (IS_SCALE(second)) { conv = cv_get_galilean(second->scale.value, first->offset.value * second->scale.value); } else if (IS_OFFSET(second)) { conv = cv_get_offset(first->offset.value + second->offset.value); } else if (IS_GALILEAN(second)) { conv = cv_get_galilean(second->galilean.slope, first->offset.value * second->galilean.slope + second->galilean.intercept); } } else if (IS_GALILEAN(first)) { if (IS_SCALE(second)) { conv = cv_get_galilean( second->scale.value * first->galilean.slope, second->scale.value * first->galilean.intercept); } else if (IS_OFFSET(second)) { conv = cv_get_galilean(first->galilean.slope, first->galilean.intercept + second->offset.value); } else if (IS_GALILEAN(second)) { conv = cv_get_galilean( second->galilean.slope * first->galilean.slope, second->galilean.slope * first->galilean.intercept + second->galilean.intercept); } } if (conv == NULL) { /* * General case: create a composite converter. */ cv_converter* c1 = CV_CLONE(first); int error = 1; if (c1 != NULL) { cv_converter* c2 = CV_CLONE(second); if (c2 != NULL) { conv = malloc(sizeof(CompositeConverter)); if (conv != NULL) { conv->composite.ops = &compositeOps; conv->composite.first = c1; conv->composite.second = c2; error = 0; } /* "conv" allocated */ if (error) cv_free(c2); } /* "c2" allocated */ if (error) cv_free(c1); } /* "c1" allocated */ } /* "conv != NULL" */ } /* "first" & "second" not trivial */ return conv; } /* * Frees resources associated with a converter. Use of the converter argument * subsequent to this function may result in undefined behavior. * * Arguments: * conv The converter to have its resources freed or NULL. The * converter must have been returned by this module. */ void cv_free( cv_converter* const conv) { if (conv != NULL) { conv->ops->free((cv_converter*)conv); } } /* * Converts a float. * * Arguments: * converter Pointer to the converter. * value The value to be converted. * Returns: * The converted value. */ float cv_convert_float( const cv_converter* converter, const float value) { return (float)converter->ops->convertDouble(converter, value); } /* * Converts a double. * * Arguments: * converter Pointer to the converter. * value The value to be converted. * Returns: * The converted value. */ double cv_convert_double( const cv_converter* converter, const double value) { return converter->ops->convertDouble(converter, value); } /* * Converts an array of floats. * * Arguments: * converter Pointer to the converter. * in Pointer to the values to be converted. The array may * overlap "out". * count The number of values to be converted. * out Pointer to the output array for the converted values. * The array may overlap "in". * Returns: * NULL "converter", "in", or "out" is NULL. * else Pointer to the output array, "out". */ float* cv_convert_floats( const cv_converter* converter, const float* const in, const size_t count, float* out) { if (converter == NULL || in == NULL || out == NULL) { out = NULL; } else { out = converter->ops->convertFloats(converter, in, count, out); } return out; } /* * Converts an array of doubles. * * Arguments: * converter Pointer to the converter. * in Pointer to the values to be converted. The array may * overlap "out". * count The number of values to be converted. * out Pointer to the output array for the converted values. * The array may overlap "in". * Returns: * NULL "converter", "in", or "out" is NULL. * else Pointer to the output array, "out". */ double* cv_convert_doubles( const cv_converter* converter, const double* const in, const size_t count, double* out) { if (converter == NULL || in == NULL || out == NULL) { out = NULL; } else { out = converter->ops->convertDoubles(converter, in, count, out); } return out; } /* * Returns a string expression representation of a converter. * * Arguments: * conv The converter. * buf The buffer into which to write the expression. * max The size of the buffer. * variable The string to be used as the input value for the * converter. * RETURNS * <0 An error was encountered. * else The number of bytes formatted excluding the terminating null. */ int cv_get_expression( const cv_converter* const conv, char* const buf, size_t max, const char* const variable) { return conv->ops->getExpression(conv, buf, max, variable); } udunits-2.2.0/lib/udunits2.xml0000644000175000017500000000100712260406756017413 0ustar amckinstryamckinstry udunits2-prefixes.xml udunits2-base.xml udunits2-derived.xml udunits2-accepted.xml udunits2-common.xml udunits-2.2.0/lib/scanner.c0000644000175000017500000024456212260406756016730 0ustar amckinstryamckinstry#line 2 "scanner.c" #line 4 "scanner.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ /* %not-for-header */ /* %if-c-only */ /* %if-not-reentrant */ #define yy_create_buffer ut_create_buffer #define yy_delete_buffer ut_delete_buffer #define yy_flex_debug ut_flex_debug #define yy_init_buffer ut_init_buffer #define yy_flush_buffer ut_flush_buffer #define yy_load_buffer_state ut_load_buffer_state #define yy_switch_to_buffer ut_switch_to_buffer #define yyin utin #define yyleng utleng #define yylex utlex #define yylineno utlineno #define yyout utout #define yyrestart utrestart #define yytext uttext #define yywrap utwrap #define yyalloc utalloc #define yyrealloc utrealloc #define yyfree utfree /* %endif */ /* %endif */ /* %ok-for-header */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 35 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* %if-c++-only */ /* %endif */ /* %if-c-only */ /* %endif */ /* %if-c-only */ /* %endif */ /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ /* %if-c-only */ #include #include #include #include /* %endif */ /* %if-tables-serialization */ /* %endif */ /* end standard C headers. */ /* %if-c-or-c++ */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ /* %endif */ /* %if-c++-only */ /* %endif */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ /* C99 requires __STDC__ to be defined as 1. */ #if defined (__STDC__) #define YY_USE_CONST #endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* %not-for-header */ /* Returned upon end-of-file. */ #define YY_NULL 0 /* %ok-for-header */ /* %not-for-header */ /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* %ok-for-header */ /* %if-reentrant */ /* %endif */ /* %if-not-reentrant */ /* %endif */ /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE utrestart(utin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif /* %if-not-reentrant */ extern int utleng; /* %endif */ /* %if-c-only */ /* %if-not-reentrant */ extern FILE *utin, *utout; /* %endif */ /* %endif */ #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up uttext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up uttext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { /* %if-c-only */ FILE *yy_input_file; /* %endif */ /* %if-c++-only */ /* %endif */ char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via utrestart()), so that the user can continue scanning by * just pointing utin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* %if-c-only Standard (non-C++) definition */ /* %not-for-header */ /* %if-not-reentrant */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* %endif */ /* %ok-for-header */ /* %endif */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* %if-c-only Standard (non-C++) definition */ /* %if-not-reentrant */ /* %not-for-header */ /* yy_hold_char holds the character lost when uttext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int utleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow utwrap()'s to do buffer switches * instead of setting up a fresh utin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; /* %ok-for-header */ /* %endif */ void utrestart (FILE *input_file ); void ut_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE ut_create_buffer (FILE *file,int size ); void ut_delete_buffer (YY_BUFFER_STATE b ); void ut_flush_buffer (YY_BUFFER_STATE b ); void utpush_buffer_state (YY_BUFFER_STATE new_buffer ); void utpop_buffer_state (void ); static void utensure_buffer_stack (void ); static void ut_load_buffer_state (void ); static void ut_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER ut_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE ut_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE ut_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE ut_scan_bytes (yyconst char *bytes,int len ); /* %endif */ void *utalloc (yy_size_t ); void *utrealloc (void *,yy_size_t ); void utfree (void * ); #define yy_new_buffer ut_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ utensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ ut_create_buffer(utin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ utensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ ut_create_buffer(utin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* %% [1.0] uttext/utin/utout/yy_state_type/utlineno etc. def's & init go here */ /* Begin user sect3 */ #define utwrap(n) 1 #define YY_SKIP_YYWRAP #define FLEX_DEBUG typedef unsigned char YY_CHAR; FILE *utin = (FILE *) 0, *utout = (FILE *) 0; typedef int yy_state_type; extern int utlineno; int utlineno = 1; extern char *uttext; #define yytext_ptr uttext /* %if-c-only Standard (non-C++) definition */ static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* %endif */ /* Done after the current pattern has been matched and before the * corresponding action - sets up uttext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ /* %% [2.0] code to fiddle uttext and utleng for yymore() goes here \ */\ utleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ /* %% [3.0] code to copy yytext_ptr to uttext[] goes here, if %array \ */\ (yy_c_buf_p) = yy_cp; /* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */ #define YY_NUM_RULES 16 #define YY_END_OF_BUFFER 17 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[315] = { 0, 0, 0, 0, 0, 17, 15, 3, 16, 14, 3, 15, 3, 3, 2, 10, 10, 10, 1, 14, 14, 14, 14, 14, 14, 15, 14, 15, 15, 15, 15, 15, 15, 3, 3, 10, 10, 10, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 10, 10, 9, 2, 0, 9, 10, 10, 10, 0, 0, 8, 10, 10, 10, 1, 0, 14, 14, 0, 0, 0, 0, 14, 14, 14, 14, 0, 4, 14, 14, 14, 14, 14, 5, 3, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 6, 6, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 7, 0, 9, 8, 0, 8, 8, 8, 14, 0, 14, 2, 1, 14, 0, 0, 0, 0, 0, 0, 0, 0, 5, 14, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 9, 6, 0, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 0, 8, 8, 8, 8, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 13, 11, 12, 5, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 8, 8, 13, 0, 11, 0, 12, 0, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 8, 13, 11, 12, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 4, 1, 1, 5, 1, 6, 7, 1, 8, 9, 1, 10, 11, 12, 13, 14, 15, 16, 17, 17, 18, 19, 19, 19, 20, 1, 1, 1, 1, 1, 21, 22, 23, 24, 23, 25, 26, 23, 23, 27, 23, 23, 23, 28, 29, 30, 31, 23, 32, 33, 34, 23, 23, 23, 23, 23, 23, 1, 1, 1, 35, 23, 1, 22, 36, 24, 23, 25, 26, 37, 23, 27, 23, 23, 38, 28, 39, 40, 31, 23, 32, 33, 41, 23, 23, 23, 23, 23, 23, 1, 1, 1, 1, 1, 42, 43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 44, 45, 45, 45, 45, 45, 45, 45, 45, 46, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 47, 45, 45, 48, 45, 49, 50, 51, 52, 51, 53, 54, 55, 56, 57, 58, 58, 58, 58, 1, 1, 59, 60, 1, 1, 1, 1, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 62, 62, 63, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[64] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1 } ; static yyconst flex_int16_t yy_base[319] = { 0, 0, 0, 55, 66, 858, 1728, 76, 1728, 1728, 848, 76, 99, 106, 853, 116, 82, 90, 844, 138, 816, 111, 113, 119, 120, 171, 156, 156, 0, 96, 0, 788, 199, 206, 1728, 216, 220, 227, 242, 828, 800, 767, 749, 746, 744, 741, 242, 263, 0, 0, 270, 757, 283, 290, 306, 331, 232, 319, 344, 364, 729, 727, 726, 735, 701, 699, 350, 219, 0, 209, 0, 288, 116, 689, 346, 379, 386, 362, 404, 405, 157, 676, 231, 1728, 286, 390, 0, 0, 439, 464, 278, 451, 476, 486, 374, 56, 661, 657, 380, 407, 497, 515, 516, 518, 541, 566, 297, 0, 591, 414, 145, 0, 493, 0, 0, 613, 171, 554, 579, 672, 604, 622, 632, 640, 202, 299, 244, 384, 387, 303, 469, 495, 517, 521, 537, 546, 491, 628, 617, 618, 650, 672, 682, 694, 704, 716, 726, 738, 748, 760, 770, 637, 575, 575, 782, 792, 588, 799, 1728, 809, 834, 548, 0, 859, 573, 235, 0, 598, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 587, 822, 881, 888, 906, 913, 646, 345, 671, 549, 673, 540, 692, 539, 809, 887, 502, 930, 940, 952, 962, 974, 984, 996, 1006, 1018, 1028, 1040, 1050, 1062, 1072, 1084, 1094, 1106, 1116, 1128, 1138, 510, 497, 895, 1161, 852, 353, 1171, 1186, 777, 819, 1210, 866, 437, 0, 1223, 0, 0, 0, 0, 0, 0, 0, 875, 0, 0, 0, 1241, 950, 461, 1251, 1261, 1271, 1281, 1291, 1147, 536, 650, 659, 801, 355, 1162, 1151, 1298, 1305, 1312, 1334, 1341, 1348, 1370, 1377, 1384, 1392, 1406, 1414, 1428, 1436, 1450, 1458, 1472, 1480, 1494, 1504, 0, 1519, 474, 1532, 1178, 0, 0, 0, 508, 0, 1550, 1557, 1575, 473, 460, 458, 388, 311, 267, 1186, 1565, 1582, 1589, 1596, 1618, 1625, 1632, 1639, 1661, 1668, 1675, 1697, 1704, 208, 205, 126, 1728, 109, 1722, 65, 1724 } ; static yyconst flex_int16_t yy_def[319] = { 0, 314, 1, 1, 1, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 15, 16, 314, 314, 19, 19, 19, 19, 19, 314, 19, 314, 315, 315, 316, 316, 314, 314, 314, 314, 35, 36, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 15, 17, 314, 314, 314, 314, 314, 314, 55, 314, 314, 314, 56, 54, 55, 314, 19, 19, 19, 314, 317, 317, 318, 19, 19, 19, 19, 314, 314, 19, 19, 19, 19, 19, 314, 314, 315, 314, 35, 37, 314, 314, 89, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 105, 106, 314, 108, 106, 106, 106, 108, 109, 314, 314, 314, 314, 314, 314, 314, 314, 314, 19, 317, 19, 19, 19, 19, 314, 314, 314, 314, 314, 314, 314, 314, 19, 19, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 160, 161, 314, 163, 161, 161, 161, 163, 164, 161, 163, 164, 161, 161, 167, 163, 164, 160, 314, 314, 314, 314, 314, 314, 19, 19, 314, 314, 314, 314, 314, 314, 314, 314, 318, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 223, 161, 314, 226, 224, 224, 314, 226, 227, 225, 226, 227, 228, 224, 167, 226, 227, 223, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 317, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 224, 314, 279, 314, 224, 224, 279, 280, 282, 282, 314, 314, 314, 314, 314, 314, 314, 314, 314, 19, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 0, 314, 314, 314, 314 } ; static yyconst flex_int16_t yy_nxt[1792] = { 0, 6, 7, 8, 9, 9, 9, 6, 10, 11, 12, 13, 14, 15, 15, 16, 17, 17, 17, 17, 6, 18, 19, 20, 20, 20, 21, 20, 20, 20, 20, 22, 23, 24, 20, 25, 20, 20, 26, 20, 20, 20, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 27, 28, 29, 30, 31, 32, 33, 34, 65, 35, 35, 36, 37, 37, 37, 37, 32, 33, 34, 38, 35, 35, 36, 37, 37, 37, 37, 152, 47, 39, 48, 48, 49, 49, 49, 49, 49, 152, 40, 41, 60, 60, 60, 42, 61, 62, 60, 60, 43, 44, 45, 47, 81, 48, 48, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 50, 50, 52, 53, 295, 54, 55, 56, 56, 56, 56, 56, 57, 65, 72, 65, 81, 58, 65, 71, 73, 65, 65, 74, 127, 81, 59, 64, 64, 64, 64, 64, 64, 64, 175, 176, 65, 65, 65, 65, 66, 65, 65, 65, 65, 65, 65, 65, 65, 179, 65, 65, 65, 65, 65, 65, 75, 75, 65, 65, 76, 76, 76, 76, 76, 76, 76, 180, 77, 78, 78, 79, 80, 67, 68, 69, 70, 70, 81, 81, 81, 82, 82, 293, 81, 83, 291, 82, 86, 86, 87, 87, 87, 87, 87, 86, 86, 87, 87, 87, 87, 87, 52, 185, 65, 88, 89, 90, 90, 90, 90, 90, 57, 91, 91, 91, 92, 93, 91, 91, 38, 112, 113, 114, 238, 239, 59, 75, 75, 65, 39, 76, 76, 76, 76, 76, 76, 76, 65, 40, 41, 65, 65, 65, 42, 313, 65, 65, 128, 43, 44, 45, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 136, 148, 149, 150, 137, 99, 100, 101, 102, 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, 103, 167, 168, 169, 295, 65, 99, 52, 53, 126, 104, 105, 106, 106, 106, 106, 106, 57, 186, 126, 65, 81, 58, 115, 115, 115, 115, 115, 116, 116, 81, 59, 52, 53, 65, 107, 108, 109, 110, 111, 111, 111, 57, 65, 117, 117, 156, 58, 118, 118, 118, 118, 118, 118, 118, 130, 59, 119, 238, 239, 131, 128, 65, 65, 120, 120, 129, 65, 121, 121, 122, 123, 123, 123, 123, 124, 129, 51, 158, 65, 63, 312, 124, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 132, 134, 151, 153, 65, 133, 135, 65, 136, 151, 154, 154, 137, 153, 155, 155, 155, 155, 155, 155, 155, 175, 176, 177, 65, 65, 81, 81, 81, 81, 81, 81, 138, 81, 81, 138, 138, 138, 138, 138, 139, 139, 81, 52, 286, 287, 140, 141, 142, 142, 142, 142, 142, 57, 293, 52, 311, 179, 148, 149, 150, 146, 147, 147, 147, 130, 288, 59, 52, 291, 131, 143, 144, 145, 146, 147, 147, 147, 57, 59, 52, 277, 277, 140, 141, 142, 142, 142, 142, 142, 52, 187, 59, 143, 144, 145, 146, 147, 147, 147, 159, 178, 166, 166, 59, 102, 102, 102, 102, 102, 102, 156, 156, 132, 59, 277, 40, 189, 133, 157, 157, 188, 102, 102, 102, 103, 103, 103, 103, 103, 103, 103, 119, 134, 82, 82, 40, 99, 135, 256, 82, 289, 191, 158, 158, 52, 53, 190, 159, 160, 161, 161, 161, 161, 161, 230, 231, 232, 254, 253, 58, 118, 118, 118, 118, 118, 118, 118, 252, 59, 52, 53, 192, 162, 163, 164, 165, 166, 166, 166, 238, 239, 240, 179, 156, 58, 118, 118, 118, 118, 118, 118, 118, 217, 59, 52, 53, 40, 170, 171, 172, 173, 174, 174, 174, 222, 241, 229, 229, 179, 58, 121, 121, 123, 123, 123, 123, 123, 119, 59, 116, 116, 116, 116, 116, 116, 116, 180, 119, 181, 181, 181, 181, 181, 182, 182, 119, 65, 65, 181, 181, 181, 181, 183, 184, 184, 291, 183, 183, 183, 183, 183, 184, 184, 52, 293, 216, 196, 197, 198, 198, 198, 198, 198, 292, 193, 65, 187, 119, 189, 194, 194, 128, 294, 195, 195, 52, 40, 59, 199, 200, 201, 202, 203, 203, 203, 52, 39, 191, 204, 205, 206, 202, 203, 203, 203, 65, 188, 52, 190, 59, 204, 205, 206, 202, 203, 203, 203, 52, 128, 59, 207, 208, 209, 210, 211, 211, 211, 192, 65, 52, 65, 59, 212, 213, 214, 210, 211, 211, 211, 52, 63, 59, 212, 213, 206, 202, 203, 203, 203, 314, 314, 52, 314, 59, 204, 205, 206, 202, 203, 203, 203, 52, 51, 59, 196, 215, 203, 203, 203, 203, 203, 98, 97, 52, 96, 59, 207, 208, 209, 210, 211, 211, 211, 52, 95, 59, 212, 213, 214, 210, 211, 211, 211, 281, 282, 282, 94, 59, 155, 155, 155, 155, 155, 155, 155, 63, 295, 59, 155, 155, 155, 155, 155, 155, 155, 218, 219, 219, 220, 221, 221, 221, 52, 53, 296, 222, 223, 224, 224, 224, 224, 224, 314, 51, 85, 281, 232, 58, 242, 242, 242, 242, 242, 243, 244, 65, 59, 52, 53, 63, 225, 226, 227, 228, 229, 229, 229, 156, 51, 46, 255, 314, 58, 255, 255, 255, 255, 255, 221, 221, 314, 59, 52, 53, 314, 233, 234, 235, 236, 237, 237, 237, 286, 287, 287, 314, 119, 58, 314, 158, 314, 277, 229, 119, 314, 314, 59, 245, 245, 245, 245, 245, 246, 247, 245, 245, 245, 245, 245, 246, 247, 119, 221, 221, 221, 221, 221, 221, 119, 314, 314, 314, 248, 248, 248, 248, 248, 246, 247, 249, 249, 249, 249, 249, 250, 251, 65, 65, 65, 82, 82, 314, 65, 52, 314, 82, 257, 258, 259, 259, 259, 259, 259, 52, 314, 179, 260, 261, 262, 263, 264, 264, 264, 314, 288, 52, 244, 59, 265, 266, 267, 263, 264, 264, 264, 52, 314, 59, 265, 266, 267, 263, 264, 264, 264, 314, 314, 52, 314, 59, 268, 269, 270, 271, 272, 272, 272, 52, 314, 59, 273, 274, 275, 271, 272, 272, 272, 314, 314, 52, 314, 59, 273, 274, 267, 263, 264, 264, 264, 52, 314, 59, 265, 266, 267, 263, 264, 264, 264, 314, 314, 52, 314, 59, 257, 276, 264, 264, 264, 264, 264, 52, 314, 59, 268, 269, 270, 271, 272, 272, 272, 314, 314, 52, 314, 59, 273, 274, 275, 271, 272, 272, 272, 52, 314, 59, 265, 266, 267, 263, 264, 264, 264, 314, 314, 52, 314, 59, 268, 269, 270, 271, 272, 272, 272, 52, 314, 59, 273, 274, 275, 271, 272, 272, 272, 314, 314, 52, 314, 59, 273, 274, 267, 263, 264, 264, 264, 52, 314, 59, 265, 266, 267, 263, 264, 264, 264, 314, 314, 52, 314, 59, 257, 276, 264, 264, 264, 264, 264, 52, 314, 59, 268, 269, 270, 271, 272, 272, 272, 314, 314, 52, 314, 59, 273, 274, 275, 271, 272, 272, 272, 52, 119, 59, 260, 261, 262, 263, 264, 264, 264, 289, 314, 251, 314, 59, 156, 298, 259, 259, 259, 259, 259, 259, 314, 59, 314, 221, 221, 221, 221, 221, 221, 221, 314, 53, 314, 277, 224, 224, 224, 224, 224, 224, 280, 280, 280, 280, 158, 58, 53, 314, 278, 232, 232, 279, 280, 280, 280, 65, 314, 314, 314, 297, 58, 65, 297, 297, 297, 297, 297, 314, 314, 59, 53, 314, 283, 240, 240, 284, 285, 285, 285, 314, 314, 314, 314, 53, 58, 277, 229, 229, 229, 229, 229, 229, 179, 59, 194, 314, 314, 58, 195, 314, 314, 288, 119, 244, 244, 244, 244, 244, 244, 244, 314, 289, 119, 248, 248, 248, 248, 248, 246, 247, 314, 289, 119, 290, 249, 249, 249, 249, 250, 251, 314, 289, 119, 249, 249, 249, 249, 249, 250, 251, 314, 289, 119, 249, 249, 249, 249, 249, 250, 251, 314, 289, 314, 251, 251, 251, 251, 251, 251, 251, 299, 267, 267, 300, 301, 301, 301, 302, 303, 303, 300, 301, 301, 301, 302, 267, 267, 263, 264, 264, 264, 59, 314, 314, 314, 314, 314, 314, 59, 314, 314, 314, 314, 314, 314, 59, 304, 275, 275, 305, 306, 306, 306, 307, 308, 308, 305, 306, 306, 306, 307, 308, 303, 300, 301, 301, 301, 59, 314, 314, 314, 314, 314, 314, 59, 314, 314, 314, 314, 314, 314, 59, 302, 303, 303, 300, 301, 301, 301, 298, 264, 264, 264, 264, 264, 264, 304, 275, 275, 305, 306, 306, 306, 59, 307, 308, 308, 305, 306, 306, 306, 314, 314, 314, 314, 314, 314, 59, 302, 267, 267, 263, 264, 264, 264, 59, 304, 275, 275, 305, 306, 306, 306, 314, 314, 314, 314, 314, 314, 59, 307, 308, 308, 305, 306, 306, 306, 59, 307, 308, 303, 300, 301, 301, 301, 314, 314, 314, 314, 314, 314, 59, 302, 303, 303, 300, 301, 301, 301, 59, 298, 264, 264, 264, 264, 264, 264, 314, 314, 314, 314, 314, 314, 59, 304, 275, 275, 305, 306, 306, 306, 59, 307, 308, 308, 305, 306, 306, 306, 314, 314, 314, 314, 314, 314, 59, 299, 267, 267, 300, 301, 301, 301, 59, 53, 314, 277, 277, 277, 277, 277, 277, 277, 314, 314, 314, 314, 59, 58, 53, 314, 280, 280, 277, 277, 277, 277, 277, 314, 314, 314, 314, 53, 58, 277, 280, 280, 280, 280, 280, 280, 179, 59, 314, 314, 314, 58, 314, 119, 314, 314, 314, 309, 309, 309, 309, 309, 309, 309, 310, 310, 310, 310, 310, 310, 310, 119, 298, 298, 298, 298, 298, 298, 298, 314, 289, 314, 251, 251, 251, 251, 251, 251, 251, 302, 303, 303, 300, 301, 301, 301, 301, 301, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 59, 314, 314, 314, 314, 314, 314, 59, 314, 314, 314, 314, 314, 314, 59, 298, 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, 302, 303, 303, 300, 301, 301, 301, 301, 301, 298, 298, 298, 298, 298, 59, 314, 314, 314, 314, 314, 314, 59, 314, 314, 314, 314, 314, 314, 59, 298, 298, 298, 298, 298, 298, 298, 298, 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, 59, 314, 314, 314, 179, 314, 314, 59, 314, 314, 314, 119, 314, 314, 59, 309, 309, 309, 309, 309, 309, 309, 310, 310, 310, 310, 310, 310, 310, 84, 84, 125, 125, 5, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314 } ; static yyconst flex_int16_t yy_chk[1792] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 317, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 95, 11, 7, 11, 11, 11, 11, 11, 11, 11, 95, 7, 7, 16, 16, 16, 7, 17, 17, 17, 17, 7, 7, 7, 12, 315, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 15, 313, 15, 15, 15, 15, 15, 15, 15, 15, 21, 22, 22, 29, 15, 72, 21, 23, 23, 24, 24, 72, 29, 15, 19, 19, 19, 19, 19, 19, 19, 110, 110, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 116, 19, 19, 19, 19, 19, 19, 25, 25, 26, 80, 25, 25, 25, 25, 25, 25, 25, 116, 26, 26, 80, 26, 26, 19, 19, 19, 19, 19, 27, 27, 27, 27, 27, 312, 27, 27, 311, 27, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 35, 124, 124, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 37, 37, 37, 37, 38, 56, 56, 56, 165, 165, 35, 46, 46, 69, 38, 46, 46, 46, 46, 46, 46, 46, 69, 38, 38, 67, 67, 67, 38, 296, 126, 67, 126, 38, 38, 38, 47, 47, 47, 47, 47, 47, 47, 50, 50, 50, 50, 50, 50, 50, 82, 90, 90, 90, 82, 50, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 106, 106, 106, 295, 71, 53, 54, 54, 71, 54, 54, 54, 54, 54, 54, 54, 54, 129, 71, 129, 84, 54, 57, 57, 57, 57, 57, 57, 57, 84, 54, 55, 55, 125, 55, 55, 55, 55, 55, 55, 55, 55, 125, 58, 58, 221, 55, 58, 58, 58, 58, 58, 58, 58, 77, 55, 59, 173, 173, 77, 186, 186, 74, 59, 59, 74, 66, 59, 59, 59, 59, 59, 59, 59, 66, 74, 127, 221, 77, 128, 294, 66, 75, 75, 75, 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 78, 79, 94, 98, 127, 78, 79, 128, 255, 94, 99, 99, 255, 98, 99, 99, 99, 99, 99, 99, 99, 109, 109, 109, 78, 79, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 88, 228, 228, 88, 88, 88, 88, 88, 88, 88, 88, 293, 91, 292, 244, 91, 91, 91, 91, 91, 91, 91, 130, 244, 88, 89, 291, 130, 89, 89, 89, 89, 89, 89, 89, 89, 91, 92, 280, 280, 92, 92, 92, 92, 92, 92, 92, 93, 131, 89, 93, 93, 93, 93, 93, 93, 93, 112, 112, 112, 112, 92, 100, 100, 100, 100, 100, 100, 101, 102, 132, 93, 286, 217, 133, 132, 101, 102, 131, 101, 101, 101, 103, 103, 103, 103, 103, 103, 103, 251, 134, 136, 136, 216, 103, 134, 195, 136, 251, 135, 101, 102, 104, 104, 133, 104, 104, 104, 104, 104, 104, 104, 161, 161, 161, 192, 190, 104, 117, 117, 117, 117, 117, 117, 117, 188, 104, 105, 105, 135, 105, 105, 105, 105, 105, 105, 105, 164, 164, 164, 179, 156, 105, 118, 118, 118, 118, 118, 118, 118, 153, 105, 108, 108, 152, 108, 108, 108, 108, 108, 108, 108, 167, 167, 167, 167, 115, 108, 120, 120, 120, 120, 120, 120, 120, 121, 108, 115, 115, 115, 115, 115, 115, 115, 115, 122, 121, 121, 121, 121, 121, 121, 121, 123, 138, 139, 122, 122, 122, 122, 122, 122, 122, 252, 123, 123, 123, 123, 123, 123, 123, 140, 253, 151, 140, 140, 140, 140, 140, 140, 140, 252, 137, 185, 187, 119, 189, 138, 139, 185, 253, 138, 139, 141, 97, 140, 141, 141, 141, 141, 141, 141, 141, 142, 96, 191, 142, 142, 142, 142, 142, 142, 142, 81, 187, 143, 189, 141, 143, 143, 143, 143, 143, 143, 143, 144, 73, 142, 144, 144, 144, 144, 144, 144, 144, 191, 65, 145, 64, 143, 145, 145, 145, 145, 145, 145, 145, 146, 63, 144, 146, 146, 146, 146, 146, 146, 146, 62, 61, 147, 60, 145, 147, 147, 147, 147, 147, 147, 147, 148, 51, 146, 148, 148, 148, 148, 148, 148, 148, 45, 44, 149, 43, 147, 149, 149, 149, 149, 149, 149, 149, 150, 42, 148, 150, 150, 150, 150, 150, 150, 150, 224, 224, 224, 41, 149, 154, 154, 154, 154, 154, 154, 154, 40, 254, 150, 155, 155, 155, 155, 155, 155, 155, 157, 157, 157, 157, 157, 157, 157, 159, 159, 254, 159, 159, 159, 159, 159, 159, 159, 225, 39, 31, 225, 225, 159, 180, 180, 180, 180, 180, 180, 180, 20, 159, 160, 160, 18, 160, 160, 160, 160, 160, 160, 160, 220, 14, 10, 193, 5, 160, 193, 193, 193, 193, 193, 220, 220, 0, 160, 163, 163, 0, 163, 163, 163, 163, 163, 163, 163, 227, 227, 227, 0, 181, 163, 238, 220, 0, 238, 238, 182, 0, 0, 163, 181, 181, 181, 181, 181, 181, 181, 182, 182, 182, 182, 182, 182, 182, 183, 218, 218, 218, 218, 218, 218, 184, 0, 0, 0, 183, 183, 183, 183, 183, 183, 183, 184, 184, 184, 184, 184, 184, 184, 194, 194, 194, 194, 194, 0, 194, 196, 0, 194, 196, 196, 196, 196, 196, 196, 196, 197, 0, 243, 197, 197, 197, 197, 197, 197, 197, 0, 243, 198, 243, 196, 198, 198, 198, 198, 198, 198, 198, 199, 0, 197, 199, 199, 199, 199, 199, 199, 199, 0, 0, 200, 0, 198, 200, 200, 200, 200, 200, 200, 200, 201, 0, 199, 201, 201, 201, 201, 201, 201, 201, 0, 0, 202, 0, 200, 202, 202, 202, 202, 202, 202, 202, 203, 0, 201, 203, 203, 203, 203, 203, 203, 203, 0, 0, 204, 0, 202, 204, 204, 204, 204, 204, 204, 204, 205, 0, 203, 205, 205, 205, 205, 205, 205, 205, 0, 0, 206, 0, 204, 206, 206, 206, 206, 206, 206, 206, 207, 0, 205, 207, 207, 207, 207, 207, 207, 207, 0, 0, 208, 0, 206, 208, 208, 208, 208, 208, 208, 208, 209, 0, 207, 209, 209, 209, 209, 209, 209, 209, 0, 0, 210, 0, 208, 210, 210, 210, 210, 210, 210, 210, 211, 0, 209, 211, 211, 211, 211, 211, 211, 211, 0, 0, 212, 0, 210, 212, 212, 212, 212, 212, 212, 212, 213, 0, 211, 213, 213, 213, 213, 213, 213, 213, 0, 0, 214, 0, 212, 214, 214, 214, 214, 214, 214, 214, 215, 250, 213, 215, 215, 215, 215, 215, 215, 215, 250, 0, 250, 0, 214, 219, 257, 257, 257, 257, 257, 257, 257, 0, 215, 0, 219, 219, 219, 219, 219, 219, 219, 0, 222, 0, 222, 222, 222, 222, 222, 222, 222, 282, 282, 282, 282, 219, 222, 223, 0, 223, 223, 223, 223, 223, 223, 223, 256, 0, 0, 0, 256, 223, 297, 256, 256, 256, 256, 256, 0, 0, 223, 226, 0, 226, 226, 226, 226, 226, 226, 226, 0, 0, 0, 0, 230, 226, 230, 230, 230, 230, 230, 230, 230, 242, 226, 297, 0, 0, 230, 297, 0, 0, 242, 245, 242, 242, 242, 242, 242, 242, 242, 0, 245, 246, 245, 245, 245, 245, 245, 245, 245, 0, 246, 247, 246, 246, 246, 246, 246, 246, 246, 0, 247, 248, 247, 247, 247, 247, 247, 247, 247, 0, 248, 249, 248, 248, 248, 248, 248, 248, 248, 0, 249, 0, 249, 249, 249, 249, 249, 249, 249, 258, 258, 258, 258, 258, 258, 258, 259, 259, 259, 259, 259, 259, 259, 260, 260, 260, 260, 260, 260, 260, 258, 0, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0, 0, 260, 261, 261, 261, 261, 261, 261, 261, 262, 262, 262, 262, 262, 262, 262, 263, 263, 263, 263, 263, 263, 263, 261, 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 263, 264, 264, 264, 264, 264, 264, 264, 265, 265, 265, 265, 265, 265, 265, 266, 266, 266, 266, 266, 266, 266, 264, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 266, 268, 268, 268, 268, 268, 268, 268, 267, 269, 269, 269, 269, 269, 269, 269, 0, 0, 0, 0, 0, 0, 268, 270, 270, 270, 270, 270, 270, 270, 269, 271, 271, 271, 271, 271, 271, 271, 0, 0, 0, 0, 0, 0, 270, 272, 272, 272, 272, 272, 272, 272, 271, 273, 273, 273, 273, 273, 273, 273, 0, 0, 0, 0, 0, 0, 272, 274, 274, 274, 274, 274, 274, 274, 273, 275, 275, 275, 275, 275, 275, 275, 0, 0, 0, 0, 0, 0, 274, 276, 276, 276, 276, 276, 276, 276, 275, 277, 0, 277, 277, 277, 277, 277, 277, 277, 0, 0, 0, 0, 276, 277, 279, 0, 279, 279, 279, 279, 279, 279, 279, 0, 0, 0, 0, 281, 279, 281, 281, 281, 281, 281, 281, 281, 288, 279, 0, 0, 0, 281, 0, 289, 0, 0, 0, 288, 288, 288, 288, 288, 288, 288, 289, 289, 289, 289, 289, 289, 289, 290, 298, 298, 298, 298, 298, 298, 298, 0, 290, 0, 290, 290, 290, 290, 290, 290, 290, 299, 299, 299, 299, 299, 299, 299, 300, 300, 300, 300, 300, 300, 300, 301, 301, 301, 301, 301, 301, 301, 299, 0, 0, 0, 0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 301, 302, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 304, 304, 304, 304, 304, 304, 304, 305, 305, 305, 305, 305, 305, 305, 303, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 305, 306, 306, 306, 306, 306, 306, 306, 307, 307, 307, 307, 307, 307, 307, 308, 308, 308, 308, 308, 308, 308, 306, 0, 0, 0, 309, 0, 0, 307, 0, 0, 0, 310, 0, 0, 308, 309, 309, 309, 309, 309, 309, 309, 310, 310, 310, 310, 310, 310, 310, 316, 316, 318, 318, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int ut_flex_debug; int ut_flex_debug = 1; static yyconst flex_int16_t yy_rule_linenum[16] = { 0, 80, 85, 90, 95, 110, 167, 180, 193, 210, 227, 244, 249, 254, 259, 266 } ; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *uttext; #line 1 "scanner.l" /* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * lex(1) specification for tokens for the Unidata units package, UDUNITS2. */ #line 15 "scanner.l" #include #include #include #include #include #include #include #include #line 1084 "scanner.c" #define INITIAL 0 #define id_seen 1 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ /* %if-c-only */ #include /* %endif */ /* %if-c++-only */ /* %endif */ #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* %if-c-only Reentrant structure and macros (non-C++). */ /* %if-reentrant */ /* %if-c-only */ static int yy_init_globals (void ); /* %endif */ /* %if-reentrant */ /* %endif */ /* %endif End reentrant structures and macros. */ /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int utlex_destroy (void ); int utget_debug (void ); void utset_debug (int debug_flag ); YY_EXTRA_TYPE utget_extra (void ); void utset_extra (YY_EXTRA_TYPE user_defined ); FILE *utget_in (void ); void utset_in (FILE * in_str ); FILE *utget_out (void ); void utset_out (FILE * out_str ); int utget_leng (void ); char *utget_text (void ); int utget_lineno (void ); void utset_lineno (int line_number ); /* %if-bison-bridge */ /* %endif */ /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int utwrap (void ); #else extern int utwrap (void ); #endif #endif /* %not-for-header */ static void yyunput (int c,char *buf_ptr ); /* %ok-for-header */ /* %endif */ #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT /* %if-c-only Standard (non-C++) definition */ /* %not-for-header */ #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif /* %ok-for-header */ /* %endif */ #endif /* %if-c-only */ /* %endif */ /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* %if-c-only Standard (non-C++) definition */ /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( uttext, utleng, 1, utout )) {} } while (0) /* %endif */ /* %if-c++-only C++ definition */ /* %endif */ #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ /* %% [5.0] fread()/read() definition of YY_INPUT goes here unless we're doing C++ \ */\ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ unsigned n; \ for ( n = 0; n < max_size && \ (c = getc( utin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( utin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, utin))==0 && ferror(utin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(utin); \ } \ }\ \ /* %if-c++-only C++ definition \ */\ /* %endif */ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR /* %if-c-only */ #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) /* %endif */ /* %if-c++-only */ /* %endif */ #endif /* %if-tables-serialization structures and prototypes */ /* %not-for-header */ /* %ok-for-header */ /* %not-for-header */ /* %tables-yydmap generated elements */ /* %endif */ /* end tables serialization structures and prototypes */ /* %ok-for-header */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 /* %if-c-only Standard (non-C++) definition */ extern int utlex (void); #define YY_DECL int utlex (void) /* %endif */ /* %if-c++-only C++ definition */ /* %endif */ #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after uttext and utleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif /* %% [6.0] YY_RULE_SETUP definition goes here */ #define YY_RULE_SETUP \ YY_USER_ACTION /* %not-for-header */ /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; /* %% [7.0] user's declarations go here */ #line 74 "scanner.l" if (_restartScanner) { BEGIN(INITIAL); _restartScanner = 0; } #line 1334 "scanner.c" if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! utin ) /* %if-c-only */ utin = stdin; /* %endif */ /* %if-c++-only */ /* %endif */ if ( ! utout ) /* %if-c-only */ utout = stdout; /* %endif */ /* %if-c++-only */ /* %endif */ if ( ! YY_CURRENT_BUFFER ) { utensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = ut_create_buffer(utin,YY_BUF_SIZE ); } ut_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { /* %% [8.0] yymore()-related code goes here */ yy_cp = (yy_c_buf_p); /* Support of uttext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; /* %% [9.0] code to set up and find next match goes here */ yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 315 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 1728 ); yy_find_action: /* %% [10.0] code to find the action number goes here */ yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; /* %% [11.0] code for utlineno update goes here */ do_action: /* This label is used only to access EOF actions. */ /* %% [12.0] debug code goes here */ if ( ut_flex_debug ) { if ( yy_act == 0 ) fprintf( stderr, "--scanner backing up\n" ); else if ( yy_act < 16 ) fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n", (long)yy_rule_linenum[yy_act], uttext ); else if ( yy_act == 16 ) fprintf( stderr, "--accepting default rule (\"%s\")\n", uttext ); else if ( yy_act == 17 ) fprintf( stderr, "--(end of buffer or a NUL)\n" ); else fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); } switch ( yy_act ) { /* beginning of action switch */ /* %% [13.0] actions go here */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 80 "scanner.l" { BEGIN(INITIAL); return SHIFT; } YY_BREAK case 2: YY_RULE_SETUP #line 85 "scanner.l" { BEGIN(INITIAL); return DIVIDE; } YY_BREAK case 3: YY_RULE_SETUP #line 90 "scanner.l" { BEGIN(INITIAL); return MULTIPLY; } YY_BREAK case 4: YY_RULE_SETUP #line 95 "scanner.l" { int status; if (sscanf(uttext, "%*[*^]%ld", &yylval.ival) != 1) { ut_handle_error_message("Invalid integer\n", stderr); status = ERR; } else { status = EXPONENT; } return status; } YY_BREAK case 5: YY_RULE_SETUP #line 110 "scanner.l" { int status = EXPONENT; int exponent = 0; int sign = 1; char* cp = uttext; if (strncmp(cp, "\xe2\x81\xba", 3) == 0) { cp += 3; } else if (strncmp(cp, "\xe2\x81\xbb", 3) == 0) { sign = -1; cp += 3; } while (cp < uttext + utleng) { int j; static struct { const char* string; const int len; } utf8_exponents[] = { {"\xe2\x81\xb0", 3}, /* 0 */ {"\xc2\xb9", 2}, /* 1 */ {"\xc2\xb2", 2}, /* 2 */ {"\xc2\xb3", 2}, /* 3 */ {"\xe2\x81\xb4", 3}, /* 4 */ {"\xe2\x81\xb5", 3}, /* 5 */ {"\xe2\x81\xb6", 3}, /* 6 */ {"\xe2\x81\xb7", 3}, /* 7 */ {"\xe2\x81\xb8", 3}, /* 8 */ {"\xe2\x81\xb9", 3}, /* 9 */ }; exponent *= 10; for (j = 0; j < 10; j++) { int len = utf8_exponents[j].len; if (strncmp(cp, utf8_exponents[j].string, len) == 0) { exponent += j; cp += len; break; } } if (j >= 10) { status = ERR; break; } } if (status == EXPONENT) yylval.ival = sign * exponent; BEGIN(INITIAL); return status; } YY_BREAK case 6: YY_RULE_SETUP #line 167 "scanner.l" { int year; int month; int day = 1; (void) sscanf((char*)uttext, "%d-%d-%d", &year, &month, &day); yylval.rval = ut_encode_date(year, month, day); BEGIN(INITIAL); return DATE; } YY_BREAK case 7: YY_RULE_SETUP #line 180 "scanner.l" { int hour; int minute; double second = 0.0; (void) sscanf((char*)uttext, "%d:%d:%lf", &hour, &minute, &second); yylval.rval = ut_encode_clock(hour, minute, second); BEGIN(INITIAL); return CLOCK; } YY_BREAK case 8: YY_RULE_SETUP #line 193 "scanner.l" { int year; int month = 1; int day = 1; int hour = 0; int minute = 0; double second = 0.0; (void) sscanf((char*)uttext, "%4d%2d%2dT%2d%2d%lf", &year, &month, &day, &hour, &minute, &second); yylval.rval = ut_encode_time(year, month, day, hour, minute, second); BEGIN(INITIAL); return TIMESTAMP; } YY_BREAK case 9: YY_RULE_SETUP #line 210 "scanner.l" { int status; errno = 0; yylval.rval = atof((char*)uttext); if (errno == 0) { status = REAL; } else { ut_handle_error_message("Invalid real\n", stderr); status = ERR; } return status; } YY_BREAK case 10: YY_RULE_SETUP #line 227 "scanner.l" { int status; errno = 0; yylval.ival = atol((char*)uttext); if (errno == 0) { status = INT; } else { ut_handle_error_message("Invalid integer\n", stderr); status = ERR; } return status; } YY_BREAK case 11: YY_RULE_SETUP #line 244 "scanner.l" { yylval.rval = 10; return LOGREF; } YY_BREAK case 12: YY_RULE_SETUP #line 249 "scanner.l" { yylval.rval = M_E; return LOGREF; } YY_BREAK case 13: YY_RULE_SETUP #line 254 "scanner.l" { yylval.rval = 2; return LOGREF; } YY_BREAK case 14: YY_RULE_SETUP #line 259 "scanner.l" { yylval.id = strdup((char*)uttext); BEGIN(id_seen); return ID; } YY_BREAK case 15: YY_RULE_SETUP #line 266 "scanner.l" { BEGIN(INITIAL); return uttext[0]; } YY_BREAK case 16: YY_RULE_SETUP #line 271 "scanner.l" ECHO; YY_BREAK #line 1689 "scanner.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(id_seen): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed utin at a new source and called * utlex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = utin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { /* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */ yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( utwrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * uttext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of utlex */ /* %ok-for-header */ /* %if-c++-only */ /* %not-for-header */ /* %ok-for-header */ /* %endif */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ /* %if-c-only */ static int yy_get_next_buffer (void) /* %endif */ /* %if-c++-only */ /* %endif */ { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ utrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), (size_t) num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; utrestart(utin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) utrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ /* %if-c-only */ /* %not-for-header */ static yy_state_type yy_get_previous_state (void) /* %endif */ /* %if-c++-only */ /* %endif */ { register yy_state_type yy_current_state; register char *yy_cp; /* %% [15.0] code to get the start state into yy_current_state goes here */ yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { /* %% [16.0] code to find the next state goes here */ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 315 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ /* %if-c-only */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) /* %endif */ /* %if-c++-only */ /* %endif */ { register int yy_is_jam; /* %% [17.0] code to find the next state, and perhaps do backing up, goes here */ register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 315 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 314); return yy_is_jam ? 0 : yy_current_state; } /* %if-c-only */ static void yyunput (int c, register char * yy_bp ) /* %endif */ /* %if-c++-only */ /* %endif */ { register char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up uttext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = (yy_n_chars) + 2; register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; /* %% [18.0] update utlineno here */ (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } /* %if-c-only */ /* %endif */ /* %if-c-only */ #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif /* %endif */ /* %if-c++-only */ /* %endif */ { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ utrestart(utin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( utwrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve uttext */ (yy_hold_char) = *++(yy_c_buf_p); /* %% [19.0] update BOL and utlineno */ return c; } /* %if-c-only */ #endif /* ifndef YY_NO_INPUT */ /* %endif */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ /* %if-c-only */ void utrestart (FILE * input_file ) /* %endif */ /* %if-c++-only */ /* %endif */ { if ( ! YY_CURRENT_BUFFER ){ utensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = ut_create_buffer(utin,YY_BUF_SIZE ); } ut_init_buffer(YY_CURRENT_BUFFER,input_file ); ut_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ /* %if-c-only */ void ut_switch_to_buffer (YY_BUFFER_STATE new_buffer ) /* %endif */ /* %if-c++-only */ /* %endif */ { /* TODO. We should be able to replace this entire function body * with * utpop_buffer_state(); * utpush_buffer_state(new_buffer); */ utensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; ut_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (utwrap()) processing, but the only time this flag * is looked at is after utwrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } /* %if-c-only */ static void ut_load_buffer_state (void) /* %endif */ /* %if-c++-only */ /* %endif */ { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; utin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ /* %if-c-only */ YY_BUFFER_STATE ut_create_buffer (FILE * file, int size ) /* %endif */ /* %if-c++-only */ /* %endif */ { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) utalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in ut_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) utalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in ut_create_buffer()" ); b->yy_is_our_buffer = 1; ut_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with ut_create_buffer() * */ /* %if-c-only */ void ut_delete_buffer (YY_BUFFER_STATE b ) /* %endif */ /* %if-c++-only */ /* %endif */ { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) utfree((void *) b->yy_ch_buf ); utfree((void *) b ); } /* %if-c-only */ #ifndef __cplusplus extern int isatty (int ); #endif /* __cplusplus */ /* %endif */ /* %if-c++-only */ /* %endif */ /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a utrestart() or at EOF. */ /* %if-c-only */ static void ut_init_buffer (YY_BUFFER_STATE b, FILE * file ) /* %endif */ /* %if-c++-only */ /* %endif */ { int oerrno = errno; ut_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then ut_init_buffer was _probably_ * called from utrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } /* %if-c-only */ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; /* %endif */ /* %if-c++-only */ /* %endif */ errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ /* %if-c-only */ void ut_flush_buffer (YY_BUFFER_STATE b ) /* %endif */ /* %if-c++-only */ /* %endif */ { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) ut_load_buffer_state( ); } /* %if-c-or-c++ */ /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ /* %if-c-only */ void utpush_buffer_state (YY_BUFFER_STATE new_buffer ) /* %endif */ /* %if-c++-only */ /* %endif */ { if (new_buffer == NULL) return; utensure_buffer_stack(); /* This block is copied from ut_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from ut_switch_to_buffer. */ ut_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /* %endif */ /* %if-c-or-c++ */ /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ /* %if-c-only */ void utpop_buffer_state (void) /* %endif */ /* %if-c++-only */ /* %endif */ { if (!YY_CURRENT_BUFFER) return; ut_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { ut_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* %endif */ /* %if-c-or-c++ */ /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ /* %if-c-only */ static void utensure_buffer_stack (void) /* %endif */ /* %if-c++-only */ /* %endif */ { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)utalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in utensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)utrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in utensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /* %endif */ /* %if-c-only */ /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE ut_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) utalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in ut_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; ut_switch_to_buffer(b ); return b; } /* %endif */ /* %if-c-only */ /** Setup the input buffer state to scan a string. The next call to utlex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * ut_scan_bytes() instead. */ YY_BUFFER_STATE ut_scan_string (yyconst char * yystr ) { return ut_scan_bytes(yystr,strlen(yystr) ); } /* %endif */ /* %if-c-only */ /** Setup the input buffer state to scan the given bytes. The next call to utlex() will * scan from a @e copy of @a bytes. * @param bytes the byte buffer to scan * @param len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE ut_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) utalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in ut_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = ut_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in ut_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } /* %endif */ #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif /* %if-c-only */ static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* %endif */ /* %if-c++-only */ /* %endif */ /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up uttext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ uttext[utleng] = (yy_hold_char); \ (yy_c_buf_p) = uttext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ utleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /* %if-c-only */ /* %if-reentrant */ /* %endif */ /** Get the current line number. * */ int utget_lineno (void) { return utlineno; } /** Get the input stream. * */ FILE *utget_in (void) { return utin; } /** Get the output stream. * */ FILE *utget_out (void) { return utout; } /** Get the length of the current token. * */ int utget_leng (void) { return utleng; } /** Get the current token. * */ char *utget_text (void) { return uttext; } /* %if-reentrant */ /* %endif */ /** Set the current line number. * @param line_number * */ void utset_lineno (int line_number ) { utlineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see ut_switch_to_buffer */ void utset_in (FILE * in_str ) { utin = in_str ; } void utset_out (FILE * out_str ) { utout = out_str ; } int utget_debug (void) { return ut_flex_debug; } void utset_debug (int bdebug ) { ut_flex_debug = bdebug ; } /* %endif */ /* %if-reentrant */ /* %if-bison-bridge */ /* %endif */ /* %endif if-c-only */ /* %if-c-only */ static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from utlex_destroy(), so don't allocate here. */ (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT utin = stdin; utout = stdout; #else utin = (FILE *) 0; utout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * utlex_init() */ return 0; } /* %endif */ /* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */ /* utlex_destroy is for both reentrant and non-reentrant scanners. */ int utlex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ ut_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; utpop_buffer_state(); } /* Destroy the stack itself. */ utfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * utlex() is called, initialization will occur. */ yy_init_globals( ); /* %if-reentrant */ /* %endif */ return 0; } /* %endif */ /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *utalloc (yy_size_t size ) { return (void *) malloc( size ); } void *utrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void utfree (void * ptr ) { free( (char *) ptr ); /* see utrealloc() for (char *) cast */ } /* %if-tables-serialization definitions */ /* %define-yytables The name for this specific scanner's tables. */ #define YYTABLES_NAME "yytables" /* %endif */ /* %ok-for-header */ #line 271 "scanner.l" udunits-2.2.0/lib/udunits2-base.xml0000644000175000017500000000567412260406756020341 0ustar amckinstryamckinstry meter m metre kilogram kg second s ampere A kelvin K mole mol candela cd udunits-2.2.0/lib/xml.c0000644000175000017500000015420112260406756016065 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * This module is thread-compatible but not thread-safe. Multi-threaded * access must be externally synchronized. */ /*LINTLIBRARY*/ #include #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "expat.h" #include "udunits2.h" #ifndef _XOPEN_PATH_MAX # define _XOPEN_PATH_MAX 1024 #endif #define NAME_SIZE 128 #define ACCUMULATE_TEXT \ XML_SetCharacterDataHandler(currFile->parser, accumulateText) #define IGNORE_TEXT \ XML_SetCharacterDataHandler(currFile->parser, NULL) typedef enum { START, UNIT_SYSTEM, PREFIX, UNIT, UNIT_NAME, ALIASES, ALIAS_NAME } ElementType; typedef struct { const char* path; char singular[NAME_SIZE]; char plural[NAME_SIZE]; char symbol[NAME_SIZE]; double value; XML_Parser parser; ut_unit* unit; ElementType context; ut_encoding xmlEncoding; ut_encoding textEncoding; int fd; int skipDepth; int prefixAdded; int haveValue; int isBase; int isDimensionless; int noPLural; int nameSeen; int symbolSeen; } File; typedef struct { char ascii[NAME_SIZE]; char latin1[NAME_SIZE]; char latin1Nbsp[NAME_SIZE]; char utf8[NAME_SIZE]; char utf8Nbsp[NAME_SIZE]; } Identifiers; static ut_status readXml( const char* const path); static File* currFile = NULL; static ut_system* unitSystem = NULL; static char* text = NULL; static size_t nbytes = 0; /* * Returns the plural form of a name. * * Arguments: * singular Pointer to the singular form of a name. * Returns: * Pointer to the plural form of "singular". Client must not free. May be * overwritten by subsequent calls. */ const char* ut_form_plural( const char* singular) { static char buf[NAME_SIZE]; const char* plural = NULL; /* failure */ if (singular != NULL) { int length = strlen(singular); if (length + 3 >= sizeof(buf)) { ut_set_status(UT_SYNTAX); ut_handle_error_message("Singular form is too long"); XML_StopParser(currFile->parser, 0); } else if (length > 0) { (void)strcpy(buf, singular); if (length == 1) { (void)strcpy(buf+length, "s"); } else { char lastChar = singular[length-1]; if (lastChar == 'y') { char penultimateChar = singular[length-2]; if (penultimateChar == 'a' || penultimateChar == 'e' || penultimateChar == 'i' || penultimateChar == 'o' || penultimateChar == 'u') { (void)strcpy(buf+length, "s"); } else { (void)strcpy(buf+length-1, "ies"); } } else { if (lastChar == 's' || lastChar == 'x' || lastChar == 'z' || (length >= 2 && ( strcmp(singular+length-2, "ch") == 0 || strcmp(singular+length-2, "sh") == 0))) { (void)strcpy(buf+length, "es"); } else { (void)strcpy(buf+length, "s"); } } } plural = buf; } } return plural; } /* * Substitutes one substring for all occurrences another in a string. * * Arguments: * inString Pointer to the input string. * str Pointer to the substring to be replaced. * outString Pointer to the output string buffer. * repl Pointer to the replacement substring. * size Size of the output string buffer, including the * terminating NUL. * Returns: * 0 Failure. The output string buffer is too small. * else Success. */ static int substitute( const char* const inString, const char* str, char* const outString, const char* repl, const size_t size) { const char* in = inString; char* out = outString; char* beyond = outString + size; size_t strLen = strlen(str); size_t replLen = strlen(repl); while (*in) { size_t nbytes; char* cp = strstr(in, str); if (cp == NULL) { nbytes = strlen(in); if (out + nbytes >= beyond) { ut_set_status(UT_SYNTAX); ut_handle_error_message("String \"%s\" is too long", inString); return 0; } (void)strncpy(out, in, nbytes); out += nbytes; break; } else { nbytes = (size_t)(cp - in); if (out + nbytes + replLen >= beyond) { ut_set_status(UT_SYNTAX); ut_handle_error_message("String \"%s\" is too long", inString); return 0; } (void)strncpy(out, in, nbytes); out += nbytes; (void)strncpy(out, repl, replLen); out += replLen; in += nbytes + strLen; } } *out = 0; return 1; } #define IS_ASCII(c) (((c) & '\x80') == 0) /* * Returns the UTF-8 string equivalent to a Latin-1 string. * * Arguments: * inString Pointer to the input, Latin-1 string. * outString Pointer to the output, UTF-8, string buffer. * size Size of "outString". * Returns: * 0 Failure. "outString" is too small. * 1 Success. */ static int latin1_to_utf8( const char* inString, char* outString, size_t size) { size_t numSpecial = 0; const unsigned char* in; unsigned char* out; assert(inString != NULL); assert(outString != NULL); /* * Compute the number of non-ASCII characters. */ for (in = (const unsigned char*)inString; *in; in++) if (!IS_ASCII(*in)) numSpecial++; if (size < ((size_t)((char*)in - (char*)inString) + numSpecial + 1)) { ut_set_status(UT_SYNTAX); ut_handle_error_message("Identifier \"%s\" is too long", inString); return 0; } /* * Convert the string. */ for (in = (const unsigned char*)inString, out = (unsigned char*)outString; *in; ++in) { if (IS_ASCII(*in)) { *out++ = *in; } else { *out++ = 0xC0 | ((0xC0 & *in) >> 6); *out++ = 0x80 | (0x3F & *in); } } *out = 0; return 1; } /* * Returns the Latin-1 string equivalent to a UTF-8 string, if possible. * * Arguments: * inString Pointer to the input, UTF-8 string. * outString Pointer to the output, Latin-1, string buffer. * size Size of "outString". * Returns: * -1 Failure. "outString" is too small. * 0 "inString" can't be represented in Latin-1. * 1 Success. */ static int utf8_to_latin1( const char* inString, char* outString, size_t size) { size_t numSpecial = 0; const unsigned char* in; unsigned char* out; assert(inString != NULL); assert(outString != NULL); /* * Compute the number of non-ASCII characters. */ for (in = (const unsigned char*)inString; *in; in++) { if (*in > 0xC3) return 0; if (!IS_ASCII(*in)) { numSpecial++; in++; } } if (size < ((size_t)((char*)in - (char*)inString) - numSpecial + 1)) { ut_set_status(UT_SYNTAX); ut_handle_error_message("Identifier \"%s\" is too long", inString); return -1; } /* * Convert the string. */ for (in = (const unsigned char*)inString, out = (unsigned char*)outString; *in; ++out) { if (IS_ASCII(*in)) { *out = *in++; } else { *out = (*in++ & 0x3) << 6; *out |= (*in++ & 0x3F); } } *out = 0; return 1; } #define LATIN1_NBSP "\xA0" #define UTF8_NBSP "\xC2\xA0" /* * Creates the regular and NBSP forms of a Latin-1 string. * * Arguments: * latin1 Pointer to the input Latin-1 string. * nonNbsp Pointer to an output string buffer of size NAME_SIZE * that will be identical to "latin1" but with all * non-breaking spaces replaced with underscores. * nbsp Pointer to an output string buffer of size NAME_SIZE * that will be identical to "latin1" but with all * underscores replaced with non-breaking spaces. */ static void make_latin1_forms( const char* latin1, char* nonNbsp, char* nbsp) { if (strchr(latin1, '_')) { substitute(latin1, "_", nbsp, LATIN1_NBSP, NAME_SIZE); substitute(nbsp, LATIN1_NBSP, nonNbsp, "_", NAME_SIZE); } else if (strstr(latin1, LATIN1_NBSP)) { substitute(latin1, LATIN1_NBSP, nonNbsp, "_", NAME_SIZE); substitute(nonNbsp, "_", nbsp, LATIN1_NBSP, NAME_SIZE); } else { (void)strcpy(nonNbsp, latin1); *nbsp = 0; } } /* * Creates the regular and NBSP forms of a UTF-8 string. * * Arguments: * utf8 Pointer to the input UTF-8 string. * nonNbsp Pointer to an output string buffer of size NAME_SIZE * that will be identical to "utf8" but with all * non-breaking spaces replaced with underscores. * nbsp Pointer to an output string buffer of size NAME_SIZE * that will be identical to "utf8" but with all * underscores replaced with non-breaking spaces. */ static int make_utf8_forms( const char* utf8, char* nonNbsp, char* nbsp) { int success; if (strchr(utf8, '_')) { success = substitute(utf8, "_", nbsp, UTF8_NBSP, NAME_SIZE); if (success) success = substitute(nbsp, UTF8_NBSP, nonNbsp, "_", NAME_SIZE); } else if (strstr(utf8, UTF8_NBSP)) { success = substitute(utf8, UTF8_NBSP, nonNbsp, "_", NAME_SIZE); if (success) success = substitute(nonNbsp, "_", nbsp, UTF8_NBSP, NAME_SIZE); } else { (void)strcpy(nonNbsp, utf8); *nbsp = 0; success = 1; } return success; } /* * Creates derivatives of an identifier, which are all legitimate combinations * of ASCII, Latin-1, and UTF-8, on the one hand, and underscore vs. * non-breaking spaces on the other. * * Arguments: * id Pointer to the identifier. * encoding The encoding of "id". * ids Pointer to an "Identifier" structure. * Returns: * 0 Failure. * else Success. If a combination is not possible or is * identical to a simpler combination, then the first * character of the relevant member of "ids" will be NUL. */ static int makeDerivatives( const char* const id, const ut_encoding encoding, Identifiers* ids) { int success = 1; assert(id != NULL); assert(ids != NULL); if (strlen(id) > NAME_SIZE - 1) { ut_set_status(UT_SYNTAX); ut_handle_error_message("Identifier \"%s\" is too long", id); success = 0; } else { ids->ascii[0] = 0; ids->latin1[0] = 0; ids->latin1Nbsp[0] = 0; ids->utf8[0] = 0; ids->utf8Nbsp[0] = 0; if (encoding == UT_ASCII) { (void)strcpy(ids->ascii, id); if (strchr(id, '_')) { (void)substitute(id, "_", ids->latin1Nbsp, LATIN1_NBSP, NAME_SIZE); success = latin1_to_utf8(ids->latin1Nbsp, ids->utf8Nbsp, NAME_SIZE); } } else if (encoding == UT_LATIN1) { make_latin1_forms(id, ids->latin1, ids->latin1Nbsp); success = latin1_to_utf8(ids->latin1, ids->utf8, NAME_SIZE) && latin1_to_utf8(ids->latin1Nbsp, ids->utf8Nbsp, NAME_SIZE); } else { success = make_utf8_forms(id, ids->utf8, ids->utf8Nbsp) && utf8_to_latin1(ids->utf8, ids->latin1, NAME_SIZE) != -1 && utf8_to_latin1(ids->utf8Nbsp, ids->latin1Nbsp, NAME_SIZE) != -1; } if (success) { if (strcmp(ids->ascii, ids->latin1) == 0) ids->latin1[0] = 0; if (strcmp(ids->ascii, ids->latin1Nbsp) == 0) ids->latin1Nbsp[0] = 0; if (strcmp(ids->ascii, ids->utf8) == 0) ids->utf8[0] = 0; if (strcmp(ids->ascii, ids->utf8Nbsp) == 0) ids->utf8Nbsp[0] = 0; } } return success; } /* * Maps a unit to an identifier. * * Arguments: * unit Pointer to the unit. * id Pointer to the identifier. * encoding The encoding of "id". * isName Whether or not "id" is a name. * Returns: * 0 Failure. * else Success. */ static int mapUnitToId( ut_unit* const unit, const char* const id, ut_encoding encoding, int isName) { int success = 0; /* failure */ ut_status (*func)(const ut_unit*, const char*, ut_encoding); const char* desc; if (isName) { func = ut_map_unit_to_name; desc = "name"; } else { func = ut_map_unit_to_symbol; desc = "symbol"; } if (func(unit, id, encoding) != UT_SUCCESS) { ut_set_status(UT_PARSE); ut_handle_error_message("Couldn't map unit to %s \"%s\"", desc, id); } else { success = 1; } return success; } /* * Maps a unit to identifiers. * * Arguments: * unit Pointer to the unit. * id Pointer to the identifier upon wich to base all * derived identifiers. * encoding The encoding of "id". * isName Whether or not "id" is a name. * Returns: * 0 Failure. * else Success. */ static int mapUnitToIds( ut_unit* const unit, const char* const id, ut_encoding encoding, int isName) { int success = 1; /* success */ Identifiers ids; if (!makeDerivatives(id, encoding, &ids)) { success = 0; } else { if (ids.ascii[0]) success = mapUnitToId(unit, ids.ascii, UT_ASCII, isName); if (success && ids.latin1[0]) success = mapUnitToId(unit, ids.latin1, UT_LATIN1, isName); if (success && ids.latin1Nbsp[0]) success = mapUnitToId(unit, ids.latin1Nbsp, UT_LATIN1, isName); if (success && ids.utf8[0]) success = mapUnitToId(unit, ids.utf8, UT_UTF8, isName); if (success && ids.utf8Nbsp[0]) success = mapUnitToId(unit, ids.utf8Nbsp, UT_UTF8, isName); } return success; } /* * Maps a unit to a name and all derivatives of the name. * * Arguments: * unit Pointer to the unit. * name Pointer to the name upon wich to base all derived names. * encoding The encoding of "name". * Returns: * 0 Failure. * else Success. */ static int mapUnitToNames( ut_unit* const unit, const char* const name, ut_encoding encoding) { return mapUnitToIds(unit, name, encoding, 1); } /* * Maps a unit to a symbol and all derivatives of the symbol. * * Arguments: * unit Pointer to the unit. * symbol Pointer to the symbol upon wich to base all derived * symbols. * encoding The encoding of "symbol". * Returns: * 0 Failure. * else Success. */ static int mapUnitToSymbols( ut_unit* const unit, const char* const symbol, ut_encoding encoding) { return mapUnitToIds(unit, symbol, encoding, 0); } /* * Maps an identifier to a unit. * * Arguments: * id Pointer to the identifier. * encoding The character encoding of "id". * unit Pointer to the unit. * isName Whether or not "id" is a name. * Returns: * 0 Failure. * else Success. */ static int mapIdToUnit( const char* id, const ut_encoding encoding, ut_unit* unit, const int isName) { int success = 0; /* failure */ ut_unit* prev = ut_get_unit_by_name(unitSystem, id); if (prev == NULL) prev = ut_get_unit_by_symbol(unitSystem, id); if (prev != NULL) { char buf[128]; int nchar = ut_format(prev, buf, sizeof(buf), UT_ASCII | UT_DEFINITION | UT_NAMES); ut_set_status(UT_PARSE); ut_handle_error_message( "Duplicate definition for \"%s\" at \"%s\":%d", id, currFile->path, XML_GetCurrentLineNumber(currFile->parser)); if (nchar < 0) nchar = ut_format(prev, buf, sizeof(buf), UT_ASCII | UT_DEFINITION); if (nchar >= 0 && nchar < sizeof(buf)) { buf[nchar] = 0; ut_set_status(UT_PARSE); ut_handle_error_message("Previous definition was \"%s\"", buf); } XML_StopParser(currFile->parser, 0); } else { /* * Take prefixes into account for a prior definition by using * ut_parse(). */ prev = ut_parse(unitSystem, id, encoding); if ((isName ? ut_map_name_to_unit(id, encoding, unit) : ut_map_symbol_to_unit(id, encoding, unit)) != UT_SUCCESS) { ut_set_status(UT_PARSE); ut_handle_error_message("Couldn't map %s \"%s\" to unit", isName ? "name" : "symbol", id); XML_StopParser(currFile->parser, 0); } else { if (prev != NULL) { char buf[128]; int nchar = ut_format(prev, buf, sizeof(buf), UT_ASCII | UT_DEFINITION | UT_NAMES); if (nchar < 0) nchar = ut_format(prev, buf, sizeof(buf), UT_ASCII | UT_DEFINITION); if (nchar < 0 || nchar >= sizeof(buf)) { ut_set_status(UT_PARSE); ut_handle_error_message("Definition of \"%s\" in \"%s\", " "line %d, overrides prefixed-unit", id, currFile->path, XML_GetCurrentLineNumber(currFile->parser)); } else { buf[nchar] = 0; ut_set_status(UT_PARSE); ut_handle_error_message("Definition of \"%s\" in \"%s\", " "line %d, overrides prefixed-unit \"%s\"", id, currFile->path, XML_GetCurrentLineNumber(currFile->parser), buf); } } success = 1; } } ut_free(prev); /* NULL safe */ return success; } /* * Maps an identifier and all derivatives to a unit. * * Arguments: * id Pointer to the identifier. * encoding The encoding of "id". * unit Pointer to the unit. * isName Whether or not "id" is a name. * Returns: * 0 Failure. * else Success. */ static int mapIdsToUnit( const char* const id, const ut_encoding encoding, ut_unit* const unit, const int isName) { Identifiers ids; int success = 1; if (!makeDerivatives(id, encoding, &ids)) { success = 0; } else { if (ids.ascii[0]) success = mapIdToUnit(ids.ascii, UT_ASCII, unit, isName); if (success && ids.latin1[0]) success = mapIdToUnit(ids.latin1, UT_LATIN1, unit, isName); if (success && ids.latin1Nbsp[0]) success = mapIdToUnit(ids.latin1Nbsp, UT_LATIN1, unit, isName); if (success && ids.utf8[0]) success = mapIdToUnit(ids.utf8, UT_UTF8, unit, isName); if (success && ids.utf8Nbsp[0]) success = mapIdToUnit(ids.utf8Nbsp, UT_UTF8, unit, isName); } return success; } /* * Maps a name and all derivatives to a unit. * * Arguments: * name Pointer to the name. * encoding The encoding of "name". * unit Pointer to the unit. * Returns: * 0 Failure. * else Success. */ static int mapNamesToUnit( const char* const name, const ut_encoding encoding, ut_unit* const unit) { return mapIdsToUnit(name, encoding, unit, 1); } /* * Maps a symbol and all derivatives to a unit. * * Arguments: * symbol Pointer to the symbol. * encoding The encoding of "symbol". * unit Pointer to the unit. * Returns: * 0 Failure. * else Success. */ static int mapSymbolsToUnit( const char* const symbol, const ut_encoding encoding, ut_unit* const unit) { return mapIdsToUnit(symbol, encoding, unit, 0); } /* * Maps between a unit and a name. * * Arguments: * unit Pointer to the unit. * name Pointer to the name . * encoding The encoding of "name". * Returns: * 0 Failure. * else Success. */ static int mapUnitAndName( ut_unit* const unit, const char* const name, ut_encoding encoding) { return mapNamesToUnit(name, encoding, unit) && mapUnitToNames(unit, name, encoding); } /* * Maps between a unit and a symbol. * * Arguments: * unit Pointer to the unit. * symbol Pointer to the symbol . * encoding The encoding of "symbol". * Returns: * 0 Failure. * else Success. */ static int mapUnitAndSymbol( ut_unit* const unit, const char* const symbol, ut_encoding encoding) { return mapSymbolsToUnit(symbol, encoding, unit) && mapUnitToSymbols(unit, symbol, encoding); } /* * Initializes a "File" data-structure to the default state. */ static void fileInit( File* const file) { file->context = START; file->skipDepth = 0; file->value = 0; file->xmlEncoding = UT_ASCII; file->textEncoding = UT_ASCII; file->unit = NULL; file->fd = -1; file->parser = NULL; file->isBase = 0; file->isDimensionless = 0; file->haveValue = 0; file->noPLural = 0; file->nameSeen = 0; file->symbolSeen = 0; file->path = NULL; (void)memset(file->singular, 0, sizeof(file->singular)); (void)memset(file->plural, 0, sizeof(file->plural)); (void)memset(file->symbol, 0, sizeof(file->symbol)); } /* * Clears the text buffer for elements. */ static void clearText(void) { if (text != NULL) *text = 0; nbytes = 0; currFile->textEncoding = UT_ASCII; } /* * Accumulates the textual portion of an element. */ static void accumulateText( void* data, const char* string, /* input text in UTF-8 */ int len) { char* tmp = realloc(text, nbytes + len + 1); if (tmp == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't reallocate %lu-byte text buffer", nbytes+len+1); XML_StopParser(currFile->parser, 0); } else { int i; text = tmp; for (i = 0; i < len; i++) { text[nbytes++] = string[i]; if (!IS_ASCII(string[i])) currFile->textEncoding = UT_UTF8; } text[nbytes] = 0; } } #if 0 /* * Converts the accumulated text from UTF-8 to user-specified encoding. * * Returns: * 0 Failure: the text could not be converted. * else Success. */ static int convertText(void) { int success = 1; if (currFile->encoding == UT_ASCII) { unsigned char* cp; for (cp = text; *cp && IS_ASCII(*cp); cp++) /* EMPTY */; if (*cp) { ut_set_status(UT_SYNTAX); ut_handle_error_message("Character isn't US-ASCII: %#x", *cp); XML_StopParser(currFile->parser, 0); success = 0; } else { textEncoding = UT_ASCII; } } else if (currFile->encoding == UT_LATIN1) { unsigned char* in; unsigned char* out; for (in = out = text; *in; ++in, ++out) { if (IS_ASCII(*in)) { *out = *in; } else { if (*in <= 0xC3) { *out = (unsigned char)((*in++ & 0x3) << 6); *out |= (unsigned char)(*in & 0x3F); } else { ut_set_status(UT_SYNTAX); ut_handle_error_message( "Character is not representable in ISO-8859-1 " "(Latin-1): %d", 1+(int)((char*)out - text)); XML_StopParser(currFile->parser, 0); success = 0; break; } } } *out = 0; nbytes = out - (unsigned char*)text; textEncoding = UT_LATIN1; } return success; } #endif /* * Handles the start of a element. */ static void startUnitSystem( void* data, const char** atts) { if (currFile->context != START) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } currFile->context = UNIT_SYSTEM; } /* * Handles the end of a element. */ static void endUnitSystem( void* data) {} /* * Handles the start of a element. */ static void startPrefix( void* data, const char* const* atts) { if (currFile->context != UNIT_SYSTEM) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); } else { currFile->prefixAdded = 0; currFile->haveValue = 0; } currFile->context = PREFIX; } /* * Handles the end of a element. */ static void endPrefix( void* data) { if (!currFile->haveValue || !currFile->prefixAdded) { ut_set_status(UT_PARSE); ut_handle_error_message("Prefix incompletely specified"); XML_StopParser(currFile->parser, 0); } else { currFile->haveValue = 0; } currFile->context = UNIT_SYSTEM; } /* * Handles the start of a element. */ static void startUnit( void* data, const char** atts) { if (currFile->context != UNIT_SYSTEM) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } else { ut_free(currFile->unit); currFile->unit = NULL; currFile->isBase = 0; currFile->isDimensionless = 0; currFile->singular[0] = 0; currFile->plural[0] = 0; currFile->symbol[0] = 0; currFile->nameSeen = 0; currFile->symbolSeen = 0; } currFile->context = UNIT; } /* * Handles the end of a element. */ static void endUnit( void* data) { if (currFile->isBase) { if (!currFile->nameSeen) { ut_set_status(UT_PARSE); ut_handle_error_message("Base unit needs a name"); XML_StopParser(currFile->parser, 0); } if (!currFile->symbolSeen) { ut_set_status(UT_PARSE); ut_handle_error_message("Base unit needs a symbol"); XML_StopParser(currFile->parser, 0); } } ut_free(currFile->unit); currFile->unit = NULL; currFile->context = UNIT_SYSTEM; } /* * Handles the start of a element. */ static void startBase( void* data, const char** atts) { if (currFile->context != UNIT) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } else { if (currFile->isDimensionless) { ut_set_status(UT_PARSE); ut_handle_error_message( " and are mutually exclusive"); XML_StopParser(currFile->parser, 0); } else if (currFile->unit != NULL) { ut_set_status(UT_PARSE); ut_handle_error_message(" and are mutually exclusive"); XML_StopParser(currFile->parser, 0); } else if (currFile->isBase) { ut_set_status(UT_PARSE); ut_handle_error_message(" element already seen"); XML_StopParser(currFile->parser, 0); } } } /* * Handles the end of a element. */ static void endBase( void* data) { currFile->unit = ut_new_base_unit(unitSystem); if (currFile->unit == NULL) { ut_set_status(UT_PARSE); ut_handle_error_message("Couldn't create new base unit"); XML_StopParser(currFile->parser, 0); } else { currFile->isBase = 1; } } /* * Handles the start of a element. */ static void startDimensionless( void* data, const char** atts) { if (currFile->context != UNIT) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } else { if (currFile->isBase) { ut_set_status(UT_PARSE); ut_handle_error_message( " and are mutually exclusive"); XML_StopParser(currFile->parser, 0); } else if (currFile->unit != NULL) { ut_set_status(UT_PARSE); ut_handle_error_message( " and are mutually exclusive"); XML_StopParser(currFile->parser, 0); } else if (currFile->isDimensionless) { ut_set_status(UT_PARSE); ut_handle_error_message(" element already seen"); XML_StopParser(currFile->parser, 0); } } } /* * Handles the end of a element. */ static void endDimensionless( void* data) { currFile->unit = ut_new_dimensionless_unit(unitSystem); if (currFile->unit == NULL) { ut_set_status(UT_PARSE); ut_handle_error_message("Couldn't create new dimensionless unit"); XML_StopParser(currFile->parser, 0); } else { currFile->isDimensionless = 1; } } /* * Handles the start of a element. */ static void startDef( void* data, const char** atts) { if (currFile->context != UNIT) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } else if (currFile->isBase) { ut_set_status(UT_PARSE); ut_handle_error_message( " and are mutually exclusive"); XML_StopParser(currFile->parser, 0); } else if (currFile->isDimensionless) { ut_set_status(UT_PARSE); ut_handle_error_message( " and are mutually exclusive"); XML_StopParser(currFile->parser, 0); } else if (currFile->unit != NULL) { ut_set_status(UT_PARSE); ut_handle_error_message(" element already seen"); XML_StopParser(currFile->parser, 0); } else { clearText(); ACCUMULATE_TEXT; } } /* * Handles the end of a element. */ static void endDef( void* data) { if (nbytes == 0) { ut_set_status(UT_PARSE); ut_handle_error_message("Empty unit definition"); XML_StopParser(currFile->parser, 0); } else { currFile->unit = ut_parse(unitSystem, text, currFile->textEncoding); if (currFile->unit == NULL) { ut_set_status(UT_PARSE); ut_handle_error_message( "Couldn't parse unit specification \"%s\"", text); XML_StopParser(currFile->parser, 0); } } } /* * Handles the start of a element. */ static void startName( void* data, const char** atts) { if (currFile->context == PREFIX) { if (!currFile->haveValue) { ut_set_status(UT_PARSE); ut_handle_error_message("No previous element"); XML_StopParser(currFile->parser, 0); } else { clearText(); ACCUMULATE_TEXT; } } else if (currFile->context == UNIT || currFile->context == ALIASES) { if (currFile->unit == NULL) { ut_set_status(UT_PARSE); ut_handle_error_message( "No previous , , or element"); XML_StopParser(currFile->parser, 0); } else { currFile->noPLural = 0; currFile->singular[0] = 0; currFile->plural[0] = 0; currFile->context = currFile->context == UNIT ? UNIT_NAME : ALIAS_NAME; } } else { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } } /* * Handles the end of a element. */ static void endName( void* data) { if (currFile->context == PREFIX) { if (!currFile->haveValue) { ut_set_status(UT_PARSE); ut_handle_error_message("No previous element"); XML_StopParser(currFile->parser, 0); } else { if (ut_add_name_prefix(unitSystem, text, currFile->value) != UT_SUCCESS) { ut_set_status(UT_PARSE); ut_handle_error_message( "Couldn't map name-prefix \"%s\" to value %g", text, currFile->value); XML_StopParser(currFile->parser, 0); } else { currFile->prefixAdded = 1; } } } else if (currFile->context == UNIT_NAME) { if (currFile->singular[0] == 0) { ut_set_status(UT_PARSE); ut_handle_error_message(" needs a "); XML_StopParser(currFile->parser, 0); } else { if (!mapUnitAndName(currFile->unit, currFile->singular, currFile->textEncoding)) { XML_StopParser(currFile->parser, 0); } else { if (!currFile->noPLural) { const char* plural = NULL; if (currFile->plural[0] != 0) { plural = currFile->plural; } else if (currFile->singular[0] != 0) { plural = ut_form_plural(currFile->singular); if (plural == NULL) { ut_set_status(UT_PARSE); ut_handle_error_message("Couldn't form plural of " "\"%s\"", currFile->singular); XML_StopParser(currFile->parser, 0); } } if (plural != NULL) { /* * Because the unit is already mapped to the singular * name, it is not mapped to the plural name. */ if (!mapNamesToUnit(plural, currFile->textEncoding, currFile->unit)) { XML_StopParser(currFile->parser, 0); } } } /* not specified */ if (strcmp(currFile->singular, "second") == 0) { if (ut_set_second(currFile->unit) != UT_SUCCESS) { ut_handle_error_message( "Couldn't set \"second\" unit in unit-system"); XML_StopParser(currFile->parser, 0); } } /* unit was 'second' unit */ } /* unit mapped to singular name */ } /* singular name specified */ currFile->nameSeen = 1; currFile->context = UNIT; } /* defining name for unit */ else if (currFile->context == ALIAS_NAME) { if (currFile->singular[0] == 0) { ut_set_status(UT_PARSE); ut_handle_error_message(" needs a "); XML_StopParser(currFile->parser, 0); } else { if (!mapNamesToUnit(currFile->singular, currFile->textEncoding, currFile->unit)) { XML_StopParser(currFile->parser, 0); } if (!currFile->noPLural) { const char* plural = NULL; if (currFile->plural[0] != 0) { plural = currFile->plural; } else if (currFile->singular[0] != 0) { plural = ut_form_plural(currFile->singular); if (plural == NULL) { ut_set_status(UT_PARSE); ut_handle_error_message("Couldn't form plural of " "\"%s\"", currFile->singular); XML_StopParser(currFile->parser, 0); } } if (plural != NULL) { if (!mapNamesToUnit(plural, currFile->textEncoding, currFile->unit)) XML_StopParser(currFile->parser, 0); } } /* not specified */ } /* singular name specified */ currFile->context = ALIASES; } /* defining name for alias */ else { assert(0); } } /* * Handles the start of a element. */ static void startSingular( void* data, const char** atts) { if (currFile->context != UNIT_NAME && currFile->context != ALIAS_NAME) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } else if (currFile->singular[0] != 0) { ut_set_status(UT_PARSE); ut_handle_error_message(" element already seen"); XML_StopParser(currFile->parser, 0); } else { clearText(); ACCUMULATE_TEXT; } } /* * Handles the end of a element. */ static void endSingular( void* data) { if (nbytes >= NAME_SIZE) { ut_set_status(UT_PARSE); ut_handle_error_message("Name \"%s\" is too long", text); XML_StopParser(currFile->parser, 0); } else { (void)strcpy(currFile->singular, text); } } /* * Handles the start of a element. */ static void startPlural( void* data, const char** atts) { if (currFile->context != UNIT_NAME && currFile->context != ALIAS_NAME ) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } else if (currFile->noPLural || currFile->plural[0] != 0) { ut_set_status(UT_PARSE); ut_handle_error_message(" or element already seen"); XML_StopParser(currFile->parser, 0); } else { clearText(); ACCUMULATE_TEXT; } } /* * Handles the end of a element. */ static void endPlural( void* data) { if (nbytes == 0) { ut_set_status(UT_PARSE); ut_handle_error_message("Empty element"); XML_StopParser(currFile->parser, 0); } else if (nbytes >= NAME_SIZE) { ut_set_status(UT_PARSE); ut_handle_error_message("Plural name \"%s\" is too long", text); XML_StopParser(currFile->parser, 0); } else { (void)strcpy(currFile->plural, text); } } /* * Handles the start of a element. */ static void startNoPlural( void* data, const char** atts) { if (currFile->context != UNIT_NAME && currFile->context != ALIAS_NAME) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } else if (currFile->plural[0] != 0) { ut_set_status(UT_PARSE); ut_handle_error_message(" element already seen"); XML_StopParser(currFile->parser, 0); } } /* * Handles the end of a element. */ static void endNoPlural( void* data) { currFile->noPLural = 1; } /* * Handles the start of a element. */ static void startSymbol( void* data, const char** atts) { if (currFile->context == PREFIX) { if (!currFile->haveValue) { ut_set_status(UT_PARSE); ut_handle_error_message("No previous element"); XML_StopParser(currFile->parser, 0); } else { clearText(); ACCUMULATE_TEXT; } } else if (currFile->context == UNIT || currFile->context == ALIASES) { if (currFile->unit == NULL) { ut_set_status(UT_PARSE); ut_handle_error_message( "No previous , , or element"); XML_StopParser(currFile->parser, 0); } else { clearText(); ACCUMULATE_TEXT; } } else { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } } /* * Handles the end of a element. */ static void endSymbol( void* data) { if (currFile->context == PREFIX) { if (ut_add_symbol_prefix(unitSystem, text, currFile->value) != UT_SUCCESS) { ut_set_status(UT_PARSE); ut_handle_error_message( "Couldn't map symbol-prefix \"%s\" to value %g", text, currFile->value); XML_StopParser(currFile->parser, 0); } else { currFile->prefixAdded = 1; } } else if (currFile->context == UNIT) { if (!mapUnitAndSymbol(currFile->unit, text, currFile->textEncoding)) XML_StopParser(currFile->parser, 0); currFile->symbolSeen = 1; } else if (currFile->context == ALIASES) { if (!mapSymbolsToUnit(text, currFile->textEncoding, currFile->unit)) XML_StopParser(currFile->parser, 0); } } /* * Handles the start of a element. */ static void startValue( void* data, const char** atts) { if (currFile->context != PREFIX) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } else if (currFile->haveValue) { ut_set_status(UT_PARSE); ut_handle_error_message(" element already seen"); XML_StopParser(currFile->parser, 0); } else { clearText(); ACCUMULATE_TEXT; } } /* * Handles the end of a element. */ static void endValue( void* data) { char* endPtr; errno = 0; currFile->value = strtod(text, &endPtr); if (errno != 0) { ut_set_status(UT_PARSE); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't decode numeric prefix value \"%s\"", text); XML_StopParser(currFile->parser, 0); } else if (*endPtr != 0) { ut_set_status(UT_PARSE); ut_handle_error_message("Invalid numeric prefix value \"%s\"", text); XML_StopParser(currFile->parser, 0); } else { currFile->haveValue = 1; } } /* * Handles the start of an element. */ static void startAliases( void* data, const char** atts) { if (currFile->context != UNIT) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } currFile->context = ALIASES; } /* * Handles the end of an element. */ static void endAliases( void* data) { currFile->context = UNIT; } /* * Handles the start of an element. */ static void startImport( void* data, const char** atts) { if (currFile->context != UNIT_SYSTEM) { ut_set_status(UT_PARSE); ut_handle_error_message("Wrong place for element"); XML_StopParser(currFile->parser, 0); } else { clearText(); ACCUMULATE_TEXT; } } /* * Handles the end of an element. */ static void endImport( void* data) { char buf[_XOPEN_PATH_MAX]; const char* path; if (text[0] == '/') { path = text; } else { (void)snprintf(buf, sizeof(buf), "%s/%s", XML_GetBase(currFile->parser), text); buf[sizeof(buf)-1] = 0; path = buf; } ut_set_status(readXml(path)); if (ut_get_status() != UT_SUCCESS) XML_StopParser(currFile->parser, 0); } /* * Handles the start of an element. */ static void startElement( void* data, const XML_Char* name, const XML_Char** atts) { if (currFile->skipDepth) { currFile->skipDepth++; } else { clearText(); if (strcasecmp(name, "unit-system") == 0) { startUnitSystem(data, atts); } else if (strcasecmp(name, "prefix") == 0) { startPrefix(data, atts); } else if (strcasecmp(name, "unit") == 0) { startUnit(data, atts); } else if (strcasecmp(name, "base") == 0) { startBase(data, atts); } else if (strcasecmp(name, "dimensionless") == 0) { startDimensionless(data, atts); } else if (strcasecmp(name, "def") == 0) { startDef(data, atts); } else if (strcasecmp(name, "value") == 0) { startValue(data, atts); } else if (strcasecmp(name, "name") == 0) { startName(data, atts); } else if (strcasecmp(name, "singular") == 0) { startSingular(data, atts); } else if (strcasecmp(name, "plural") == 0) { startPlural(data, atts); } else if (strcasecmp(name, "symbol") == 0) { startSymbol(data, atts); } else if (strcasecmp(name, "aliases") == 0) { startAliases(data, atts); } else if (strcasecmp(name, "import") == 0) { startImport(data, atts); } else { currFile->skipDepth = 1; } } } /* * Handles the end of an element. */ static void endElement( void* data, const XML_Char* name) { if (currFile->skipDepth != 0) { --currFile->skipDepth; } else { if (strcasecmp(name, "unit-system") == 0) { endUnitSystem(data); } else if (strcasecmp(name, "prefix") == 0) { endPrefix(data); } else if (strcasecmp(name, "unit") == 0) { endUnit(data); } else if (strcasecmp(name, "base") == 0) { endBase(data); } else if (strcasecmp(name, "dimensionless") == 0) { endDimensionless(data); } else if (strcasecmp(name, "def") == 0) { endDef(data); } else if (strcasecmp(name, "value") == 0) { endValue(data); } else if (strcasecmp(name, "name") == 0) { endName(data); } else if (strcasecmp(name, "singular") == 0) { endSingular(data); } else if (strcasecmp(name, "plural") == 0) { endPlural(data); } else if (strcasecmp(name, "symbol") == 0) { endSymbol(data); } else if (strcasecmp(name, "aliases") == 0) { endAliases(data); } else if (strcasecmp(name, "import") == 0) { endImport(data); } else { ut_set_status(UT_PARSE); ut_handle_error_message("Unknown element \"<%s>\"", name); XML_StopParser(currFile->parser, 0); } } IGNORE_TEXT; } /* * Handles the header of an XML file. */ static void declareXml( void* data, const char* version, const char* encoding, int standalone) { if (strcasecmp(encoding, "US-ASCII") == 0) { currFile->xmlEncoding = UT_ASCII; } else if (strcasecmp(encoding, "ISO-8859-1") == 0) { currFile->xmlEncoding = UT_LATIN1; } else if (strcasecmp(encoding, "UTF-8") == 0) { currFile->xmlEncoding = UT_UTF8; } else { ut_set_status(UT_PARSE); ut_handle_error_message("Unknown XML encoding \"%s\"", encoding); XML_StopParser(currFile->parser, 0); } } /* * Reads an XML file into the unit-system with the given XML parser. * * Arguments: * parser Pointer to the XML parser. * path Pointer to the pathname of the XML file. * Returns: * UT_SUCCESS Success. * UT_OPEN_ARG File "path" couldn't be opened. See "errno". * UT_OS Operating-system error. See "errno". * UT_PARSE Parse failure. */ static ut_status readXmlWithParser( XML_Parser parser, const char* const path) { ut_status status = UT_SUCCESS; /* success */ File file; assert(parser != NULL); assert(path != NULL); fileInit(&file); file.fd = open(path, O_RDONLY); if (file.fd == -1) { status = UT_OPEN_ARG; ut_set_status(status); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't open file \"%s\"", path); } else { int nbytes; File* const prevFile = currFile; file.path = path; file.parser = parser; currFile = &file; do { char buf[BUFSIZ]; /* from */ nbytes = read(file.fd, buf, sizeof(buf)); if (nbytes < 0) { status = UT_OS; ut_set_status(status); ut_handle_error_message(strerror(errno)); } else { if (XML_Parse(file.parser, buf, nbytes, nbytes == 0) != XML_STATUS_OK) { status = UT_PARSE; ut_set_status(status); ut_handle_error_message( XML_ErrorString(XML_GetErrorCode(file.parser))); } } } while (status == UT_SUCCESS && nbytes > 0); if (status != UT_SUCCESS) { /* * Parsing of the XML file terminated prematurely. */ ut_handle_error_message("File \"%s\", line %d, column %d", path, XML_GetCurrentLineNumber(file.parser), XML_GetCurrentColumnNumber(file.parser)); } currFile = prevFile; (void)close(file.fd); file.fd = -1; } /* "file.fd" open */ return status; } /* * Reads an XML file into the unit-system. * * Arguments: * path Pointer to the pathname of the XML file. * Returns: * UT_SUCCESS Success. * UT_OPEN_ARG File "path" couldn't be opened. See "errno". * UT_OS Operating-system error. See "errno". * UT_PARSE Parse failure. */ static ut_status readXml( const char* const path) { ut_status status; XML_Parser parser = XML_ParserCreate(NULL); if (parser == NULL) { status = UT_OS; ut_set_status(status); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't create XML parser"); } else { char base[_XOPEN_PATH_MAX]; (void)strncpy(base, path, sizeof(base)); base[sizeof(base)-1] = 0; (void)memmove(base, dirname(base), sizeof(base)); base[sizeof(base)-1] = 0; if (XML_SetBase(parser, base) != XML_STATUS_OK) { status = UT_OS; ut_set_status(status); ut_handle_error_message(strerror(errno)); ut_handle_error_message("XML_SetBase(\"%s\") failure", base); } else { XML_SetXmlDeclHandler(parser, declareXml); XML_SetElementHandler(parser, startElement, endElement); XML_SetCharacterDataHandler(parser, NULL); status = readXmlWithParser(parser, path); } /* parser "base" set */ XML_ParserFree(parser); } /* parser != NULL */ return status; } /** * Returns the pathname of the XML database. * * @param path The pathname of the XML file or NULL. * @param status Status. One of UT_OPEN_ARG, UT_OPEN_ENV, or UT_OPEN_DEFAULT. * @return If "path" is not NULL, then it is returned; otherwise, the * pathname specified by the environment variable * UDUNITS2_XML_PATH is returned if set; otherwise, the * compile-time pathname of the installed, default, unit * database is returned. */ const char* ut_get_path_xml( const char* path, ut_status* status) { if (path != NULL) { *status = UT_OPEN_ARG; } else { path = getenv("UDUNITS2_XML_PATH"); if (path != NULL) { *status = UT_OPEN_ENV; } else { path = DEFAULT_UDUNITS2_XML_PATH; *status = UT_OPEN_DEFAULT; } } return path; } /** * Returns the unit-system corresponding to an XML file. This is the usual way * that a client will obtain a unit-system. * * @param path The pathname of the XML file or NULL. If NULL, then the * pathname specified by the environment variable UDUNITS2_XML_PATH * is used if set; otherwise, the compile-time pathname of the * installed, default, unit database is used. * @retval NULL Failure. "ut_get_status()" will be one of the following: * UT_OPEN_ARG "path" is non-NULL but file couldn't be * opened. See "errno" for reason. * UT_OPEN_ENV "path" is NULL and environment variable * UDUNITS2_XML_PATH is set but file couldn't * be opened. See "errno" for reason. * UT_OPEN_DEFAULT "path" is NULL, environment variable * UDUNITS2_XML_PATH is unset, and the * installed, default, unit database couldn't * be opened. See "errno" for reason. * UT_PARSE Couldn't parse unit database. * UT_OS Operating-system error. See "errno". * @return Pointer to the unit-system defined by "path". */ ut_system* ut_read_xml( const char* path) { ut_set_status(UT_SUCCESS); unitSystem = ut_new_system(); if (unitSystem == NULL) { ut_handle_error_message("Couldn't create new unit-system"); } else { ut_status status; ut_status openError; status = readXml(ut_get_path_xml(path, &openError)); if (status == UT_OPEN_ARG) { status = openError; } if (status != UT_SUCCESS) { ut_free_system(unitSystem); unitSystem = NULL; } ut_set_status(status); } /* unitSystem != NULL */ return unitSystem; } udunits-2.2.0/lib/udunits-1.c0000644000175000017500000002756312260406756017130 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ #include #include #include #include #include #include #include "udunits.h" static ut_system* unitSystem = NULL; static ut_unit* encodedTimeUnit = NULL; static ut_unit* second = NULL; static char* buffer; static int buflen = 80; static void* unit2s = NULL; /* * Initialize the units(3) package. */ int utInit( const char *path) { int status; (void)ut_set_error_message_handler(ut_ignore); if (unitSystem != NULL) { ut_free_system(unitSystem); unitSystem = NULL; } unitSystem = ut_read_xml(NULL); if (unitSystem == NULL) { status = ut_get_status() == UT_PARSE ? UT_ESYNTAX : UT_EIO; } else { second = ut_get_unit_by_name(unitSystem, "second"); encodedTimeUnit = ut_offset_by_time(second, ut_encode_time(2001, 1, 1, 0, 0, 0.0)); buffer = malloc(buflen); if (buffer == NULL) { buflen = 0; status = UT_EALLOC; } else { status = 0; } } return status; } /* * Indicate if the units(3) package has been initialized. */ int utIsInit() { return unitSystem != NULL; } static int compare( const void* key1, const void* key2) { return key1 < key2 ? -1 : key1 == key2 ? 0 : 1; } static void freeIfAllocated( utUnit* const unit) { if (tdelete(unit->unit2, &unit2s, compare) != NULL) { ut_free(unit->unit2); } unit->unit2 = NULL; } void utFree( utUnit* const unit) { freeIfAllocated(unit); } void utIni( utUnit* const unit) { if (unit != NULL) { unit->unit2 = NULL; } } static int setUnit( utUnit* const unit, ut_unit* const unit2) { int status; if (tsearch(unit2, &unit2s, compare) == NULL) { status = UT_EALLOC; } else { freeIfAllocated(unit); unit->unit2 = unit2; status = 0; } return status; } /* * Decode a formatted unit specification into a unit-structure. */ int utScan( const char *spec, utUnit *unit) { int status; if (spec == NULL || unit == NULL) { status = UT_EINVALID; } else { ut_unit* ut_unit = ut_parse(unitSystem, spec, UT_ASCII); if (ut_unit != NULL) { status = setUnit(unit, ut_unit); } else { status = ut_get_status(); if (status == UT_BAD_ARG) { status = unitSystem == NULL ? UT_ENOINIT : UT_EINVALID; } else if (status == UT_SYNTAX) { status = UT_ESYNTAX; } else if (status == UT_UNKNOWN) { status = UT_EUNKNOWN; } else { status = UT_EALLOC; } } } return status; } /* * Convert a temporal value into a UTC Gregorian date and time. */ int utCalendar( double value, const utUnit *unit, int *year, int *month, int *day, int *hour, int *minute, float *second) { int status = 0; /* success */ cv_converter* converter = ut_get_converter(unit->unit2, encodedTimeUnit); if (converter == NULL) { status = encodedTimeUnit == NULL ? UT_ENOINIT : UT_EINVALID; } else { double encodedTime = cv_convert_double(converter, value); double sec, res; ut_decode_time(encodedTime, year, month, day, hour, minute, &sec, &res); *second = (float)sec; cv_free(converter); } return status; } /* * Convert a date into a temporal value. The date is assumed to * use the Gregorian calendar if on or after noon, October 15, 1582; * otherwise, the date is assumed to use the Julian calendar. */ int utInvCalendar( int year, int month, int day, int hour, int minute, double second, const utUnit *unit, double *value) { int status = 0; /* success */ cv_converter* converter = ut_get_converter(encodedTimeUnit, unit->unit2); if (converter == NULL) { status = encodedTimeUnit == NULL ? UT_ENOINIT : UT_EINVALID; } else { double encodedTime = ut_encode_time(year, month, day, hour, minute, second); *value = cv_convert_double(converter, encodedTime); cv_free(converter); } return status; } static ut_status isTimeVisitBasic( const ut_unit* unit, void* arg) { return (ut_status)ut_are_convertible(unit, second); } static ut_status isTimeVisitProduct( const ut_unit* unit, int count, const ut_unit* const* basicUnits, const int* powers, void* arg) { int isTime; if (!ut_are_convertible(unit, second)) { isTime = 0; } else { int i; isTime = 0; for (i = 0; i < count; i++) { if (ut_are_convertible(basicUnits[i], second) && powers[i] == 1) { isTime = 1; break; } } } return (ut_status)isTime; } static ut_status isTimeVisitGalilean( const ut_unit* unit, double scale, const ut_unit* underlyingUnit, double origin, void* arg) { return (ut_status)0; } static ut_status isTimeVisitTimestamp( const ut_unit* unit, const ut_unit* timeUnit, double origin, void* arg) { return (ut_status)1; } static ut_status isTimeVisitLogarithmic( const ut_unit* unit, double base, const ut_unit* reference, void* arg) { return (ut_status)0; } /* * Indicate if a unit structure refers to a unit of time. */ int utIsTime( const utUnit *up) { ut_visitor visitor; visitor.visit_basic = isTimeVisitBasic; visitor.visit_product = isTimeVisitProduct; visitor.visit_galilean = isTimeVisitGalilean; visitor.visit_timestamp = isTimeVisitTimestamp; visitor.visit_logarithmic = isTimeVisitLogarithmic; return ut_accept_visitor(up->unit2, &visitor, NULL); } static ut_status hasOriginVisitBasic( const ut_unit* unit, void* arg) { return (ut_status)0; } static ut_status hasOriginVisitProduct( const ut_unit* unit, int count, const ut_unit* const* basicUnits, const int* powers, void* arg) { return (ut_status)0; } static ut_status hasOriginVisitGalilean( const ut_unit* unit, double scale, const ut_unit* underlyingUnit, double origin, void* arg) { return (ut_status)1; } static ut_status hasOriginVisitTimestamp( const ut_unit* unit, const ut_unit* timeUnit, double origin, void* arg) { return (ut_status)1; } static ut_status hasOriginVisitLogarithmic( const ut_unit* unit, double base, const ut_unit* reference, void* arg) { return (ut_status)0; } /* * Indicate if a unit structure has an origin. */ int utHasOrigin( const utUnit *up) { ut_visitor visitor; visitor.visit_basic = hasOriginVisitBasic; visitor.visit_product = hasOriginVisitProduct; visitor.visit_galilean = hasOriginVisitGalilean; visitor.visit_timestamp = hasOriginVisitTimestamp; visitor.visit_logarithmic = hasOriginVisitLogarithmic; return ut_accept_visitor(up->unit2, &visitor, NULL); } static utUnit* resultingUnit( utUnit* result, ut_unit* const unit2) { if (unit2 == NULL) { result = NULL; } else if (result != NULL) { if (setUnit(result, unit2) != 0) { result == NULL; } } return result; } /* * Clear a unit structure. */ utUnit* utClear( utUnit *unit) { return resultingUnit(unit, ut_get_dimensionless_unit_one(unitSystem)); } /* * Copy a unit-structure. */ utUnit* utCopy( const utUnit *source, utUnit *dest) { return source == NULL ? NULL : dest == NULL ? NULL : resultingUnit(dest, ut_clone(source->unit2)); } /* * Multiply one unit-structure by another. */ utUnit* utMultiply( const utUnit *term1, const utUnit *term2, utUnit *result) { return term1 == NULL || term2 == NULL ? NULL : resultingUnit(result, ut_multiply(term1->unit2, term2->unit2)); } /* * Divide one unit-structure by another. */ utUnit* utDivide( const utUnit *numer, const utUnit *denom, utUnit *result) { return numer == NULL || denom == NULL ? NULL : resultingUnit(result, ut_divide(numer->unit2, denom->unit2)); } /* * Form the reciprocal of a unit-structure. */ utUnit* utInvert( const utUnit *unit, utUnit *result) { return unit == NULL ? NULL : resultingUnit(result, ut_invert(unit->unit2)); } /* * Raise a unit-structure to a power. */ utUnit* utRaise( const utUnit *unit, int power, utUnit *result) { return unit == NULL ? NULL : resultingUnit(result, ut_raise(unit->unit2, power)); } /* * Shift the origin of a unit-structure by an arithmetic amount. */ utUnit* utShift( const utUnit *unit, double amount, utUnit *result) { return unit == NULL ? NULL : resultingUnit(result, ut_offset(unit->unit2, amount)); } /* * Scale a unit-structure. */ utUnit* utScale( const utUnit *unit, double factor, utUnit *result) { return unit == NULL ? NULL : resultingUnit(result, ut_scale(factor, unit->unit2)); } /* * Compute the conversion factor between two unit-structures. */ int utConvert( const utUnit *from, const utUnit *to, double *slope, double *intercept) { int status; cv_converter* converter = ut_get_converter(from->unit2, to->unit2); if (converter == NULL) { status = ut_get_status(); if (status == UT_BAD_ARG) { status = UT_EINVALID; } else if (status == UT_NOT_SAME_SYSTEM) { status = UT_ENOINIT; } else if (status == UT_MEANINGLESS) { status = UT_ECONVERT; } else { status = UT_EALLOC; } } else { *intercept = cv_convert_double(converter, 0.0); *slope = cv_convert_double(converter, 1.0) - *intercept; status = 0; } return status; } /* * Encode a unit-structure into a formatted unit-specification. */ int utPrint( const utUnit *unit, char **buf) { int status; for (;;) { int len = ut_format(unit->unit2, buffer, buflen, UT_ASCII); if (len == -1) { status = ut_get_status(); if (status == UT_BAD_ARG) { status = UT_EINVALID; } else { status = UT_EALLOC; } break; } if (len < buflen) { *buf = buffer; status = 0; break; } else { int newLen = buflen * 2; char* newBuf = malloc(newLen); if (newBuf == NULL) { status = UT_EALLOC; break; } buffer = newBuf; buflen = newLen; } } return status; } /* * Add a unit to the units database. */ int utAdd( char *name, int hasPlural, const utUnit *unit) { int status = ut_map_name_to_unit(name, UT_ASCII, unit->unit2); if (status == UT_SUCCESS) { status = ut_map_unit_to_name(unit->unit2, name, UT_ASCII); if (status == UT_SUCCESS) { if (!hasPlural) { status = UT_SUCCESS; } else { extern const char* ut_form_plural(const char*); const char* plural = ut_form_plural(name); status = ut_map_name_to_unit(plural, UT_ASCII, unit->unit2); } /* unit has plural name */ if (status != UT_SUCCESS) { (void)ut_unmap_unit_to_name(unit->unit2, UT_ASCII); } } /* unit mapped to name */ if (status != UT_SUCCESS) { (void)ut_unmap_name_to_unit(unitSystem, name, UT_ASCII); } } /* singular name mapped to unit */ return status == UT_SUCCESS ? 0 : status == UT_EXISTS ? UT_DUP : UT_EALLOC; } /* * Return the unit corresponding to a unit-specification. * */ int utFind( char *spec, utUnit *up) { int status; ut_unit* unit = ut_parse(unitSystem, spec, UT_ASCII); if (unit == NULL) { status = ut_get_status(); if (status == UT_BAD_ARG) { status = UT_EINVALID; } else if (status == UT_SYNTAX) { status = UT_ESYNTAX; } else if (status == UT_UNKNOWN) { status = UT_EUNKNOWN; } else if (status == UT_OS) { status = UT_EALLOC; } } else { status = setUnit(up, unit); } return status; } /* * Terminate use of this package. */ void utTerm() { ut_free(second); second = NULL; ut_free(encodedTimeUnit); encodedTimeUnit = NULL; ut_free_system(unitSystem); unitSystem = NULL; } udunits-2.2.0/lib/systemMap.h0000644000175000017500000000374412260406756017261 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ #ifndef UT_SYSTEM_MAP_H_INCLUDED #define UT_SYSTEM_MAP_H_INCLUDED #include "udunits2.h" typedef struct SystemMap SystemMap; #ifdef __cplusplus extern "C" { #endif /* * Returns a new instance of a system-map. * * Arguments: * compare Function for comparing keys. * Returns: * NULL Operating-system failure. See "errno". * else Pointer to the new map. */ SystemMap* smNew(); /* * Returns the address of the pointer to which a unit-system maps. * * Arguments: * map Pointer to the system-map. * system Pointer to the unit-system. * Returns: * NULL There is no pointer associated with "system". * else Address of the pointer to which "system" maps. */ void** smFind( const SystemMap* const map, const void* const system); /* * Returns the address of the pointer to which a unit-system maps -- creating a * new entry if necessary. If a new entry is created, then the pointer whose * address is returned will be NULL. * * Arguments: * map Pointer to the system-map. * system Pointer to the unit-system. * Returns: * NULL Operating system failure. See "errno". * else Address of the pointer to which "system" maps. */ void** smSearch( SystemMap* const map, const void* system); /* * Removes the system-map entry that corresponds to a unit-system. * * Arguments: * map Pointer to the map. * system Pointer to the unit-system. */ void smRemove( SystemMap* const map, const void* const system); /* * Frees a system-map. This function should be called when a system-map is no * longer needed. * * Arguments: * map Pointer to the system-map to be freed or NULL. Use of "map" * upon return results in undefined behavior. */ void smFree( SystemMap* const map); #ifdef __cplusplus } #endif #endif udunits-2.2.0/lib/error.c0000644000175000017500000000474212260406756016422 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * This module is thread-compatible but not thread-safe. Multi-threaded * access must be externally synchronized. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include "udunits2.h" /* * Writes an error-message to the standard-error stream when received and * appends a newline. This is the initial error-message handler. * * Arguments: * fmt The format for the error-message. * args The arguments of "fmt". * Returns: * <0 A output error was encountered. See "errno". * else The number of bytes of "fmt" and "arg" written excluding any * terminating NUL. */ int ut_write_to_stderr( const char* const fmt, va_list args) { int nbytes = vfprintf(stderr, fmt, args); (void)fputc('\n', stderr); return nbytes; } /* * Does nothing with an error-message. * * Arguments: * fmt The format for the error-message. * args The arguments of "fmt". * Returns: * 0 Always. */ int ut_ignore( const char* const fmt, va_list args) { return 0; } static ut_error_message_handler errorMessageHandler = ut_write_to_stderr; /* * Returns the previously-installed error-message handler and optionally * installs a new handler. The initial handler is "ut_write_to_stderr()". * * Arguments: * handler NULL or pointer to the error-message handler. If NULL, * then the handler is not changed. The * currently-installed handler can be obtained this way. * Returns: * Pointer to the previously-installed error-message handler. */ ut_error_message_handler ut_set_error_message_handler( ut_error_message_handler handler) { ut_error_message_handler prev = errorMessageHandler; if (handler != NULL) errorMessageHandler = handler; return prev; } /* * Handles an error-message. * * Arguments: * fmt The format for the error-message. * ... The arguments for "fmt". * Returns: * <0 An output error was encountered. * else The number of bytes of "fmt" and "arg" written excluding any * terminating NUL. */ int ut_handle_error_message( const char* const fmt, ...) { int nbytes; va_list args; va_start(args, fmt); nbytes = errorMessageHandler(fmt, args); va_end(args); return nbytes; } udunits-2.2.0/lib/unitToIdMap.h0000644000175000017500000000113112260406756017460 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ #ifndef UT_UNIT_TO_ID_MAP_H_INCLUDED #define UT_UNIT_TO_ID_MAP_H_INCLUDED #ifdef __cplusplus extern "C" { #endif /* * Frees resources associated with a unit-system. * * Arguments: * system Pointer to the unit-system to have its associated * resources freed. */ void utimFreeSystem( ut_system* system); #ifdef __cplusplus } #endif #endif udunits-2.2.0/lib/status.c0000644000175000017500000000162712260406756016613 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Status of the last operation by the UDUNITS2(3) library. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include "udunits2.h" static ut_status _status = UT_SUCCESS; /* * Returns the status of the last operation by the units module. This function * will not change the status. */ ut_status ut_get_status() { return _status; } /* * Sets the status of the units module. This function would not normally be * called by the user unless they were doing their own parsing or formatting. * * Arguments: * status The status of the units module. */ void ut_set_status( const ut_status status) { _status = status; } udunits-2.2.0/lib/udunits2lib.info0000644000175000017500000023162612260406756020251 0ustar amckinstryamckinstryThis is udunits2lib.info, produced by makeinfo version 4.13 from udunits2lib.texi. INFO-DIR-SECTION Software libraries START-INFO-DIR-ENTRY * UDUNITS-2: (udunits2lib). The Unidata units library. END-INFO-DIR-ENTRY Copyright 2013 University Corporation for Atmospheric Research. All rights reserved. This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware. 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 CONTRIBUTORS 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 WITH THE SOFTWARE.  File: udunits2lib.info, Node: Top, Next: Synopsis, Prev: (dir), Up: (dir) UDUNITS-2 ********* This manual describes how to use the C API of the UDUNITS-2 library. Among other things, the library allows C code to obtain a binary representation of a unit of a physical quantity, to operate on such units, and to convert numeric values between compatible units. The library comes with an extensive database of units all referenced to the SI system of units. Copyright 2013 University Corporation for Atmospheric Research. All rights reserved. This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware. 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 CONTRIBUTORS 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 WITH THE SOFTWARE. * Menu: * Synopsis:: Terse usage display * Why:: What's a unit package good for? * Unit-Systems:: Explanation of unit-systems and how to get one * Parsing:: Converting strings into units * Syntax:: Syntax for string representation of units * Formatting:: Converting units into strings * Value Conversion:: Converting values between units * Prefixes:: Defining unit prefixes * Mapping:: Mapping between units and identifiers * Operations:: Operations on units * Time:: Handling time * Errors:: Error-handling * Database:: The units database * Types:: Data types * Complete Index:: Complete index  File: udunits2lib.info, Node: Synopsis, Next: Why, Prev: Top, Up: Top 1 Synopsis ********** Coding: #include ut_system* ut_get_path_xml(const char* PATH); ut_system* ut_read_xml(const char* PATH); ut_system* ut_new_system(void); void ut_free_system(ut_system* SYSTEM); ut_system* ut_get_system(const ut_unit* UNIT); ut_unit* ut_get_dimensionless_unit_one(const ut_system* SYSTEM); ut_unit* ut_get_unit_by_name(const ut_system* SYSTEM, const char* NAME); ut_unit* ut_get_unit_by_symbol(const ut_system* SYSTEM, const char* SYMBOL); ut_status ut_set_second(const ut_unit* SECOND); ut_status ut_add_name_prefix(ut_system* SYSTEM, const char* NAME, double VALUE); ut_status ut_add_symbol_prefix(ut_system* SYSTEM, const char* SYMBOL, double VALUE); ut_unit* ut_new_base_unit(ut_system* SYSTEM); ut_unit* ut_new_dimensionless_unit(ut_system* SYSTEM); ut_unit* ut_clone(const ut_unit* UNIT); void ut_free(ut_unit* UNIT); const char* ut_get_name(const ut_unit* UNIT, ut_encoding ENCODING); ut_status ut_map_name_to_unit(const char* NAME, const ut_encoding ENCODING, const ut_unit* UNIT); ut_status ut_unmap_name_to_unit(ut_system* SYSTEM, const char* NAME, const ut_encoding ENCODING); ut_status ut_map_unit_to_name(const ut_unit* UNIT, const char* NAME, ut_encoding ENCODING); ut_status ut_unmap_unit_to_name(const ut_unit* UNIT, ut_encoding ENCODING); const char* ut_get_symbol(const ut_unit* UNIT, ut_encoding ENCODING); ut_status ut_map_symbol_to_unit(const char* SYMBOL, const ut_encoding ENCODING, const ut_unit* UNIT); ut_status ut_unmap_symbol_to_unit(ut_system* SYSTEM, const char* SYMBOL, const ut_encoding ENCODING); ut_status ut_map_unit_to_symbol(const ut_unit* UNIT, const char* SYMBOL, ut_encoding ENCODING); ut_status ut_unmap_unit_to_symbol(const ut_unit* UNIT, ut_encoding ENCODING); int ut_is_dimensionless(const ut_unit* UNIT); int ut_same_system(const ut_unit* UNIT1, const ut_unit* UNIT2); int ut_compare(const ut_unit* UNIT1, const ut_unit* UNIT2); int ut_are_convertible(const ut_unit* UNIT1, const ut_unit* UNIT2); cv_converter* ut_get_converter(ut_unit* FROM, ut_unit* TO); ut_unit* ut_scale(double FACTOR, const ut_unit* UNIT); ut_unit* ut_offset(const ut_unit* UNIT, double OFFSET); ut_unit* ut_offset_by_time(const ut_unit* UNIT, double ORIGIN); ut_unit* ut_multiply(const ut_unit* UNIT1, const ut_unit* UNIT2); ut_unit* ut_invert(const ut_unit* UNIT); ut_unit* ut_divide(const ut_unit* NUMER, const ut_unit* DENOM); ut_unit* ut_raise(const ut_unit* UNIT, int POWER); ut_unit* ut_root(const ut_unit* UNIT, int ROOT); ut_unit* ut_log(double BASE, const ut_unit* REFERENCE); ut_unit* ut_parse(const ut_system* SYSTEM, const char* STRING, ut_encoding ENCODING); char* ut_trim(char* STRING, ut_encoding ENCODING); int ut_format(const ut_unit* UNIT, char* BUF, size_t SIZE, unsigned OPTS); ut_status ut_accept_visitor(const ut_unit* UNIT, const ut_visitor* VISITOR, void* ARG); double ut_encode_date(int YEAR, int MONTH, int DAY); double ut_encode_clock(int HOURS, int MINUTES, double SECONDS); double ut_encode_time(int YEAR, int MONTH, int DAY, int HOUR, int MINUTE, double SECOND); void ut_decode_time(double VALUE, int* YEAR, int* MONTH, int* DAY, int* HOUR, int* MINUTE, double* SECOND, double* RESOLUTION); ut_status ut_get_status(void); void ut_set_status(ut_status STATUS); int ut_handle_error_message(const char* FMT, ...); ut_error_message_handler ut_set_error_message_handler(ut_error_message_handler HANDLER); int ut_write_to_stderr(const char* FMT, va_list ARGS); int ut_ignore(const char* FMT, va_list ARGS); float cv_convert_float(const cv_converter* CONVERTER, float VALUE); double cv_convert_double(const cv_converter* CONVERTER, double VALUE); float* cv_convert_floats(const cv_converter* CONVERTER, const float* IN, size_t COUNT, float* OUT); double* cv_convert_doubles(const cv_converter* CONVERTER, const double* CONST in, SIZE_T count, DOUBLE* out); void cv_free(cv_converter* CONV); Compiling: c89 -I _includedir_ ... Where _includedir_ is the installation-directory for C header files (e.g., `/usr/local/include'). Linking: c89 ... -L_libdir_ -ludunits2 -lexpat ... -lm Where _libdir_ is the installation-directory for object code libraries (e.g., `/usr/local/lib').  File: udunits2lib.info, Node: Why, Next: Unit-Systems, Prev: Synopsis, Up: Top 2 What's a Unit Package Good For? ********************************* The existance of a software package is justified by what you can do with it. The three main things you can do with the UDUNIT-2 package are 1. *note Convert numeric values between compatible units: Value Conversion. 2. Convert a string representation of a unit into a binary one -- enabling the programatic manipulation of units. There are three ways to do this: * *note Get the unit: Extracting. from a *note unit-system::. This requires that you know the unit's name or symbol and that the unit is in a unit-system. * *note Parse a string representation of the unit into its binary representation: Parsing. This requires that the string be parsable by `*note ut_parse()::'. * *note Explicity construct the unit from subcomponent units using unit operations: Operations. 3. *note Convert a binary representation of a unit into a string: Formatting. -- enabling the printing and storing of units in a human-readable form. While the above might seem to be trivial activities, their general availability at the time might have helped prevent the Mars Climate Orbiter (http://en.wikipedia.org/wiki/Mars_Climate_Orbiter) fiasco.  File: udunits2lib.info, Node: Unit-Systems, Next: Value Conversion, Prev: Why, Up: Top 3 Unit-Systems ************** A unit-system is a set of units that are all defined in terms of the same set of base units. In the SI system of units, for example, the base units are the meter, kilogram, second, ampere, kelvin, mole, and candela. (For definitions of these base units, see `http://physics.nist.gov/cuu/Units/current.html'.) In the UDUNITS-2 package, every accessible unit belongs to one and only one unit-system. It is not possible to convert numeric values between units of different unit-systems. Similarly, units belonging to different unit-systems always compare unequal. There are several categories of operations on unit-systems: * Menu: * Obtaining:: How to obtain a unit-system. * Extracting:: Getting a unit from a unit-system. * Adding:: Adding new units to a unit-system. * Prefixes:: Add new unit-prefixes to a unit-system. * Misc:: Miscelaneous unit-system operations.  File: udunits2lib.info, Node: Obtaining, Next: Extracting, Up: Unit-Systems 3.1 Obtaining a Unit-System =========================== Typically, you would obtain a unit-system of predefined units by reading the default unit database using `*note ut_read_xml()::' with a `NULL' pathname argument. If this doesn't quite match your needs, then there are alternatives. Together with the typical solution, the means for obtaining a useful unit-system are (in order of increasing complexity): * Obtain the default unit-system using `*note ut_read_xml: ut_read_xml().(NULL)'. * Copy and customize the unit database and then call `*note ut_read_xml()::' with the pathname of the customized database to obtain a customized unit-system. * Same as either of the above but then adding new units to the unit-system using `*note ut_new_base_unit()::' and `*note ut_new_dimensionless_unit()::'. * Same as the above but also deriving new units using *note unit operations: Operations. and then adding them to the unit-system using *note unit mapping: Mapping. * Same as the above but starting with an empty unit-system obtained from `*note ut_new_system()::', in which case you will definitely have to start with `*note ut_new_base_unit()::' and `*note ut_new_dimensionless_unit()::'. You should pass every unit-system pointer to `*note ut_free_system()::' when you no longer need the corresponding unit-system. -- Function: `const char*' ut_get_path_xml `(const char* PATH, ut_status* status)' Returns the pathname of the XML-formatted unit-database corresponding to PATH. If PATH is non-`NULL', then it is returned; otherwise, if the environment variable `UDUNITS2_XML_PATH' is set, then its value is returned; otherwise, the pathname of the default unit-database is returned. The value of `*status' indicates which of these possibilities occurred: `UT_OPEN_ARG' PATH is non-`NULL' and was returned. `UT_OPEN_ENV' PATH is `NULL', the environment variable `UDUNITS2_XML_PATH' is set, and its value was returned. `UT_OPEN_DEFAULT' PATH is `NULL', the environment variable `UDUNITS2_XML_PATH' is unset, and the pathname of the default unit-database was returned. -- Function: `ut_system*' ut_read_xml `(const char* PATH)' Reads the XML-formatted unit-database specified by PATH and returns the corresponding unit-sytem. If PATH is `NULL', then the pathname specified by the environment variable `UDUNITS2_XML_PATH' is used if set; otherwise, the compile-time pathname of the installed, default, unit database is used. You should pass the returned pointer to `ut_free_system()' when you no longer need the unit-system. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return one of the following: `UT_OPEN_ARG' PATH is non-`NULL' but the file couldn't be opened. See `errno' for the reason. `UT_OPEN_ENV' PATH is `NULL' and environment variable `UDUNITS2_XML_PATH' is set but the file couldn't be opened. See `errno' for the reason. `UT_OPEN_DEFAULT' PATH is `NULL', environment variable `UDUNITS2_XML_PATH' is unset, and the installed, default, unit database couldn't be opened. See `errno' for the reason. `UT_OS' Operating-system error. See `errno'. `UT_PARSE' The database file couldn't be parsed. -- Function: `ut_system*' ut_new_system `(void)' Creates and returns a new unit-system. On success, the unit-system will be empty except for the dimensionless unit one. You should pass the returned pointer to `ut_free_system()' when you no longer need the unit-system. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return the following: `UT_OS' Operating-system error. See `errno'.  File: udunits2lib.info, Node: Extracting, Next: Adding, Prev: Obtaining, Up: Unit-Systems 3.2 Extracting Units from a Unit-System ======================================= *NOTE\:* This section covers low-level access to the indidual units of a *note unit-system::. General parsing of arbitrary unit specifications is coverted in the section *note Parsing::. A *note unit-system:: contains mappings from identifiers to units (and vice versa). Consequently, once you have a unit-system, you can easily obtain a unit for which you know the name or symbol using the function `*note ut_get_unit_by_name()::' or `*note ut_get_unit_by_symbol()::'. -- Function: `ut_unit*' ut_get_unit_by_name `(const ut_system* SYSTEM, const char* NAME)' Returns the unit to which NAME maps from the unit-system referenced by SYSTEM or `NULL' if no such unit exists. Name comparisons are case-insensitive. If this function returns `NULL', then `*note ut_get_status()::' will return one of the following: `UT_SUCCESS' NAME doesn't map to a unit of SYSTEM. `UT_BAD_ARG' SYSTEM or NAME is `NULL'. -- Function: `ut_unit*' ut_get_unit_by_symbol `(const ut_system* SYSTEM, const char* SYMBOL)' Returns the unit to which SYMBOL maps from the unit-system referenced by SYSTEM or `NULL' if no such unit exists. Symbol comparisons are case-sensitive. If this function returns `NULL', then `*note ut_get_status()::' will return one of the following: `UT_SUCCESS' SYMBOL doesn't map to a unit of SYSTEM. `UT_BAD_ARG' SYSTEM or SYMBOL is `NULL'. -- Function: `ut_unit*' ut_get_dimensionless_unit_one `(const ut_system* SYSTEM)' Returns the dimensionless unit one of the unit-system referenced by SYSTEM. While not necessary, the returned pointer may be passed to `ut_free()' when you no longer need the unit. If SYSTEM is `NULL', then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return `UT_BAD_ARG'.  File: udunits2lib.info, Node: Adding, Next: Prefixes, Prev: Extracting, Up: Unit-Systems 3.3 Adding Units to a Unit-System ================================= If you use `*note ut_read_xml()::', then you should not normally need to add any new units to a unit-system. Because you get units via their names or symbols, adding a unit to a unit-system actually means mapping one or more identifiers (i.e., names or symbols) to the unit. Thereafter, you can use `*note ut_get_unit_by_name()::' and `*note ut_get_unit_by_symbol()::' to retrieve the unit. The mapping of identifiers to units is covered *note here: Mapping. Having said that, it is possible to create a new base or dimensionless unit within a unit-system using `*note ut_new_base_unit()::' or `*note ut_new_dimensionless_unit()::'--you'll just also have to map identifiers to the newly-created unit in order to be able to retrieve it later by identifier. -- Function: `ut_unit*' ut_new_base_unit `(ut_system* SYSTEM)' Creates and adds a new base-unit to the unit-system referenced by SYSTEM. This function returns the new base-unit. You should pass the returned pointer to `ut_free()' when you no longer need the unit. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' SYSTEM is `NULL'. `UT_OS' Operating-system failure. See `errno'. If you use `*note ut_read_xml()::', then you should not normally need to call this function. -- Function: `ut_unit*' ut_new_dimensionless_unit `(ut_system* SYSTEM)' Creates and adds a new dimensionless-unit to the unit-system referenced by SYSTEM. This function returns the new dimensionless-unit. You should pass the returned pointer to `ut_free()' when you no longer need the unit. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' SYSTEM is `NULL'. `UT_OS' Operating-system failure. See `errno'. If you use `*note ut_read_xml()::', then you should not normally need to call this function.  File: udunits2lib.info, Node: Prefixes, Next: Misc, Prev: Adding, Up: Unit-Systems 3.4 Adding Unit-Prefixes to a Unit-System ========================================= A prefix is a word or symbol that is appended to the beginning of a word or symbol that represents a unit in order to modify the value of that unit. For example, the prefix "kilo" in the word "kiloamperes" changes the value from one ampere to one-thousand amperes. If you use `*note ut_read_xml()::', then you should not normally need to add any new prefixes to a unit-system. -- Function: `*note ut_status::' ut_add_name_prefix `(ut_system* SYSTEM, const char* NAME, double VALUE)' Adds the name-prefix NAME with the value VALUE to the unit-system SYSTEM. A name-prefix is something like "mega" or "milli". Comparisons between name-prefixes are case-insensitive. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' SYSTEM or NAME is `NULL', or VALUE is `0'. `UT_EXISTS' NAME already maps to a different value. `UT_OS' Operating-system failure. See `errno'. -- Function: `*note ut_status::' ut_add_symbol_prefix `(ut_system* SYSTEM, const char* SYMBOL, double VALUE)' Adds the symbol-prefix SYMBOL with the value VALUE to the unit-system SYSTEM. A symbol-prefix is something like "M" or "m". Comparisons between symbol-prefixes are case-sensitive. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' SYSTEM or SYMBOL is `NULL', or VALUE is `0'. `UT_EXISTS' SYMBOL already maps to a different value. `UT_OS' Operating-system failure. See `errno'.  File: udunits2lib.info, Node: Misc, Prev: Prefixes, Up: Unit-Systems 3.5 Miscelaneous Operations on Unit-Systems =========================================== -- Function: `void' ut_free_system `(ut_system* SYSTEM)' Frees the unit-system referenced by SYSTEM. All unit-to-identifier and identifier-to-unit mappings are removed. Use of `system' after this function returns results in undefined behavior. -- Function: `*note ut_status::' ut_set_second `(const ut_unit* SECOND)' Sets the "second" unit of a unit-system. This function must be called before the first call to `ut_offset_by_time()' for a unit in the same unit-system. `*note ut_read_xml()::' calls this function if the unit-system it's reading contains a unit named "second". This function returns one of the following: `UT_SUCCESS' The "second" unit of SYSTEM was successfully set. `UT_EXISTS' The "second" unit of SYSTEM is set to a different unit. `UT_BAD_ARG' SECOND is `NULL'.  File: udunits2lib.info, Node: Value Conversion, Next: Parsing, Prev: Unit-Systems, Up: Top 4 Converting Values Between Units ********************************* You can convert numeric values in one unit to equivalent values in another, compatible unit by means of a converter. For example #include ... ut_unit* from = ...; ut_unit* to = ...; cv_converter* converter = ut_get_converter(from, to); double fromValue = ...; double toValue = cv_convert_double(converter, fromValue); cv_free(converter); The converter API is declared in the header-file `', which is automatically included by the UDUNITS-2 header-file (`') so you don't need to explicitly include it. -- Function: `int' ut_are_convertible `(const ut_unit* UNIT1, uconst t_unit* UNIT2)' Indicates if numeric values in unit UNIT1 are convertible to numeric values in unit UNIT2 via *note ut_get_converter()::. In making this determination, dimensionless units are ignored. This function returns a non-zero value if conversion is possible; otherwise, `0' is returned and *note ut_get_status():: will return one of the following: `UT_BAD_ARG' UNIT1 or UNIT2 is `NULL'. `UT_NOT_SAME_SYSTEM' UNIT1 and UNIT2 belong to different *note unit-system::s. `UT_SUCCESS' Conversion between the units is not possible (e.g., UNIT1 refers to a meter and UNIT2 refers to a kilogram. -- Function: `cv_converter*' ut_get_converter `(ut_unit* const FROM, ut_unit* const TO)' Creates and returns a converter of numeric values in the FROM unit to equivalent values in the TO unit. You should pass the returned pointer to `cv_free()' when you no longer need the converter. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' FROM or TO is `NULL'. `UT_NOT_SAME_SYSTEM' The units FROM and TO don't belong to the same unit-system. `UT_MEANINGLESS' The units belong to the same unit-system but conversion between them is meaningless (e.g., conversion between seconds and kilograms is meaningless). `UT_OS' Operating-system failure. See `errno'. -- Function: `float' cv_convert_float `(const cv_converter* CONVERTER, const float VALUE)' Converts the single floating-point value VALUE and returns the new value. -- Function: `double' cv_convert_double `(const cv_converter* CONVERTER, const double VALUE)' Converts the single double-precision value VALUE and returns the new value. -- Function: `float*' cv_convert_floats `(const cv_converter* CONVERTER, const float* IN, size_t COUNT, float* OUT)' Converts the COUNT floating-point values starting at IN, writing the new values starting at OUT and, as a convenience, returns OUT. The input and output arrays may overlap or be identical. -- Function: `double*' cv_convert_doubles `(const cv_converter* CONVERTER, const double* IN, size_t COUNT, double* OUT)' Converts the COUNT double-precision values starting at IN, writing the new values starting at OUT and, as a convenience, returns OUT. The input and output arrays may overlap or be identical. -- Function: `void' cv_free `(cv_converter* CONV)'; Frees resources associated with the converter referenced by CONV. You should call this function when you no longer need the converter. Use of CONV upon return results in undefined behavior.  File: udunits2lib.info, Node: Parsing, Next: Syntax, Prev: Value Conversion, Up: Top 5 Parsing a String into a Unit ****************************** Here's an example of parsing a string representation of a unit into its binary representation: #include #include ... ut_system* unitSystem = *note ut_read_xml(NULL): ut_read_xml().; const char* string = "kg.m2/s3"; ut_unit* watt = *note ut_parse: ut_parse().(unitSystem, string, UT_ASCII); if (watt == NULL) { /* Unable to parse string. */ } else { /* Life is good. */ } -- Function: `ut_unit*' ut_parse `(const ut_system* SYSTEM, const char* STRING, ut_encoding ENCODING)' Returns the binary unit representation corresponding to the string unit representation STRING in the character-set ENCODING using the unit-system SYSTEM. STRING must have no leading or trailing whitespace (see `*note ut_trim()::'). If an error occurs, then this function returns `NULL' and `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' SYSTEM or STRING is `NULL'. `UT_SYNTAX' STRING contained a syntax error. `UT_UNKNOWN' STRING contained an unknown identifier. `UT_OS' Operating-system failure. See `errno' for the reason. -- Function: `size_t' ut_trim `(char* STRING, ut_encoding ENCODING)' Removes all leading and trailing whitespace from the NUL-terminated string STRING. Returns STRING, which is modified if it contained leading or trailing whitespace.  File: udunits2lib.info, Node: Syntax, Next: Formatting, Prev: Parsing, Up: Top 6 Unit Syntax ************* For the most part, the UDUNITS-2 package follows the syntax for unit-strings promulgated by the US National Institute for Standards and Technology (NIST). Details, of which, can be found at `http://physics.nist.gov/cuu/Units/index.html'. The one general exception to this is the invention of a syntax for "offset"-units (e.g., the definition of the degree Celsius is "K @ 273.15"). * Menu: * Examples:: Examples of unit specifications * Grammar:: Formal unit grammar  File: udunits2lib.info, Node: Examples, Next: Grammar, Up: Syntax 6.1 Unit Specification Examples =============================== String Type Using Names Using Comment Symbols -------------------------------------------------------------------------------------------------------- Simple meter m Raised meter^2 m2 higher precedence than multiplying or dividing Product newton meter N.m Quotient meter per second m/s Scaled 60 second 60 s Prefixed kilometer km Offset kelvin from 273.15 K @ 273.15 lower precedence than multiplying or dividing Logarithmic lg(re milliwatt) lg(re mW) "lg" is base 10, "ln" is base e, and "lb" is base 2 Grouped (5 meter)/(30 second) (5 m)/(30 s) The above may be combined, e.g., "0.1 lg(re m/(5 s)^2) @ 50". You may also look at the `' elements in *note the units database: Database. to see examples of string unit specifications. You may use the `*note udunits2: (udunits2prog)Top.' utility to experiment with string unit specifications.  File: udunits2lib.info, Node: Grammar, Prev: Examples, Up: Syntax 6.2 Unit Grammar ================ Here is the unit-syntax understood by the UDUNITS-2 package. Words printed _Thusly_ indicate non-terminals; words printed THUSLY indicate terminals; and words printed indicate lexical elements. _Unit-Spec: one of_ nothing _Shift-Spec_ _Shift-Spec: one of_ _Product-Spec_ _Product-Spec_ SHIFT REAL _Product-Spec_ SHIFT INT _Product-Spec_ SHIFT _Timestamp_ _Product-Spec: one of_ _Power-Spec_ _Product-Spec_ _Power-Spec_ _Product-Spec_ MULTIPLY _Power-Spec_ _Product-Spec_ DIVIDE _Power-Spec_ _Power-Spec: one of_ _Basic-Spec_ _Basic-Spec_ INT _Basic-Spec_ EXPONENT _Basic-Spec_ RAISE INT _Basic-Spec: one of_ ID "(" _Shift-Spec_ ")" LOGREF _Product_Spec_ ")" _Number_ _Number: one of_ INT REAL _Timestamp: one of_ DATE DATE CLOCK DATE CLOCK CLOCK DATE CLOCK INT DATE CLOCK ID TIMESTAMP TIMESTAMP INT TIMESTAMP ID SHIFT: * * : one of "@" "after" "from" "since" "ref" REAL: the usual floating-point format INT: the usual integer format MULTIPLY: one of "-" "." "*" + DIVIDE: * * : one of per PER "/" EXPONENT: ISO-8859-9 or UTF-8 encoded exponent characters RAISE: one of "^" "**" ID: one of "%" "'" "\"" degree sign greek mu character : * : [A-Za-z_] ISO-8859-1 alphabetic characters non-breaking space : one of : [0-9] LOGREF: * : one of "log" "lg" "ln" "lb" : "(" * ":"? * DATE: "-" ("-" )? : [+-]?[0-9]{1,4} : "0"?[1-9]|1[0-2] : "0"?[1-9]|[1-2][0-9]|"30"|"31" CLOCK: ":" (":" )? TIMSTAMP: ( ?)? "T" ( ?)? : [+-]?[0-1]?[0-9]|2[0-3] : [0-5]?[0-9] : (|60) (\.[0-9]*)?  File: udunits2lib.info, Node: Formatting, Next: Operations, Prev: Syntax, Up: Top 7 Formatting a Unit into a String ********************************* Use the `*note ut_format()::' function to obtain the string representation of a binary unit. For example, the following gets the definition of the unit "watt" in ASCII characters using unit-symbols rather than unit-names: ut_unit* watt = ...; char buf[128]; unsigned opts = *note UT_ASCII: ut_encoding. | UT_DEFINITION; int len = *note ut_format: ut_format().(watt, buf, sizeof(buf), opts); if (len == -1) { /* Couldn't get string */ } else if (len == sizeof(buf)) { /* Entire buffer used: no terminating NUL */ } else { /* Have string with terminating NUL */ } -- Function: `int' ut_format `(const ut_unit* UNIT, char* BUF, size_t SIZE, unsigned OPTS)' Formats the unit UNIT (i.e., returns its string representation) into the buffer pointed-to by BUF of size SIZE. The argument OPTS specifies how the formatting is to be done and is a bitwise OR of a *note ut_encoding:: value and zero or more of the following: `UT_NAMES' Use unit names instead of symbols. `UT_DEFINITION' The formatted string should be the definition of UNIT in terms of basic-units instead of stopping any expansion at the highest level possible. On success, this function returns either the number of bytes - excluding the terminating `NUL' - that were written into `buf' or the number of bytes that _would have been written_. The difference is due to the runtime `snprinf()' function that was used. On failure, this function returns `-1' and *note ut_get_status():: will return one of the following: `UT_BAD_ARG' UNIT or BUF is `NULL', or OPTS contains the bit patterns of both `UT_LATIN1' and `UT_UTF8'. `UT_CANT_FORMAT' UNIT can't be formatted in the desired manner (e.g., OPTS contains `UT_ASCII' but UNIT doesn't have an identifier in that character-set or OPTS doesn't contain UT_NAMES and a necessary symbol doesn't exist).  File: udunits2lib.info, Node: Operations, Next: Mapping, Prev: Formatting, Up: Top 8 Unit Operations ***************** You can use unit operations to construct new units, get information about units, or compare units. * Menu: * Unary:: Operations on a single unit * Binary:: Operations on pairs of units  File: udunits2lib.info, Node: Unary, Next: Binary, Up: Operations 8.1 Unary Unit Operations ========================= -- Function: `void' ut_free `(ut_unit* UNIT)' Frees resources associated with UNIT. You should invoke this function on every unit that you no longer need. Use of UNIT upon return from this function results in undefined behavior. -- Function: `ut_unit*' ut_scale `(double FACTOR, const ut_unit* UNIT)' Returns a unit equivalent to another unit scaled by a numeric factor. For example: const ut_unit* meter = ... const ut_unit* kilometer = ut_scale(1000, meter); The returned unit is equivalent to UNIT multiplied by FACTOR. You should pass the returned pointer to `*note ut_free()::' when you no longer need the unit. -- Function: `ut_unit*' ut_offset `(const ut_unit* UNIT, double OFFSET)' Returns a unit equivalent to another unit relative to a particular origin. For example: const ut_unit* kelvin = ... const ut_unit* celsius = ut_offset(kelvin, 273.15); The returned unit is equivalent to UNIT with an origin of OFFSET. You should pass the returned pointer to `*note ut_free()::' when you no longer need the unit. If an error occurs, then this function returns `NULL' and `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' UNIT is `NULL'. `UT_OS' Operating-system error. See `errno' for the reason. -- Function: `ut_unit*' ut_offset_by_time `(const ut_unit* const UNIT, const double ORIGIN)' Returns a timestamp-unit equivalent to the time unit UNIT referenced to the time-origin ORIGIN (as returned by `*note ut_encode_time()::'). For example: const ut_unit* second = ... const ut_unit* secondsSinceTheEpoch = ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0.0)); Leap seconds are not taken into account. You should pass the returned pointer to `*note ut_free()::' when you no longer need the unit. If an error occurs, then this function returns `NULL' and `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' UNIT is `NULL'. `UT_OS' Operating-system error. See `errno' for the reason. `UT_MEANINGLESS' Creation of a timestamp unit based on UNIT is not meaningful. It might not be a time-unit, for example. `UT_NO_SECOND' The associated unit-system doesn't contain a "second" unit. See `*note ut_set_second()::'. *CAUTION:* The timestamp-unit was created to be analogous to, for example, the degree celsius--but for the time dimension. I've come to believe, however, that creating such a unit was a mistake, primarily because users try to use the unit in ways for which it was not designed (such as converting dates in a calendar whose year is exactly 365 days long). Such activities are much better handled by a dedicated calendar package. Please be careful about using timestamp-units. See also the section on *note The Handling of Time: Time. -- Function: `ut_unit*' ut_invert `(const ut_unit* UNIT)' Returns the inverse (i.e., reciprocal) of the unit UNIT. This convenience function is equal to `*note ut_raise(UNIT,-1): ut_raise().'. You should pass the returned pointer to `*note ut_free()::' when you no longer need the unit. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' UNIT is `NULL'. `UT_OS' Operating-system error. See `errno' for the reason. -- Function: `ut_unit*' ut_raise `(const ut_unit* UNIT, int POWER)' Returns the unit equal to unit UNIT raised to the power POWER. You should pass the returned pointer to `ut_free()' when you no longer need the unit. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' UNIT is `NULL'. `UT_OS' Operating-system error. See `errno' for the reason. -- Function: `ut_unit*' ut_root `(const ut_unit* UNIT, int ROOT)' Returns the unit equal to the ROOT root of unit UNIT. You should pass the returned pointer to `ut_free()' when you no longer need the unit. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' UNIT is `NULL'. `UT_MEANINGLESS' It's meaningless to take the given root of the given unit. This could be because the resulting unit would have fractional (i.e., non-integral) dimensionality, or because the unit is, for example, a logarithmic unit. `UT_OS' Operating-system error. See `errno' for the reason. -- Function: `ut_unit*' ut_log `(double BASE, const ut_unit* REFERENCE)' Returns the logarithmic unit corresponding to the logarithmic base BASE and a reference level specified as the unit REFERENCE. For example, the following creates a decibel unit with a one milliwatt reference level: const ut_unit* milliWatt = ...; const ut_unit* bel_1_mW = ut_log(10.0, milliWatt); if (bel_1_mW != NULL) { const ut_unit* decibel_1_mW = *note ut_scale: ut_scale().(0.1, bel_1_mW); *note ut_free: ut_free().(bel_1_mW); /* no longer needed */ if (decibel_1_mW != NULL) { /* Have decibel unit with 1 mW reference */ ... *note ut_free: ut_free().(decibel_1_mW); } /* "decibel_1_mW" allocated */ } You should pass the returned pointer to `ut_free()' when you no longer need the unit. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' REFERENCE is `NULL'. `UT_OS' Operating-system error. See `errno' for the reason. `UT_BAD_ARG' BASE is invalid (e.g., it must be greater than one). -- Function: `const char*' ut_get_name `(const ut_unit* UNIT, ut_encoding ENCODING)' Returns the name to which the unit referenced by UNIT maps in the character-encoding specified by ENCODING. If this function returns `NULL', then `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' NAME is `NULL'. `UT_SUCCESS' UNIT doesn't map to a name in the given character-set. -- Function: `const char*' ut_get_symbol `(const ut_unit* UNIT, ut_encoding ENCODING)' Returns the symbol to which the unit referenced by UNIT maps in the character-encoding specified by ENCODING. If this function returns `NULL', then `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' SYMBOL is `NULL'. `UT_SUCCESS' UNIT doesn't map to a symbol in the given character-set. -- Function: `ut_system*' ut_get_system `(const ut_unit* UNIT)' Returns the unit-system to which the unit referenced by UNIT belongs. If UNIT is `NULL', then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return `UT_BAD_ARG'. -- Function: `int' ut_is_dimensionless `(const ut_unit* UNIT)' Indicates if unit UNIT is dimensionless (like "radian"). This function returns a non-zero value if the unit is dimensionfull; otherwise, `0' is returned and *note ut_get_status():: will return one of the following: `UT_BAD_ARG' UNIT1 is `NULL'. `UT_SUCCESS' The unit is dimensionless. -- Function: `ut_unit*' ut_clone `(const ut_unit* UNIT)' Returns a copy of the unit referenced by UNIT. You should pass the returned pointer to `ut_free()' when you no longer need the unit. If an error occurs, then this function writes an error-message using `*note ut_handle_error_message()::' and returns `NULL'. Also, `*note ut_get_status()::' will return one of the following: `UT_BAD_ARG' UNIT is `NULL'. `UT_OS' Operating-system failure. See `errno'. If you use `*note ut_read_xml()::', then you should not normally need to call this function. -- Function: `*note ut_status::' ut_accept_visitor `(const ut_unit* UNIT, const *note ut_visitor: ut_visitor.* VISITOR, void* ARG)' Accepts the visitor VISITOR to the unit UNIT. The argument ARG is passed to the visitor's functions. This function returns one of the following: `UT_BAD_ARG' VISITOR or UNIT is `NULL'. `UT_VISIT_ERROR' An error occurred in VISITOR while visiting UNIT. `UT_SUCCESS' Success. -- Data type: ut_visitor int foo(int) int bar(int, int) You pass a pointer to a data object of this type if and when you call `*note ut_accept_visitor()::'. It contains the following pointers to functions that implement your unit-visitor: `*note ut_status:: (*visit_basic)(const ut_unit* UNIT, void* ARG);' Visits the basic-unit UNIT. A basic-unit is a base unit like "meter" or a non-dimensional but named unit like "radian". This function returns `*note UT_SUCCESS: ut_status.' on and only on success. `*note ut_status:: (*visit_product)(const ut_unit* UNIT, int COUNT, const ut_unit* const* BASICUNITS, const int* POWERS, void* ARG);' Visits the product-unit UNIT. The product-unit is a product of the COUNT basic-units referenced by BASICUNITS, each raised to their respective, non-zero power in POWERS. This function returns `*note UT_SUCCESS: ut_status.' on and only on success. `*note ut_status:: (*visit_galilean)(const ut_unit* UNIT, double SCALE, const ut_unit* UNDERLYINGUNIT, double ORIGIN, void* arg);' Visits the Galilean-unit UNIT. The Galilean-unit has the underlying unit UNDERLYINGUNIT and either the non-unity scale factor SCALE or the non-zero origin ORIGIN, or both. This function returns `*note UT_SUCCESS: ut_status.' on and only on success. `*note ut_status:: (*visit_timestamp)(const ut_unit* UNIT, const ut_unit* TIMEUNIT, double ORIGIN, void* ARG);' Visits the timestamp-unit UNIT. The timestamp-unit has the underlying unit of time TIMEUNIT and the `*note ut_encode_time()::'-encoded time-origin ORIGIN. This function returns `*note UT_SUCCESS: ut_status.' on and only on success. `*note ut_status:: (*visit_logarithmic)(const ut_unit* UNIT, double BASE, const ut_unit* REFERENCE, void* ARG);' Visits the logarithmic-unit UNIT. The logarithmic-unit has the logarithmic base BASE and the reference-level is specified by the unit REFERENCE. This function returns `*note UT_SUCCESS: ut_status.' on and only on success.  File: udunits2lib.info, Node: Binary, Prev: Unary, Up: Operations 8.2 Binary Unit Operations ========================== Binary unit operations act on two units. *NOTE\:* The functions `*note ut_are_convertible()::' and `*note ut_get_converter()::' are also binary unit operations but are documented elsewhere. -- Function: `ut_unit*' ut_multiply `(const ut_unit* UNIT1, const ut_unit* UNIT2)' Returns the result of multiplying unit UNIT1 by unit UNIT2. You should pass the pointer to *note ut_free():: when you no longer need the unit On failure, this function returns `NULL' and *note ut_get_status():: will return one of the following: `UT_BAD_ARG' UNIT1 or UNIT2 is `NULL'. `UT_NOT_SAME_SYSTEM' UNIT1 and UNIT2 belong to different *note unit-system::s. `UT_OS' Operating-system error. See ERRNO for the reason. -- Function: `ut_unit*' ut_divide `(const ut_unit* NUMER, const ut_unit* DENOM)' Returns the result of dividing unit NUMER by unit DENOM. You should pass the pointer to *note ut_free():: when you no longer need the unit On failure, this function returns `NULL' and *note ut_get_status():: will return one of the following: `UT_BAD_ARG' NUMER or DENOM is `NULL'. `UT_NOT_SAME_SYSTEM' UNIT1 and UNIT2 belong to different *note unit-system::s. `UT_OS' Operating-system error. See `errno' for the reason. -- Function: `int' ut_compare `(const ut_unit* UNIT1, const ut_unit* UNIT2)' Compares two units. Returns a value less than, equal to, or greater than zero as UNIT1 is considered less than, equal to, or greater than UNIT2, respectively. Units from different *note unit-system::s never compare equal. The value zero is also returned if both unit pointers are `NULL'. -- Function: `int' ut_same_system `(const ut_unit* UNIT1, const ut_unit* UNIT2)' Indicates if two units belong to the same unit-system. This function returns a non-zero value if the two units belong to the same *note unit-system::; otherwise, `0' is returned and *note ut_get_status():: will return one of the following: `UT_BAD_ARG' UNIT1 or UNIT2 is `NULL'. `UT_SUCCESS' The units belong to different *note unit-system::s.  File: udunits2lib.info, Node: Mapping, Next: Time, Prev: Operations, Up: Top 9 Mapping Between Identifiers and Units *************************************** Within a unit-system, you can map an identifier to a unit and vice versa. If an identifier maps to a unit, then the unit can be retrieved from the unit-system via the identifier. Similarly, if a unit maps to an identifier, then the unit can be printed using the identifier. There a two kinds of identifiers: names and symbols. * Menu: * Names:: Mapping between units and names. * Symbols:: Mapping between units and symbols.  File: udunits2lib.info, Node: Names, Next: Symbols, Up: Mapping 9.1 Names ========= You can map a name to a unit and vice versa. If you use `*note ut_read_xml()::', then you shouldn't normally need to do this. -- Function: `*note ut_status::' ut_map_name_to_unit `(const char* NAME, const ut_encoding ENCODING, const ut_unit* UNIT)' Maps the name referenced by NAME, in character-set ENCODING, to the unit referenced by UNIT in the unit-system that contains UNIT. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' NAME or UNIT is `NULL'. `UT_OS' Operating-system failure. See `errno'. `UT_EXISTS' NAME already maps to a different unit. -- Function: `*note ut_status::' ut_unmap_name_to_unit `(ut_system* SYSTEM, const char* NAME, const ut_encoding ENCODING)' Removes any mapping from name NAME, in character-set ENCODING, to a unit in unit-system SYSTEM. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' SYSTEM or NAME is `NULL'. -- Function: `*note ut_status::' ut_map_unit_to_name `(const ut_unit* UNIT, const char* NAME, ut_encoding ENCODING)' Maps the unit UNIT to the name NAME, which is in character-set ENCODING, in the unit-system that contains the unit. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' UNIT or NAME is `NULL', or NAME is not in the character-set ENCODING. `UT_OS' Operating-system failure. See `errno'. `UT_EXISTS' UNIT already maps to a different name. -- Function: `*note ut_status::' ut_unmap_unit_to_name `(const ut_unit* UNIT, ut_encoding ENCODING)' Removes any mapping from unit UNIT to a name in character-set ENCODING from the unit-system that contains the unit. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' UNIT is `NULL'.  File: udunits2lib.info, Node: Symbols, Prev: Names, Up: Mapping 9.2 Symbols =========== You can map a symbol to a unit and vice versa. If you use `*note ut_read_xml()::', then you shouldn't normally need to do this. -- Function: `*note ut_status::' ut_map_symbol_to_unit `(const char* SYMBOL, const ut_encoding ENCODING, const ut_unit* UNIT)' Maps the symbol referenced by SYMBOL, in character-set ENCODING, to the unit referenced by UNIT in the unit-system that contains UNIT. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' SYMBOL or UNIT is `NULL'. `UT_OS' Operating-system failure. See `errno'. `UT_EXISTS' SYMBOL already maps to a different unit. -- Function: `*note ut_status::' ut_unmap_symbol_to_unit `(ut_system* SYSTEM, const char* SYMBOL, const ut_encoding ENCODING)' Removes any mapping from symbol SYMBOL, in character-set ENCODING, to a unit in unit-system SYSTEM. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' SYSTEM or SYMBOL is `NULL'. -- Function: `*note ut_status::' ut_map_unit_to_symbol `(const ut_unit* UNIT, const char* SYMBOL, ut_encoding ENCODING)' Maps the unit UNIT to the symbol SYMBOL, which is in character-set ENCODING, in the unit-system that contains the unit. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' UNIT or SYMBOL is `NULL'. `UT_BAD_ARG' Symbol SYMBOL is not in the character-set ENCODING. `UT_OS' Operating-system failure. See `errno'. `UT_EXISTS' UNIT already maps to a different symbol. -- Function: `*note ut_status::' ut_unmap_unit_to_symbol `(const ut_unit* UNIT, ut_encoding ENCODING)' Removes any mapping from unit UNIT to a symbol in character-set ENCODING from the unit-system that contains the unit. This function returns one of the following: `UT_SUCCESS' Success. `UT_BAD_ARG' UNIT is `NULL'.  File: udunits2lib.info, Node: Time, Next: Errors, Prev: Mapping, Up: Top 10 The Handling of Time *********************** You should use a true calendar package rather than the UDUNITS-2 package to handle time. Having said that, many people use the time-handling capabilities of the UDUNITS-2 package because it supports "units" like "`seconds since 1970-01-01'". You should be aware, however, that the hybrid Gregorian/Julian calendar used by the UDUNITS-2 package _cannot be changed_. Dates on or after 1582-10-15 are assumed to be Gregorian dates; dates before that are assumed to be Julian dates. In particular, the year 1 BCE is immediately followed by the year 1 CE. In general, the UDUNITS-2 package handles time by encoding it as double-precision value, which can then be acted upon arithmetically. -- Function: `double' ut_encode_time `(int YEAR, int MONTH, int DAY, int HOUR, int MINUTE, double SECOND)' Encodes a time as a double-precision value. This convenience function is equivalent to *note ut_encode_date: ut_encode_date().(YEAR,MONTH,DAY) + *note ut_encode_clock: ut_encode_clock().(HOUR,MINUTE,SECOND) -- Function: `double' ut_encode_date `(int YEAR, int MONTH, int DAY)' Encodes a date as a double-precision value. You probably won't use this function. Dates on or after 1582-10-15 are assumed to be Gregorian dates; dates before that are assumed to be Julian dates. In particular, the year 1 BCE is immediately followed by the year 1 CE. -- Function: `double' ut_encode_clock `(int HOUR, int MINUTE, double SECOND)' Encodes a clock-time as a double-precision value. You probably won't use this function. -- Function: `void' ut_decode_time `(double TIME, int* YEAR, int* MONTH, int* DAY, int* HOUR, int* MINUTE, double* SECOND, double* RESOLUTION)' Decodes a time from a double-precision value into its individual components. The variable referenced by RESOLUTION will be set to the resolution (i.e., uncertainty) of the time in seconds.  File: udunits2lib.info, Node: Errors, Next: Database, Prev: Time, Up: Top 11 Error Handling ***************** Error-handling in the units module has two aspects: the status of the last operation performed by the module and the handling of error-messages: * Menu: * Status:: The status of the last operation. * Messages:: The handling of error-messages.  File: udunits2lib.info, Node: Status, Next: Messages, Up: Errors 11.1 Status of Last Operation ============================= UDUNITS-2 functions set their status by calling `*note ut_set_status()::'. You can use the function `*note ut_get_status()::' to retrieve that status. -- Function: `*note ut_status::' ut_get_status `(void)' Returns the value specified in the last call to `*note ut_set_status()::' -- Function: `void' ut_set_status `(*note ut_status:: STATUS)' Set the status of the units module to STATUS. -- Data type: ut_status This enumeration has the following values: `UT_SUCCESS' Success `UT_BAD_ARG' An argument violates the the function's contract (e.g., it's `NULL'). `UT_EXISTS' Unit, prefix, or identifier already exists `UT_NO_UNIT' No such unit exists `UT_OS' Operating-system error. See `errno' for the reason. `UT_NOT_SAME_SYSTEM' The units belong to different unit-systems `UT_MEANINGLESS' The operation on the unit or units is meaningless `UT_NO_SECOND' The unit-system doesn't have a unit named "second" `UT_VISIT_ERROR' An error occurred while visiting a unit `UT_CANT_FORMAT' A unit can't be formatted in the desired manner `UT_SYNTAX' String unit representation contains syntax error `UT_UNKNOWN' String unit representation contains unknown word `UT_OPEN_ARG' Can't open argument-specified unit database `UT_OPEN_ENV' Can't open environment-specified unit database `UT_OPEN_DEFAULT' Can't open installed, default, unit database `UT_PARSE' Error parsing unit database  File: udunits2lib.info, Node: Messages, Prev: Status, Up: Errors 11.2 Error-Messages =================== -- Function: `int' ut_handle_error_message `(const char* FMT, ...)' Handles the error-message corresponding to the format-string FMT and any subsequent arguments referenced by it. The interpretation of the formatting-string is identical to that of the UNIX function `printf()'. On success, this function returns the number of bytes in the error-message; otherwise, this function returns `-1'. Use the function `*note ut_set_error_message_handler()::' to change how error-messages are handled. -- Function: `*note ut_error_message_handler::' ut_set_error_message_handler `(*note ut_error_message_handler:: HANDLER)' Sets the function that handles error-messages and returns the previous error-message handler. The initial error-message handler is `*note ut_write_to_stderr()::'. -- Function: `int' ut_write_to_stderr `(const char* FMT, va_list ARGS)' Writes the variadic error-message corresponding to formatting-string FMT and arguments ARGS to the standard-error stream and appends a newline. The interpretation of the formatting-string is identical to that of the UNIX function `printf()'. On success, this function returns the number of bytes in the error-message; otherwise, this function returns `-1'. -- Function: `int' ut_ignore `(const char* FMT, va_list ARGS)' Does nothing. In particular, it ignores the variadic error-message corresponding to formatting-string FMT and arguments ARGS. Pass this function to `*note ut_set_error_message_handler()::' when you don't want the unit module to print any error-messages. -- Data type: ut_error_message_handler This is the type of an error-message handler. It's definition is typedef int (*ut_error_message_handler)(const char* fmt, va_list args);  File: udunits2lib.info, Node: Database, Next: Types, Prev: Errors, Up: Top 12 The Units Database ********************* The database of units that comes with the UDUNITS-2 package is an XML-formatted file that is based on the SI system of units. It contains the names and symbols of most of the units that you will ever encounter. The pathname of the installed file is `_datadir_/udunits2.xml', where _datadir_ is the installation-directory for read-only, architecture-independent data (e.g., `/usr/local/share'). This pathname is the default that `*note ut_read_xml()::' uses. Naturally, because the database is a regular file, it can be edited to add new units or remove existing ones. Be very careful about doing this, however, because you might lose the benefit of exchanging unit-based information with others who haven't modified their database.  File: udunits2lib.info, Node: Types, Next: Complete Index, Prev: Database, Up: Top 13 Data Types ************* The data types `*note ut_visitor::', `*note ut_status::', and `*note ut_error_message_handler::' are documented elsewhere. -- Data type: ut_encoding This enumeration has the following values: `UT_ASCII' US ASCII (http://en.wikipedia.org/wiki/Ascii) character-set. `UT_ISO_8859_1' The ISO-8859-1 (http://en.wikipedia.org/wiki/Iso-8859-1) character-set. `UT_LATIN1' Synonym for `UT_ISO_8859_1'. `UT_UTF8' The UTF-8 (http://en.wikipedia.org/wiki/Utf-8) encoding of the Unicode character-set.  File: udunits2lib.info, Node: Complete Index, Prev: Types, Up: Top Index ***** [index] * Menu: * adding prefixes to a unit-system: Prefixes. (line 6) * adding units to a unit-system: Adding. (line 6) * base unit: Unit-Systems. (line 7) * binary unit operations: Binary. (line 6) * converting values between units: Value Conversion. (line 6) * cv_convert_double: Value Conversion. (line 72) * cv_convert_doubles: Value Conversion. (line 83) * cv_convert_float: Value Conversion. (line 67) * cv_convert_floats: Value Conversion. (line 77) * cv_free: Value Conversion. (line 88) * data types: Types. (line 6) * database, unit, obtaining predefined: Obtaining. (line 6) * database, units: Database. (line 6) * error handling: Errors. (line 6) * error-messages: Messages. (line 6) * examples, unit specification: Examples. (line 6) * formatting a unit into a string: Formatting. (line 6) * getting a unit by its name: Extracting. (line 16) * getting a unit by its symbol: Extracting. (line 30) * grammar, unit: Grammar. (line 6) * mapping identifiers: Mapping. (line 6) * mapping units: Mapping. (line 6) * messages, error: Messages. (line 6) * module status: Status. (line 6) * names: Names. (line 6) * operations, unit: Operations. (line 6) * parsing a string into a unit: Parsing. (line 6) * prefixes, adding to a unit-system: Prefixes. (line 6) * status of last operation: Status. (line 6) * string, formatting a unit into a: Formatting. (line 6) * string, parsing into a unit: Parsing. (line 6) * symbols: Symbols. (line 6) * synopsis: Synopsis. (line 6) * syntax, unit: Syntax. (line 6) * system of units: Unit-Systems. (line 6) * time, handling of: Time. (line 6) * types, data: Types. (line 6) * unary unit operations: Unary. (line 6) * unit conversion: Value Conversion. (line 6) * unit database, obtaining predefined: Obtaining. (line 6) * unit grammar: Grammar. (line 6) * unit operations: Operations. (line 6) * unit specification examples: Examples. (line 6) * unit syntax: Syntax. (line 6) * unit, adding to a unit-system: Adding. (line 6) * unit, base: Unit-Systems. (line 7) * unit, formatting into a string: Formatting. (line 6) * unit, getting by name: Extracting. (line 16) * unit, getting by symbol: Extracting. (line 30) * unit-system: Unit-Systems. (line 6) * unit-system, adding a unit to: Adding. (line 6) * unit-system, adding prefixes to a: Prefixes. (line 6) * unit-system, obtaining predefined: Obtaining. (line 6) * units database: Database. (line 6) * units, mapping to identifiers: Mapping. (line 6) * units, obtaining predefined: Obtaining. (line 6) * ut_accept_visitor: Unary. (line 224) * ut_add_name_prefix: Prefixes. (line 16) * ut_add_symbol_prefix: Prefixes. (line 35) * ut_are_convertible: Value Conversion. (line 25) * ut_clone: Unary. (line 206) * ut_compare: Binary. (line 46) * ut_decode_time: Time. (line 39) * ut_divide: Binary. (line 30) * ut_encode_clock: Time. (line 33) * ut_encode_date: Time. (line 25) * ut_encode_time: Time. (line 20) * ut_encoding: Types. (line 10) * ut_error_message_handler: Messages. (line 38) * ut_format: Formatting. (line 28) * ut_free: Unary. (line 7) * ut_free_system: Misc. (line 7) * ut_get_converter: Value Conversion. (line 44) * ut_get_dimensionless_unit_one: Extracting. (line 45) * ut_get_name: Unary. (line 162) * ut_get_path_xml: Obtaining. (line 38) * ut_get_status: Status. (line 11) * ut_get_symbol: Unary. (line 175) * ut_get_system: Unary. (line 187) * ut_get_unit_by_name: Extracting. (line 18) * ut_get_unit_by_symbol: Extracting. (line 32) * ut_handle_error_message: Messages. (line 7) * ut_ignore: Messages. (line 32) * ut_invert: Unary. (line 77) * ut_is_dimensionless: Unary. (line 194) * ut_log: Unary. (line 127) * ut_map_name_to_unit: Names. (line 11) * ut_map_symbol_to_unit: Symbols. (line 11) * ut_map_unit_to_name: Names. (line 41) * ut_map_unit_to_symbol: Symbols. (line 41) * ut_multiply: Binary. (line 14) * ut_new_base_unit: Adding. (line 23) * ut_new_dimensionless_unit: Adding. (line 40) * ut_new_system: Obtaining. (line 90) * ut_offset: Unary. (line 22) * ut_offset_by_time: Unary. (line 40) * ut_parse: Parsing. (line 25) * ut_raise: Unary. (line 92) * ut_read_xml: Obtaining. (line 58) * ut_read_xml(), discussion of: Obtaining. (line 6) * ut_root: Unary. (line 106) * ut_same_system: Binary. (line 54) * ut_scale: Unary. (line 12) * ut_set_error_message_handler: Messages. (line 19) * ut_set_second: Misc. (line 14) * ut_set_status: Status. (line 15) * ut_status: Status. (line 18) * ut_trim: Parsing. (line 45) * ut_unmap_name_to_unit: Names. (line 29) * ut_unmap_symbol_to_unit: Symbols. (line 29) * ut_unmap_unit_to_name: Names. (line 60) * ut_unmap_unit_to_symbol: Symbols. (line 62) * ut_visitor: Unary. (line 238) * ut_write_to_stderr: Messages. (line 24)  Tag Table: Node: Top2152 Node: Synopsis5310 Node: Why14038 Ref: unit-system15439 Node: Unit-Systems15439 Node: Obtaining16464 Ref: ut_get_path_xml()17943 Ref: ut_read_xml()18811 Ref: ut_new_system()20147 Node: Extracting20701 Ref: ut_get_unit_by_name()21356 Ref: ut_get_unit_by_symbol()21854 Ref: ut_get_dimensionless_unit_one()22357 Node: Adding22849 Ref: ut_new_base_unit()23781 Ref: ut_new_dimensionless_unit()24489 Node: Prefixes25224 Ref: ut_add_name_prefix()25782 Ref: ut_add_symbol_prefix()26385 Node: Misc26995 Ref: ut_free_system()27159 Ref: ut_set_second()27426 Node: Value Conversion28051 Ref: ut_are_convertible()28851 Ref: ut_get_converter()29614 Ref: cv_convert_float()30544 Ref: cv_convert_double()30731 Ref: cv_convert_floats()30923 Ref: cv_convert_doubles()31256 Ref: cv_free()31595 Node: Parsing31855 Ref: ut_parse()32518 Ref: ut_trim()33277 Node: Syntax33529 Node: Examples34119 Node: Grammar35496 Node: Formatting38618 Ref: ut_format()39441 Node: Operations40867 Node: Unary41193 Ref: ut_free()41318 Ref: ut_scale()41566 Ref: ut_offset()42007 Ref: ut_offset_by_time()42719 Ref: ut_invert()44419 Ref: ut_raise()45057 Ref: ut_root()45618 Ref: ut_log()46447 Ref: ut_get_name()47896 Ref: ut_get_symbol()48347 Ref: ut_get_system()48806 Ref: ut_is_dimensionless()49151 Ref: ut_clone()49552 Ref: ut_accept_visitor()50178 Ref: ut_visitor50668 Node: Binary52894 Ref: ut_multiply()53216 Ref: ut_divide53798 Ref: ut_compare()54377 Ref: ut_same_system()54782 Node: Mapping55270 Node: Names55879 Ref: ut_map_name_to_unit()56098 Ref: ut_unmap_name_to_unit()56641 Ref: ut_map_unit_to_name()57023 Ref: ut_unmap_unit_to_name()57602 Node: Symbols57972 Ref: ut_map_symbol_to_unit()58197 Ref: ut_unmap_symbol_to_unit()58753 Ref: ut_map_unit_to_symbol()59145 Ref: ut_unmap_unit_to_symbol()59760 Node: Time60134 Ref: ut_encode_time()60957 Ref: ut_encode_date()61304 Ref: ut_encode_clock()61671 Ref: ut_decode_time()61860 Node: Errors62231 Node: Status62603 Ref: ut_get_status()62888 Ref: ut_set_status()63030 Ref: ut_status63146 Node: Messages64386 Ref: ut_handle_error_message()64498 Ref: ut_set_error_message_handler()65031 Ref: ut_write_to_stderr()65344 Ref: ut_ignore()65807 Ref: ut_error_message_handler66148 Node: Database66342 Node: Types67209 Ref: ut_encoding67452 Node: Complete Index67905  End Tag Table udunits-2.2.0/lib/scanner.l0000644000175000017500000001277712260406756016742 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * lex(1) specification for tokens for the Unidata units package, UDUNITS2. */ %option noyywrap %{ #include #include #include #include #include #include #include #include %} space [ \t\r\f\v] int [0-9]+ int_period {int}\. period_int \.{int} int_period_int {int}\.{int} mantissa {int_period}|{period_int}|{int_period_int} real_exp [eE][+-]?[0-9]+ real [+-]?({int}{real_exp}|{mantissa}{real_exp}?) year [+-]?[0-9]{1,4} month 0?[1-9]|1[0-2] day 0?[1-9]|[1-2][0-9]|30|31 hour [+-]?[0-1]?[0-9]|2[0-3] minute [0-5]?[0-9] second ({minute}|60)(\.[0-9]*)? middot \xc2\xb7 utf8_exp_digit \xc2(\xb9|\xb2|\xb3)|\xe2\x81(\xb0|[\xb4-\xb9]) utf8_exp_sign \xe2\x81\xba|\xe2\x81\xbb utf8_exponent {utf8_exp_sign}?{utf8_exp_digit}+ nbsp \xc2\xa0 shy \xc2\xad degree \xc2\xb0 mu \xc2\xb5 blk1 \xc3([\x80-\x96]) blk2 \xc3([\x98-\xB6]) blk3 \xc3([\xB8-\xBF]) latin1 {nbsp}|{shy}|{degree}|{mu}|{blk1}|{blk2}|{blk3} utf8_cont [\x80-\xbf] utf8_2bytes [\xc8-\xdf]{utf8_cont} utf8_3bytes [\xe0-\xef]{utf8_cont}{utf8_cont} letter [_a-zA-Z]|{latin1}|{utf8_2bytes}|{utf8_3bytes} alphanum {letter}|[0-9] id %|'|\"|{letter}({alphanum}*{letter})? broken_date {year}-{month}(-{day})? packed_date {year}({month}{day}?)? broken_clock {hour}:{minute}(:{second})? packed_clock {hour}({minute}{second}?)? broken_timestamp {broken_date}({space}+{broken_clock})? packed_timestamp {packed_date}T{packed_clock}? logref \({space}*[Rr][Ee](:{space})?{space}* after [Aa][Ff][Tt][Ee][Rr] from [Ff][Rr][Oo][Mm] since [Ss][Ii][Nn][Cc][Ee] ref [Rr][Ee][Ff] per [Pp][Ee][Rr] %Start id_seen %% if (_restartScanner) { BEGIN(INITIAL); _restartScanner = 0; } {space}*(@|{after}|{from}|{since}|{ref}){space}* { BEGIN(INITIAL); return SHIFT; } {space}*({per}|"/"){space}* { BEGIN(INITIAL); return DIVIDE; } "-"|"."|"*"|{middot}|{space}+ { BEGIN(INITIAL); return MULTIPLY; } ("^"|"**")[+-]?{int} { int status; if (sscanf(yytext, "%*[*^]%ld", &yylval.ival) != 1) { ut_handle_error_message("Invalid integer\n", stderr); status = ERR; } else { status = EXPONENT; } return status; } {utf8_exponent} { int status = EXPONENT; int exponent = 0; int sign = 1; char* cp = yytext; if (strncmp(cp, "\xe2\x81\xba", 3) == 0) { cp += 3; } else if (strncmp(cp, "\xe2\x81\xbb", 3) == 0) { sign = -1; cp += 3; } while (cp < yytext + yyleng) { int j; static struct { const char* string; const int len; } utf8_exponents[] = { {"\xe2\x81\xb0", 3}, /* 0 */ {"\xc2\xb9", 2}, /* 1 */ {"\xc2\xb2", 2}, /* 2 */ {"\xc2\xb3", 2}, /* 3 */ {"\xe2\x81\xb4", 3}, /* 4 */ {"\xe2\x81\xb5", 3}, /* 5 */ {"\xe2\x81\xb6", 3}, /* 6 */ {"\xe2\x81\xb7", 3}, /* 7 */ {"\xe2\x81\xb8", 3}, /* 8 */ {"\xe2\x81\xb9", 3}, /* 9 */ }; exponent *= 10; for (j = 0; j < 10; j++) { int len = utf8_exponents[j].len; if (strncmp(cp, utf8_exponents[j].string, len) == 0) { exponent += j; cp += len; break; } } if (j >= 10) { status = ERR; break; } } if (status == EXPONENT) yylval.ival = sign * exponent; BEGIN(INITIAL); return status; } {broken_date}(T|{space}*) { int year; int month; int day = 1; (void) sscanf((char*)yytext, "%d-%d-%d", &year, &month, &day); yylval.rval = ut_encode_date(year, month, day); BEGIN(INITIAL); return DATE; } {broken_clock}{space}* { int hour; int minute; double second = 0.0; (void) sscanf((char*)yytext, "%d:%d:%lf", &hour, &minute, &second); yylval.rval = ut_encode_clock(hour, minute, second); BEGIN(INITIAL); return CLOCK; } {packed_timestamp}{space}* { int year; int month = 1; int day = 1; int hour = 0; int minute = 0; double second = 0.0; (void) sscanf((char*)yytext, "%4d%2d%2dT%2d%2d%lf", &year, &month, &day, &hour, &minute, &second); yylval.rval = ut_encode_time(year, month, day, hour, minute, second); BEGIN(INITIAL); return TIMESTAMP; } {real} { int status; errno = 0; yylval.rval = atof((char*)yytext); if (errno == 0) { status = REAL; } else { ut_handle_error_message("Invalid real\n", stderr); status = ERR; } return status; } [+-]?{int} { int status; errno = 0; yylval.ival = atol((char*)yytext); if (errno == 0) { status = INT; } else { ut_handle_error_message("Invalid integer\n", stderr); status = ERR; } return status; } (log|lg){space}*{logref} { yylval.rval = 10; return LOGREF; } ln{space}*{logref} { yylval.rval = M_E; return LOGREF; } lb{space}*{logref} { yylval.rval = 2; return LOGREF; } {id} { yylval.id = strdup((char*)yytext); BEGIN(id_seen); return ID; } . { BEGIN(INITIAL); return yytext[0]; } %% udunits-2.2.0/lib/systemMap.c0000644000175000017500000000774112260406756017255 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Module for system-to-pointer maps. * * This module is thread-compatible but not thread-safe. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include "systemMap.h" #include "udunits2.h" struct SystemMap { void* tree; }; typedef struct { const ut_system* system; void* ptr; } Entry; /* * Compares two entries according to their unit-system pointers. * * Arguments: * entry1 Pointer to the first entry. * entry2 Pointer to the second entry. * Returns: * -1 The first entry's key is less than the second's. * 0 The first entry's key is equal to the second's. * 1 The first entry's key is greater than the second's. */ static int compareEntries( const void* entry1, const void* entry2) { const ut_system* const system1 = ((Entry*)entry1)->system; const ut_system* const system2 = ((Entry*)entry2)->system; return system1 < system2 ? -1 : system1 == system2 ? 0 : 1; } /* * Returns a new instance of a system-map. * * Arguments: * compare Function for comparing keys. * Returns: * NULL Operating-system failure. See "errno". * else Pointer to the new map. */ SystemMap* smNew() { SystemMap* map = (SystemMap*)malloc(sizeof(SystemMap)); if (map != NULL) map->tree = NULL; return map; } /* * Returns the address of the pointer to which a unit-system maps. * * Arguments: * map Pointer to the system-map. * system Pointer to the unit-system. * Returns: * NULL There is no pointer associated with "system". * else Address of the pointer to which "system" maps. */ void** smFind( const SystemMap* const map, const void* const system) { Entry targetEntry; Entry** treeEntry; targetEntry.system = system; treeEntry = tfind(&targetEntry, &map->tree, compareEntries); return treeEntry == NULL ? NULL : &(*treeEntry)->ptr; } /* * Returns the address of the pointer to which a unit-system maps -- creating a * new entry if necessary. If a new entry is created, then the pointer whose * address is returned will be NULL. * * Arguments: * map Pointer to the system-map. * system Pointer to the unit-system. * Returns: * NULL Operating system failure. See "errno". * else Address of the pointer to which "system" maps. */ void** smSearch( SystemMap* const map, const void* system) { void** addr = NULL; /* failure */ Entry* targetEntry = (Entry*)malloc(sizeof(Entry)); if (targetEntry != NULL) { Entry** treeEntry; targetEntry->system = system; targetEntry->ptr = NULL; treeEntry = tsearch(targetEntry, &map->tree, compareEntries); if (treeEntry == NULL) { free(targetEntry); } else { addr = &(*treeEntry)->ptr; if (targetEntry != *treeEntry) free(targetEntry); } } return addr; } /* * Removes the system-map entry that corresponds to a unit-system. * * Arguments: * map Pointer to the map. * system Pointer to the unit-system. */ void smRemove( SystemMap* const map, const void* const system) { Entry targetEntry; Entry** treeEntry; targetEntry.system = system; treeEntry = tfind(&targetEntry, &map->tree, compareEntries); if (treeEntry != NULL) { Entry* entry = *treeEntry; (void)tdelete(entry, &map->tree, compareEntries); free(entry); } } /* * Frees a system-map. This function should be called when a system-map is no * longer needed. * * Arguments: * map Pointer to the system-map to be freed or NULL. Use of "map" * upon return results in undefined behavior. */ void smFree( SystemMap* const map) { if (map != NULL) { while (map->tree != NULL) { Entry* entry = *(Entry**)map->tree; tdelete(entry, &map->tree, compareEntries); free(entry); } free(map); } } udunits-2.2.0/lib/udunits2-prefixes.xml0000644000175000017500000000440612260406756021244 0ustar amckinstryamckinstry 1e24 yotta Y 1e21 zetta Z 1e18 exa E 1e15 peta P 1e12 tera T 1e9 giga G 1e6 mega M 1e3 kilo k 100 hecto h 10 deka da .1 deci d .01 centi c 1e-3 milli m 1e-6 micro µ μ u 1e-9 nano n 1e-12 pico p 1e-15 femto f 1e-18 atto a 1e-21 zepto z 1e-24 yocto y udunits-2.2.0/lib/idToUnitMap.c0000644000175000017500000003047612260406756017471 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Identifier-to-unit map. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include "udunits2.h" #include "unitAndId.h" #include "systemMap.h" typedef struct { int (*compare)(const void*, const void*); void* tree; } IdToUnitMap; static SystemMap* systemToNameToUnit; static SystemMap* systemToSymbolToUnit; static int sensitiveCompare( const void* const node1, const void* const node2) { return strcmp(((const UnitAndId*)node1)->id, ((const UnitAndId*)node2)->id); } static int insensitiveCompare( const void* const node1, const void* const node2) { return strcasecmp(((const UnitAndId*)node1)->id, ((const UnitAndId*)node2)->id); } static IdToUnitMap* itumNew( int (*compare)(const void*, const void*)) { IdToUnitMap* map = (IdToUnitMap*)malloc(sizeof(IdToUnitMap)); if (map != NULL) { map->tree = NULL; map->compare = compare; } return map; } /* * Frees an identifier-to-unit map. All entries are freed. * * Arguments: * map Pointer to the identifier-to-unit map. * Returns: */ static void itumFree( IdToUnitMap* map) { if (map != NULL) { while (map->tree != NULL) { UnitAndId* uai = *(UnitAndId**)map->tree; (void)tdelete(uai, &map->tree, map->compare); uaiFree(uai); } free(map); } /* valid arguments */ } /* * Adds an entry to an identifier-to-unit map. * * Arguments: * map The database. * id The identifier. May be freed upon return. * unit The unit. May be freed upon return. * Returns: * UT_OS Operating-system error. See "errno". * UT_EXISTS "id" already maps to a different unit. * UT_SUCCESS Success. */ static ut_status itumAdd( IdToUnitMap* map, const char* const id, const ut_unit* const unit) { ut_status status; UnitAndId* targetEntry; assert(map != NULL); assert(id != NULL); assert(unit != NULL); targetEntry = uaiNew(unit, id); if (targetEntry != NULL) { UnitAndId** treeEntry = tsearch(targetEntry, &map->tree, map->compare); if (treeEntry == NULL) { uaiFree(targetEntry); status = UT_OS; } else { if (ut_compare((*treeEntry)->unit, unit) == 0) { status = UT_SUCCESS; } else { status = UT_EXISTS; ut_set_status(status); ut_handle_error_message( "\"%s\" already maps to existing but different unit", id); } if (targetEntry != *treeEntry) uaiFree(targetEntry); } /* found entry */ } /* "targetEntry" allocated */ return status; } /* * Removes an entry to an identifier-to-unit map. * * Arguments: * map The database. * id The identifier. May be freed upon return. * Returns: * UT_SUCCESS Success. */ static ut_status itumRemove( IdToUnitMap* map, const char* const id) { UnitAndId targetEntry; UnitAndId** treeEntry; assert(map != NULL); assert(id != NULL); targetEntry.id = (char*)id; treeEntry = tfind(&targetEntry, &map->tree, map->compare); if (treeEntry != NULL) { UnitAndId* uai = *treeEntry; (void)tdelete(uai, &map->tree, map->compare); uaiFree(uai); } return UT_SUCCESS; } /* * Finds the entry in an identifier-to-unit map that corresponds to an * identifer. * * Arguments: * map The identifier-to-unit map. * id The identifier to be used as the key in the search. * Returns: * NULL Failure. "map" doesn't contain an entry that corresponds * to "id". * else Pointer to the entry corresponding to "id". */ static const UnitAndId* itumFind( IdToUnitMap* map, const char* const id) { UnitAndId* entry = NULL; /* failure */ UnitAndId targetEntry; UnitAndId** treeEntry; assert(map != NULL); assert(id != NULL); targetEntry.id = (char*)id; treeEntry = tfind(&targetEntry, &map->tree, map->compare); if (treeEntry != NULL) entry = *treeEntry; return entry; } /* * Adds to a particular unit-system a mapping from an identifier to a unit. * * Arguments: * systemMap Address of the pointer to the system-map. * id Pointer to the identifier. May be freed upon return. * unit Pointer to the unit. May be freed upon return. * compare Pointer to comparison function for unit-identifiers. * Returns: * UT_BAD_ARG "id" is NULL or "unit" is NULL. * UT_OS Operating-sytem failure. See "errno". * UT_SUCCESS Success. */ static ut_status mapIdToUnit( SystemMap** const systemMap, const char* const id, const ut_unit* const unit, int (*compare)(const void*, const void*)) { ut_status status = UT_SUCCESS; if (id == NULL) { status = UT_BAD_ARG; } else if (unit == NULL) { status = UT_BAD_ARG; } else { ut_system* system = ut_get_system(unit); if (*systemMap == NULL) { *systemMap = smNew(); if (*systemMap == NULL) status = UT_OS; } if (*systemMap != NULL) { IdToUnitMap** const idToUnit = (IdToUnitMap**)smSearch(*systemMap, system); if (idToUnit == NULL) { status = UT_OS; } else { if (*idToUnit == NULL) { *idToUnit = itumNew(compare); if (*idToUnit == NULL) status = UT_OS; } if (*idToUnit != NULL) status = itumAdd(*idToUnit, id, unit); } /* have system-map entry */ } /* have system-map */ } /* valid arguments */ return status; } /* * Removes the mapping from an identifier to a unit. * * Arguments: * systemMap Address of the pointer to the system-map. * id Pointer to the identifier. May be freed upon return. * system Pointer to the unit-system associated with the mapping. * Returns: * UT_BAD_ARG "id" is NULL, "system" is NULL, or "compare" is NULL. * UT_SUCCESS Success. */ static ut_status unmapId( SystemMap* const systemMap, const char* const id, ut_system* system) { ut_status status; if (systemMap == NULL || id == NULL || system == NULL) { status = UT_BAD_ARG; } else { IdToUnitMap** const idToUnit = (IdToUnitMap**)smFind(systemMap, system); status = (idToUnit == NULL || *idToUnit == NULL) ? UT_SUCCESS : itumRemove(*idToUnit, id); } /* valid arguments */ return status; } /* * Adds a mapping from a name to a unit. * * Arguments: * name Pointer to the name to be mapped to "unit". May be * freed upon return. * encoding The character encoding of "name". * unit Pointer to the unit to be mapped-to by "name". May be * freed upon return. * Returns: * UT_BAD_ARG "name" or "unit" is NULL. * UT_OS Operating-system error. See "errno". * UT_EXISTS "name" already maps to a different unit. * UT_SUCCESS Success. */ ut_status ut_map_name_to_unit( const char* const name, const ut_encoding encoding, const ut_unit* const unit) { ut_set_status( mapIdToUnit(&systemToNameToUnit, name, unit, insensitiveCompare)); return ut_get_status(); } /* * Removes a mapping from a name to a unit. After this function, * ut_get_unit_by_name(system,name) will no longer return a unit. * * Arguments: * system The unit-system to which the unit belongs. * name The name of the unit. * encoding The character encoding of "name". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" or "name" is NULL. */ ut_status ut_unmap_name_to_unit( ut_system* system, const char* const name, const ut_encoding encoding) { ut_set_status(unmapId(systemToNameToUnit, name, system)); return ut_get_status(); } /* * Adds a mapping from a symbol to a unit. * * Arguments: * symbol Pointer to the symbol to be mapped to "unit". May be * freed upon return. * encoding The character encoding of "symbol". * unit Pointer to the unit to be mapped-to by "symbol". May * be freed upon return. * Returns: * UT_BAD_ARG "symbol" or "unit" is NULL. * UT_OS Operating-system error. See "errno". * UT_EXISTS "symbol" already maps to a different unit. * UT_SUCCESS Success. */ ut_status ut_map_symbol_to_unit( const char* const symbol, const ut_encoding encoding, const ut_unit* const unit) { ut_set_status( mapIdToUnit(&systemToSymbolToUnit, symbol, unit, sensitiveCompare)); return ut_get_status(); } /* * Removes a mapping from a symbol to a unit. After this function, * ut_get_unit_by_symbol(system,symbol) will no longer return a unit. * * Arguments: * system The unit-system to which the unit belongs. * symbol The symbol of the unit. * encoding The character encoding of "symbol". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" or "symbol" is NULL. */ ut_status ut_unmap_symbol_to_unit( ut_system* system, const char* const symbol, const ut_encoding encoding) { ut_set_status(unmapId(systemToSymbolToUnit, symbol, system)); return ut_get_status(); } /* * Returns the unit to which an identifier maps in a particular unit-system. * * Arguments: * systemMap NULL or pointer to the system-map. If NULL, then * NULL will be returned. * system Pointer to the unit-system. * id Pointer to the identifier. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "system" is NULL or "id" is NULL. * else Pointer to the unit in "system" with the identifier "id". * Should be passed to ut_free() when no longer needed. */ static ut_unit* getUnitById( const SystemMap* const systemMap, const ut_system* const system, const char* const id) { ut_unit* unit = NULL; /* failure */ if (system == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("getUnitById(): NULL unit-system argument"); } else if (id == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("getUnitById(): NULL identifier argument"); } else if (systemMap != NULL) { IdToUnitMap** const idToUnit = (IdToUnitMap**)smFind(systemMap, system); if (idToUnit != NULL) { const UnitAndId* uai = itumFind(*idToUnit, id); if (uai != NULL) unit = ut_clone(uai->unit); } } /* valid arguments */ return unit; } /* * Returns the unit with a given name from a unit-system. Name comparisons * are case-insensitive. * * Arguments: * system Pointer to the unit-system. * name Pointer to the name of the unit to be returned. * Returns: * NULL Failure. "ut_get_status()" will be * UT_SUCCESS "name" doesn't map to a unit of * "system". * UT_BAD_ARG "system" or "name" is NULL. * else Pointer to the unit of the unit-system with the given name. * The pointer should be passed to ut_free() when the unit is * no longer needed. */ ut_unit* ut_get_unit_by_name( const ut_system* const system, const char* const name) { ut_set_status(UT_SUCCESS); return getUnitById(systemToNameToUnit, system, name); } /* * Returns the unit with a given symbol from a unit-system. Symbol * comparisons are case-sensitive. * * Arguments: * system Pointer to the unit-system. * symbol Pointer to the symbol associated with the unit to be * returned. * Returns: * NULL Failure. "ut_get_status()" will be * UT_SUCCESS "symbol" doesn't map to a unit of * "system". * UT_BAD_ARG "system" or "symbol" is NULL. * else Pointer to the unit in the unit-system with the given symbol. * The pointer should be passed to ut_free() when the unit is no * longer needed. */ ut_unit* ut_get_unit_by_symbol( const ut_system* const system, const char* const symbol) { ut_set_status(UT_SUCCESS); return getUnitById(systemToSymbolToUnit, system, symbol); } /* * Frees resources associated with a unit-system. * * Arguments: * system Pointer to the unit-system to have its associated * resources freed. */ void itumFreeSystem( ut_system* system) { if (system != NULL) { SystemMap* systemMaps[2]; int i; systemMaps[0] = systemToNameToUnit; systemMaps[1] = systemToSymbolToUnit; for (i = 0; i < 2; i++) { if (systemMaps[i] != NULL) { IdToUnitMap** const idToUnit = (IdToUnitMap**)smFind(systemMaps[i], system); if (idToUnit != NULL) itumFree(*idToUnit); smRemove(systemMaps[i], system); } } } /* valid arguments */ } udunits-2.2.0/lib/unitcore.c0000644000175000017500000026257012260406756017126 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Unit creation and manipulation routines for the udunits(3) library. * * The following data-structures exist in this module: * BasicUnit Like an ISO "base unit" but also for dimensionless * units (e.g., "radian"). * ProductUnit A unit that, when it is created, contains all the * BasicUnit-s that exist at the time, each raised * to an integral power (that can be zero). * GalileanUnit A unit whose value is related to another unit by a * Galilean transformation (y = ax + b). Examples include * "yard" and "degrees Fahrenheit". * LogUnit A unit that is related to another unit by a logarithmic * transformation (y = a*log(x)). The "Bel" is an example. * TimestampUnit A wrong-headed unit that shouldn't exist but does for * backward compatibility. It was intended to provide * similar functionality as the GalileanUnit, but for time * units (e.g., "seconds since the epoch"). Unfortunately, * people try to use it for more than it is capable (e.g., * days since some time on an imaginary world with only 360 * days per year). * ut_unit A data-structure that encapsulates ProductUnit, * GalileanUnit, LogUnit, and TimestampUnit. * * This module is thread-compatible but not thread-safe: multi-thread access to * this module must be externally synchronized. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "udunits2.h" /* this module's API */ #include "converter.h" typedef enum { PRODUCT_EQUAL = 0, /* The units are equal -- ignoring dimensionless * basic-units */ PRODUCT_INVERSE, /* The units are reciprocals of each other */ PRODUCT_UNCONVERTIBLE, /* The units have incompatible dimensionality */ PRODUCT_UNKNOWN /* The relationship is unknown */ } ProductRelationship; typedef struct BasicUnit BasicUnit; typedef struct ProductUnit ProductUnit; struct ut_system { ut_unit* second; ut_unit* one; /* the dimensionless-unit one */ BasicUnit** basicUnits; int basicCount; }; typedef struct { ProductUnit* (*getProduct)(const ut_unit*); ut_unit* (*clone)(const ut_unit*); void (*free)(ut_unit*); /* * The following comparison function is called if and only if the two units * belong to the same unit system. */ int (*compare)(const ut_unit*, const ut_unit*); ut_unit* (*multiply)(const ut_unit*, const ut_unit*); ut_unit* (*raise)(const ut_unit*, const int power); ut_unit* (*root)(const ut_unit*, const int root); int (*initConverterToProduct)(ut_unit*); int (*initConverterFromProduct)(ut_unit*); ut_status (*acceptVisitor)(const ut_unit*, const ut_visitor*, void*); } UnitOps; typedef enum { BASIC, PRODUCT, GALILEAN, LOG, TIMESTAMP } UnitType; #undef ABS #define ABS(a) ((a) < 0 ? -(a) : (a)) #undef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #undef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define GET_PRODUCT(unit) \ ((unit)->common.ops->getProduct(unit)) #define CLONE(unit) ((unit)->common.ops->clone(unit)) #define MULTIPLY(unit1, unit2) \ ((unit1)->common.ops->multiply(unit1, unit2)) #define RAISE(unit, power) \ ((unit)->common.ops->raise(unit, power)) #define ROOT(unit, root) \ ((unit)->common.ops->root(unit, root)) #define FREE(unit) ((unit)->common.ops->free(unit)) #define COMPARE(unit1, unit2) \ ((unit1)->common.ops->compare(unit1, unit2)) #define ENSURE_CONVERTER_TO_PRODUCT(unit) \ ((unit)->common.toProduct != NULL || \ (unit)->common.ops->initConverterToProduct(unit) == 0) #define ENSURE_CONVERTER_FROM_PRODUCT(unit) \ ((unit)->common.fromProduct != NULL || \ (unit)->common.ops->initConverterFromProduct(unit) == 0) #define ACCEPT_VISITOR(unit, visitor, arg) \ ((unit)->common.ops->acceptVisitor(unit, visitor, arg)) typedef struct { ut_system* system; const UnitOps* ops; UnitType type; cv_converter* toProduct; cv_converter* fromProduct; } Common; struct BasicUnit { Common common; ProductUnit* product; /* equivalent product-unit */ int index; /* system->basicUnits index */ int isDimensionless; }; struct ProductUnit { Common common; short* indexes; short* powers; int count; }; typedef struct { Common common; ut_unit* unit; double scale; double offset; } GalileanUnit; typedef struct { Common common; ut_unit* unit; double origin; } TimestampUnit; typedef struct { Common common; ut_unit* reference; double base; } LogUnit; union ut_unit { Common common; BasicUnit basic; ProductUnit product; GalileanUnit galilean; TimestampUnit timestamp; LogUnit log; }; #define IS_BASIC(unit) ((unit)->common.type == BASIC) #define IS_PRODUCT(unit) ((unit)->common.type == PRODUCT) #define IS_GALILEAN(unit) ((unit)->common.type == GALILEAN) #define IS_LOG(unit) ((unit)->common.type == LOG) #define IS_TIMESTAMP(unit) ((unit)->common.type == TIMESTAMP) /* * The following function are declared here because they are used in the * basic-unit section before they are defined in the product-unit section. */ static ProductUnit* productNew( ut_system* const system, const short* const indexes, const short* const powers, const int count); static void productFree( ut_unit* const unit); static ut_unit* productMultiply( const ut_unit* const unit1, const ut_unit* const unit2); static ut_unit* productRaise( const ut_unit* const unit, const int power); static ut_unit* productRoot( const ut_unit* const unit, const int root); /* * The following two functions convert between Julian day number and * Gregorian/Julian dates (Julian dates are used prior to October 15, * 1582; Gregorian dates are used after that). Julian day number 0 is * midday, January 1, 4713 BCE. The Gregorian calendar was adopted * midday, October 15, 1582. * * Author: Robert Iles, March 1994 * * C Porter: Steve Emmerson, October 1995 * * Original: http://www.nag.co.uk:70/nagware/Examples/calendar.f90 * * There is no warranty on this code. */ /* * Convert a Julian day number to a Gregorian/Julian date. */ void julianDayToGregorianDate(julday, year, month, day) long julday; /* Julian day number to convert */ int *year; /* Gregorian year (out) */ int *month; /* Gregorian month (1-12) (out) */ int *day; /* Gregorian day (1-31) (out) */ { long ja, jb, jd; int jc; int je, iday, imonth, iyear; double xc; if (julday < 2299161) ja = julday; else { int ia = (int)(((julday - 1867216) - 0.25) / 36524.25); ja = julday + 1 + ia - (int)(0.25 * ia); } jb = ja + 1524; xc = ((jb - 2439870) - 122.1) / 365.25; jc = (int)(6680.0 + xc); jd = 365 * jc + (int)(0.25 * jc); je = (int)((jb - jd) / 30.6001); iday = (int)(jb - jd - (int)(30.6001 * je)); imonth = je - 1; if (imonth > 12) imonth -= 12; iyear = jc - 4715; if (imonth > 2) iyear -= 1; if (iyear <= 0) iyear -= 1; *year = iyear; *month = imonth; *day = iday; } /* * Convert a Gregorian/Julian date to a Julian day number. * * The Gregorian calendar was adopted midday, October 15, 1582. */ long gregorianDateToJulianDay(year, month, day) int year; /* Gregorian year */ int month; /* Gregorian month (1-12) */ int day; /* Gregorian day (1-31) */ { int32_t igreg = 15 + 31 * (10 + (12 * 1582)); int32_t iy; /* signed, origin 0 year */ int32_t ja; /* Julian century */ int32_t jm; /* Julian month */ int32_t jy; /* Julian year */ long julday; /* returned Julian day number */ /* * Because there is no 0 BC or 0 AD, assume the user wants the start of * the common era if they specify year 0. */ if (year == 0) year = 1; iy = year; if (year < 0) iy++; if (month > 2) { jy = iy; jm = month + 1; } else { jy = iy - 1; jm = month + 13; } /* * Note: SLIGHTLY STRANGE CONSTRUCTIONS REQUIRED TO AVOID PROBLEMS WITH * OPTIMISATION OR GENERAL ERRORS UNDER VMS! */ julday = day + (int)(30.6001 * jm); if (jy >= 0) { julday += 365 * jy; julday += 0.25 * jy; } else { double xi = 365.25 * jy; if ((int)xi != xi) xi -= 1; julday += (int)xi; } julday += 1720995; if (day + (31* (month + (12 * iy))) >= igreg) { ja = jy/100; julday -= ja; julday += 2; julday += ja/4; } return julday; } /* * Returns the Julian day number that is the origin of all things temporal in * this module. * * Returns: * The Julian day number that is the origin for time in this module. */ static long getJuldayOrigin() { static long juldayOrigin; if (juldayOrigin == 0) juldayOrigin = gregorianDateToJulianDay(2001, 1, 1); return juldayOrigin; } /* * Encodes a time as a double-precision value. * * Arguments: * hours The number of hours (0 = midnight). * minutes The number of minutes. * seconds The number of seconds. * Returns: * The clock-time encoded as a scalar value. */ double ut_encode_clock( int hours, int minutes, double seconds) { return (hours*60 + minutes)*60 + seconds; } /* * Decompose a value into a set of values accounting for uncertainty. */ static void decompose(value, uncer, nbasis, basis, count) double value; double uncer; /* >= 0 */ int nbasis; double *basis; /* all values > 0 */ double *count; { int i; for (i = 0; i < nbasis; i++) { double r = fmod(value, basis[i]); /* remainder */ /* Adjust remainder to minimum magnitude. */ if (ABS(2*r) > basis[i]) r += r > 0 ? -basis[i] : basis[i]; if (ABS(r) <= uncer) { /* The value equals a basis multiple within the uncertainty. */ double half = value < 0 ? -basis[i]/2 : basis[i]/2; modf((value+half)/basis[i], count+i); break; } value = basis[i] * modf(value/basis[i], count+i); } if (i >= nbasis) { count[--i] += value; } else { for (i++; i < nbasis; i++) count[i] = 0; } } /* * Encodes a date as a double-precision value. * * Arguments: * year The year. * month The month. * day The day (1 = the first of the month). * Returns: * The date encoded as a scalar value. */ double ut_encode_date( int year, int month, int day) { return 86400.0 * (gregorianDateToJulianDay(year, month, day) - getJuldayOrigin()); } /* * Encodes a time as a double-precision value. The convenience function is * equivalent to "ut_encode_date(year,month,day) + * ut_encode_clock(hour,minute,second)" * * Arguments: * year The year. * month The month. * day The day. * hour The hour. * minute The minute. * second The second. * Returns: * The time encoded as a scalar value. */ double ut_encode_time( const int year, const int month, const int day, const int hour, const int minute, const double second) { return ut_encode_date(year, month, day) + ut_encode_clock(hour, minute, second); } /* * Decodes a time from a double-precision value. * * Arguments: * value The value to be decoded. * year Pointer to the variable to be set to the year. * month Pointer to the variable to be set to the month. * day Pointer to the variable to be set to the day. * hour Pointer to the variable to be set to the hour. * minute Pointer to the variable to be set to the minute. * second Pointer to the variable to be set to the second. * resolution Pointer to the variable to be set to the resolution * of the decoded time in seconds. */ void ut_decode_time( double value, int *year, int *month, int *day, int *hour, int *minute, double *second, double *resolution) { int days; int hours; int minutes; double seconds; double uncer; /* uncertainty of input value */ typedef union { double vec[7]; struct { double days; double hours12; double hours; double minutes10; double minutes; double seconds10; double seconds; } ind; } Basis; Basis counts; static const Basis basis = {86400, 43200, 3600, 600, 60, 10, 1}; uncer = ldexp(value < 0 ? -value : value, -DBL_MANT_DIG); days = (int)floor(value/basis.ind.days); value -= days * basis.ind.days; /* make positive excess */ decompose(value, uncer, (int)(sizeof(basis.vec)/sizeof(basis.vec[0])), basis.vec, counts.vec); days += counts.ind.days; hours = (int)counts.ind.hours12 * 12 + (int)counts.ind.hours; minutes = (int)counts.ind.minutes10 * 10 + (int)counts.ind.minutes; seconds = (int)counts.ind.seconds10 * 10 + counts.ind.seconds; if (seconds >= 60) { seconds -= 60; ++minutes; } if (minutes >= 60) { minutes -= 60; ++hours; } if (hours >= 24) { hours -= 24; ++days; } *second = seconds; *minute = minutes; *hour = hours; *resolution = uncer; julianDayToGregorianDate(getJuldayOrigin() + days, year, month, day); } /****************************************************************************** * Parameters common to all types of units: ******************************************************************************/ /* * Arguments: * common Pointer to unit common-area. * ops Pointer to unit-specific function-structure. * system Pointer to unit-system. * type The type of unit. * Returns: * 0 Success. */ static int commonInit( Common* const common, const UnitOps* const ops, const ut_system* const system, const UnitType type) { assert(system != NULL); assert(common != NULL); assert(ops != NULL); common->system = (ut_system*)system; common->ops = ops; common->type = type; common->toProduct = NULL; common->fromProduct = NULL; return 0; } /****************************************************************************** * Basic-Unit: ******************************************************************************/ static UnitOps basicOps; /* * Returns a new instance of a basic-unit. * * Arguments: * system The unit-system to be associated with the new instance. * isDimensionless Whether or not the unit is dimensionless (e.g., * "radian"). * index The index of the basic-unit in "system". * Returns: * NULL Failure. "ut_get_status()" will be: * UT_OS Operating-system error. See "errno". * else Pointer to newly-allocated basic-unit. */ static BasicUnit* basicNew( ut_system* const system, const int isDimensionless, const int index) { BasicUnit* basicUnit = NULL; /* failure */ int error = 1; short power = 1; short shortIndex = (short)index; ProductUnit* product; assert(system != NULL); product = productNew(system, &shortIndex, &power, 1); if (product == NULL) { ut_set_status(UT_OS); ut_handle_error_message( "basicNew(): Couldn't create new product-unit"); } else { basicUnit = malloc(sizeof(BasicUnit)); if (basicUnit == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "basicNew(): Couldn't allocate %lu-byte basic-unit", sizeof(BasicUnit)); } else if (commonInit(&basicUnit->common, &basicOps, system, BASIC) == 0) { basicUnit->index = index; basicUnit->isDimensionless = isDimensionless; basicUnit->product = product; error = 0; } /* "basicUnit" allocated */ if (error) productFree((ut_unit*)product); } /* "product" allocated */ return basicUnit; } static ProductUnit* basicGetProduct( const ut_unit* const unit) { assert(IS_BASIC(unit)); return unit->basic.product; } static ut_unit* basicClone( const ut_unit* const unit) { assert(IS_BASIC(unit)); return (ut_unit*)basicNew(unit->common.system, unit->basic.isDimensionless, unit->basic.index); } static void basicFree( ut_unit* const unit) { if (unit != NULL) { assert(IS_BASIC(unit)); productFree((ut_unit*)unit->basic.product); unit->basic.product = NULL; free(unit); } } static int basicCompare( const ut_unit* const unit1, const ut_unit* const unit2) { int cmp; assert(unit1 != NULL); assert(IS_BASIC(unit1)); assert(unit2 != NULL); if (IS_PRODUCT(unit2)) { cmp = -COMPARE(unit2, unit1); } else if (!IS_BASIC(unit2)) { int diff = unit1->common.type - unit2->common.type; cmp = diff < 0 ? -1 : diff == 0 ? 0 : 1; } else { int index1 = unit1->basic.index; int index2 = unit2->basic.index; cmp = index1 < index2 ? -1 : index1 == index2 ? 0 : 1; } return cmp; } /* * Multiplies a basic-unit by another unit. * * Arguments: * unit1 The basic-unit. * unit2 The other unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* basicMultiply( const ut_unit* const unit1, const ut_unit* const unit2) { assert(unit1 != NULL); assert(unit2 != NULL); assert(IS_BASIC(unit1)); return productMultiply((const ut_unit*)unit1->basic.product, unit2); } /* * Returns the result of raising a basic-unit to a power. * * Arguments: * unit The basic-unit. * power The power. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given unit is * meaningless. * else The resulting unit. */ static ut_unit* basicRaise( const ut_unit* const unit, const int power) { assert(unit != NULL); assert(IS_BASIC(unit)); assert(power != 0); assert(power != 1); return productRaise((ut_unit*)unit->basic.product, power); } /* * Returns the result of taking a root of a basic-unit. * * Arguments: * unit The basic-unit. * root The root to take. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given unit is * meaningless. * else The resulting unit. */ static ut_unit* basicRoot( const ut_unit* const unit, const int root) { assert(unit != NULL); assert(IS_BASIC(unit)); assert(root > 1); return productRoot((ut_unit*)unit->basic.product, root); } /* * Initializes the converter of numeric from the given product-unit to the * underlying product-unit (i.e., to itself). * * Arguments: * unit The product unit. * Returns: * 0 Success. */ static int basicInitConverterToProduct( ut_unit* const unit) { assert(unit != NULL); assert(IS_BASIC(unit)); if (unit->common.toProduct == NULL) unit->common.toProduct = cv_get_trivial(); return 0; } /* * Initializes the converter of numeric to the given product-unit from the * underlying product-unit (i.e., to itself). * * Arguments: * unit The product unit. * Returns: * 0 Success. */ static int basicInitConverterFromProduct( ut_unit* const unit) { assert(unit != NULL); assert(IS_BASIC(unit)); if (unit->common.fromProduct == NULL) unit->common.fromProduct = cv_get_trivial(); return 0; } static ut_status basicAcceptVisitor( const ut_unit* const unit, const ut_visitor* const visitor, void* const arg) { assert(unit != NULL); assert(IS_BASIC(unit)); assert(visitor != NULL); return visitor->visit_basic(unit, arg); } static UnitOps basicOps = { basicGetProduct, basicClone, basicFree, basicCompare, basicMultiply, basicRaise, basicRoot, basicInitConverterToProduct, basicInitConverterFromProduct, basicAcceptVisitor }; /****************************************************************************** * Product Unit: ******************************************************************************/ static UnitOps productOps; /* * Arguments: * system The unit-system for the new unit. * indexes Pointer to array of indexes of basic-units. May be freed upon * return. * powers Pointer to array of powers. Client may free upon return. * count The number of elements in "indexes" and "powers". May be zero. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_OS Operating-system error. See "errno". * else The newly-allocated, product-unit. */ static ProductUnit* productNew( ut_system* const system, const short* const indexes, const short* const powers, const int count) { ProductUnit* productUnit; assert(system != NULL); assert(count >= 0); assert(count == 0 || (indexes != NULL && powers != NULL)); productUnit = malloc(sizeof(ProductUnit)); if (productUnit == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "productNew(): Couldn't allocate %d-byte product-unit", sizeof(ProductUnit)); } else { int error = 1; if (commonInit(&productUnit->common, &productOps, system, PRODUCT) == 0) { if (count == 0) { productUnit->count = count; productUnit->indexes = NULL; productUnit->powers = NULL; error = 0; } else { size_t nbytes = sizeof(short)*count; short* newIndexes = malloc(nbytes*2); if (count > 0 && newIndexes == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("productNew(): " "Couldn't allocate %d-element index array", count); } else { short* newPowers = newIndexes + count; productUnit->count = count; productUnit->indexes = memcpy(newIndexes, indexes, nbytes); productUnit->powers = memcpy(newPowers, powers, nbytes); error = 0; } } /* "count > 0" */ } /* "productUnit->common" initialized */ if (error) { free(productUnit); productUnit = NULL; } } /* "productUnit" allocated */ return productUnit; } static ProductUnit* productGetProduct( const ut_unit* const unit) { assert(unit != NULL); assert(IS_PRODUCT(unit)); return (ProductUnit*)&unit->product; } static ut_unit* productClone( const ut_unit* const unit) { ut_unit* clone; assert(unit != NULL); assert(IS_PRODUCT(unit)); if (unit == unit->common.system->one) { clone = unit->common.system->one; } else { clone = (ut_unit*)productNew(unit->common.system, unit->product.indexes, unit->product.powers, unit->product.count); } return clone; } static int productCompare( const ut_unit* const unit1, const ut_unit* const unit2) { int cmp; assert(unit1 != NULL); assert(IS_PRODUCT(unit1)); assert(unit2 != NULL); if (IS_BASIC(unit2)) { cmp = productCompare(unit1, (ut_unit*)unit2->basic.product); } else if (!IS_PRODUCT(unit2)) { int diff = unit1->common.type - unit2->common.type; cmp = diff < 0 ? -1 : diff == 0 ? 0 : 1; } else { const ProductUnit* const product1 = &unit1->product; const ProductUnit* const product2 = &unit2->product; cmp = product1->count - product2->count; if (cmp == 0) { const short* const indexes1 = product1->indexes; const short* const indexes2 = product2->indexes; const short* const powers1 = product1->powers; const short* const powers2 = product2->powers; int i; for (i = 0; i < product1->count; ++i) { cmp = indexes1[i] - indexes2[i]; if (cmp == 0) cmp = powers1[i] - powers2[i]; if (cmp != 0) break; } } } return cmp; } static void productReallyFree( ut_unit* const unit) { if (unit != NULL) { assert(IS_PRODUCT(unit)); free(unit->product.indexes); unit->product.indexes = NULL; cv_free(unit->common.toProduct); unit->common.toProduct = NULL; cv_free(unit->common.fromProduct); unit->common.fromProduct = NULL; free(unit); } } static void productFree( ut_unit* const unit) { if (unit != unit->common.system->one) productReallyFree(unit); } /* * Multiplies a product-unit by another unit. * * Arguments: * unit1 The product unit. * unit2 The other unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * UT_OS Operating-system failure. See "errno". * else The resulting unit. */ static ut_unit* productMultiply( const ut_unit* const unit1, const ut_unit* const unit2) { ut_unit* result = NULL; /* failure */ assert(unit1 != NULL); assert(unit2 != NULL); assert(IS_PRODUCT(unit1)); if (!IS_PRODUCT(unit2)) { result = MULTIPLY(unit2, unit1); } else { const ProductUnit* const product1 = &unit1->product; const ProductUnit* const product2 = &unit2->product; short* indexes1 = product1->indexes; short* indexes2 = product2->indexes; short* powers1 = product1->powers; short* powers2 = product2->powers; int count1 = product1->count; int count2 = product2->count; int sumCount = count1 + count2; if (sumCount == 0) { result = unit1->common.system->one; } else { static short* indexes = NULL; indexes = realloc(indexes, sizeof(short)*sumCount); if (indexes == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("productMultiply(): " "Couldn't allocate %d-element index array", sumCount); } else { static short* powers = NULL; powers = realloc(powers, sizeof(short)*sumCount); if (powers == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("productMultiply(): " "Couldn't allocate %d-element power array", sumCount); } else { int count = 0; int i1 = 0; int i2 = 0; while (i1 < count1 || i2 < count2) { if (i1 >= count1) { indexes[count] = indexes2[i2]; powers[count++] = powers2[i2++]; } else if (i2 >= count2) { indexes[count] = indexes1[i1]; powers[count++] = powers1[i1++]; } else if (indexes1[i1] > indexes2[i2]) { indexes[count] = indexes2[i2]; powers[count++] = powers2[i2++]; } else if (indexes1[i1] < indexes2[i2]) { indexes[count] = indexes1[i1]; powers[count++] = powers1[i1++]; } else { if (powers1[i1] != -powers2[i2]) { indexes[count] = indexes1[i1]; powers[count++] = powers1[i1] + powers2[i2]; } i1++; i2++; } } result = (ut_unit*)productNew(unit1->common.system, indexes, powers, count); } /* "powers" re-allocated */ } /* "indexes" re-allocated */ } /* "sumCount > 0" */ } /* "unit2" is a product-unit */ return result; } /* * Returns the result of raising a product unit to a power. * * Arguments: * unit The product unit. * power The power. Must be greater than -256 and less than 256. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given unit is * meaningless. * else The resulting unit. */ static ut_unit* productRaise( const ut_unit* const unit, const int power) { ut_unit* result = NULL; /* failure */ const ProductUnit* product; int count; short* newPowers; assert(unit != NULL); assert(IS_PRODUCT(unit)); assert(power >= -255 && power <= 255); assert(power != 0); assert(power != 1); product = &unit->product; count = product->count; if (count == 0) { result = unit->common.system->one; } else { newPowers = malloc(sizeof(short)*count); if (newPowers == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("productRaise(): " "Couldn't allocate %d-element powers-buffer", count); } else { const short* const oldPowers = product->powers; int i; for (i = 0; i < count; i++) newPowers[i] = (short)(oldPowers[i] * power); result = (ut_unit*)productNew(unit->common.system, product->indexes, newPowers, count); free(newPowers); } /* "newPowers" allocated */ } /* "count > 0" */ return result; } /* * Returns the result of taking a root of a unit. * * Arguments: * unit The product unit. * root The root. Must be greater than 1 and less than 256. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given unit is * meaningless. * else The resulting unit. */ static ut_unit* productRoot( const ut_unit* const unit, const int root) { ut_unit* result = NULL; /* failure */ const ProductUnit* product; int count; short* newPowers; assert(unit != NULL); assert(IS_PRODUCT(unit)); assert(root > 1 && root <= 255); product = &unit->product; count = product->count; if (count == 0) { result = unit->common.system->one; } else { newPowers = malloc(sizeof(short)*count); if (newPowers == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("productRoot(): " "Couldn't allocate %d-element powers-buffer", count); } else { const short* const oldPowers = product->powers; int i; for (i = 0; i < count; i++) { if ((oldPowers[i] % root) != 0) { break; } newPowers[i] = (short)(oldPowers[i] / root); } if (i < count) { char buf[80]; if (ut_format(unit, buf, sizeof(buf), UT_ASCII) == -1) { ut_set_status(UT_MEANINGLESS); ut_handle_error_message("productRoot(): " "Can't take root of unit"); } else { ut_set_status(UT_MEANINGLESS); buf[sizeof(buf)-1] = 0; ut_handle_error_message("productRoot(): " "It's meaningless to take the %d%s root of \"%s\"", root, root == 2 ? "nd" : root == 3 ? "rd" : "th", buf); } } else { result = (ut_unit*)productNew(unit->common.system, product->indexes, newPowers, count); } free(newPowers); } /* "newPowers" allocated */ } /* "count > 0" */ return result; } /* * Initializes a converter of numeric values between the given product-unit and * the underlying product-unit (i.e., to itself). * * Arguments: * converter Pointer to pointer to the converter to be initialized. * Returns: * 0 Success. */ static int productInitConverter( cv_converter** const converter) { assert(converter != NULL); *converter = cv_get_trivial(); return 0; } /* * Initializes the converter of numeric values from the given product-unit to * the underlying product-unit (i.e., to itself). * * Arguments: * unit The product unit. * Returns: * 0 Success. */ static int productInitConverterToProduct( ut_unit* const unit) { assert(unit != NULL); assert(IS_PRODUCT(unit)); return productInitConverter(&unit->common.toProduct); } /* * Initializes the converter of numeric values to the given product-unit from * the underlying product-unit (i.e., to itself). * * Arguments: * unit The product unit. * Returns: * 0 Success. */ static int productInitConverterFromProduct( ut_unit* const unit) { assert(unit != NULL); assert(IS_PRODUCT(unit)); return productInitConverter(&unit->common.fromProduct); } /* * Returns the relationship between two product-units. In determining the * relationship, dimensionless basic-units are ignored. * * Arguments: * unit1 The first product unit. * unit2 The second product unit. * Returns: * PRODUCT_EQUAL The units are equal -- ignoring dimensionless * basic-units. * PRODUCT_INVERSE The units are reciprocals of each other. * PRODUCT_UNCONVERTIBLE The dimensionalities of the units are * unconvertible. */ static ProductRelationship productRelationship( const ProductUnit* const unit1, const ProductUnit* const unit2) { ProductRelationship relationship = PRODUCT_UNKNOWN; assert(unit1 != NULL); assert(unit2 != NULL); { const short* const indexes1 = unit1->indexes; const short* const indexes2 = unit2->indexes; const short* const powers1 = unit1->powers; const short* const powers2 = unit2->powers; const int count1 = unit1->count; const int count2 = unit2->count; const ut_system* const system = unit1->common.system; int i1 = 0; int i2 = 0; while (i1 < count1 || i2 < count2) { int iBasic = -1; if (i1 >= count1) { iBasic = indexes2[i2++]; } else if (i2 >= count2) { iBasic = indexes1[i1++]; } else if (indexes1[i1] > indexes2[i2]) { iBasic = indexes2[i2++]; } else if (indexes1[i1] < indexes2[i2]) { iBasic = indexes1[i1++]; } if (iBasic != -1) { if (!system->basicUnits[iBasic]->isDimensionless) { relationship = PRODUCT_UNCONVERTIBLE; break; } } else { iBasic = indexes1[i1]; if (!system->basicUnits[iBasic]->isDimensionless) { if (powers1[i1] == powers2[i2]) { if (relationship == PRODUCT_INVERSE) { relationship = PRODUCT_UNCONVERTIBLE; break; } relationship = PRODUCT_EQUAL; } else if (powers1[i1] == -powers2[i2]) { if (relationship == PRODUCT_EQUAL) { relationship = PRODUCT_UNCONVERTIBLE; break; } relationship = PRODUCT_INVERSE; } else { relationship = PRODUCT_UNCONVERTIBLE; break; } } i1++; i2++; } } } if (relationship == PRODUCT_UNKNOWN) { /* * Both units are dimensionless. */ relationship = PRODUCT_EQUAL; } return relationship; } static ut_status productAcceptVisitor( const ut_unit* const unit, const ut_visitor* const visitor, void* const arg) { int count = unit->product.count; BasicUnit** basicUnits = malloc(sizeof(BasicUnit)*count); assert(unit != NULL); assert(IS_PRODUCT(unit)); assert(visitor != NULL); if (count != 0 && basicUnits == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("productAcceptVisitor(): " "Couldn't allocate %d-element basic-unit array", count); } else { int* powers = malloc(sizeof(int)*count); if (count != 0 && powers == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("productAcceptVisitor(): " "Couldn't allocate %d-element power array", count); } else { const ProductUnit* prodUnit = &unit->product; int i; for (i = 0; i < count; ++i) { basicUnits[i] = unit->common.system->basicUnits[prodUnit->indexes[i]]; powers[i] = prodUnit->powers[i]; } ut_set_status(visitor->visit_product(unit, count, (const ut_unit**)basicUnits, powers, arg)); free(powers); } /* "powers" allocated */ free(basicUnits); } /* "basicUnits" allocated */ return ut_get_status(); } static UnitOps productOps = { productGetProduct, productClone, productFree, productCompare, productMultiply, productRaise, productRoot, productInitConverterToProduct, productInitConverterFromProduct, productAcceptVisitor }; /* * Indicates if a product-unit is dimensionless or not. * * Arguments: * unit The product-unit in question. * Returns: * 0 "unit" is dimensionfull. * else "unit" is dimensionless. */ static int productIsDimensionless( const ProductUnit* const unit) { int isDimensionless = 1; int count; const short* indexes; ut_system* system; int i; assert(unit != NULL); assert(IS_PRODUCT(unit)); count = unit->count; indexes = unit->indexes; system = unit->common.system; for (i = 0; i < count; ++i) { if (!system->basicUnits[indexes[i]]->isDimensionless) { isDimensionless = 0; break; } } return isDimensionless; } /****************************************************************************** * Galilean Unit: ******************************************************************************/ static UnitOps galileanOps; /* * Returns a new unit instance. The returned instance is not necessarily a * Galilean unit. * * Arguments: * scale The scale-factor for the new unit. * unit The underlying unit. May be freed upon return. * offset The offset for the new unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_OS Operating-system error. See "errno". * else The newly-allocated, galilean-unit. */ static ut_unit* galileanNew( double scale, const ut_unit* unit, double offset) { ut_unit* newUnit = NULL; /* failure */ assert(scale != 0); assert(unit != NULL); if (IS_GALILEAN(unit)) { scale *= unit->galilean.scale; offset += (unit->galilean.scale * unit->galilean.offset) / scale; unit = unit->galilean.unit; } if (scale == 1 && offset == 0) { newUnit = CLONE(unit); } else { GalileanUnit* galileanUnit = malloc(sizeof(GalileanUnit)); if (galileanUnit == NULL) { ut_set_status(UT_OS); ut_handle_error_message("galileanNew(): " "Couldn't allocate %lu-byte Galilean unit", sizeof(GalileanUnit)); } else { int error = 1; if (commonInit(&galileanUnit->common, &galileanOps, unit->common.system, GALILEAN) == 0) { galileanUnit->scale = scale; galileanUnit->offset = offset; galileanUnit->unit = CLONE(unit); error = 0; } if (error) { free(galileanUnit); galileanUnit = NULL; } } /* "galileanUnit" allocated */ newUnit = (ut_unit*)galileanUnit; } /* Galilean unit necessary */ return newUnit; } static ProductUnit* galileanGetProduct( const ut_unit* const unit) { assert(unit != NULL); assert(IS_GALILEAN(unit)); return GET_PRODUCT(unit->galilean.unit); } static ut_unit* galileanClone( const ut_unit* const unit) { const GalileanUnit* galileanUnit; assert(unit != NULL); assert(IS_GALILEAN(unit)); galileanUnit = &unit->galilean; return galileanNew(galileanUnit->scale, galileanUnit->unit, galileanUnit->offset); } static int galileanCompare( const ut_unit* const unit1, const ut_unit* const unit2) { int cmp; assert(unit1 != NULL); assert(IS_GALILEAN(unit1)); if (!IS_GALILEAN(unit2)) { int diff = unit1->common.type - unit2->common.type; cmp = diff < 0 ? -1 : diff == 0 ? 0 : 1; } else { const GalileanUnit* const galilean1 = &unit1->galilean; const GalileanUnit* const galilean2 = &unit2->galilean; cmp = galilean1->offset < galilean2->offset ? -1 : galilean1->offset == galilean2->offset ? 0 : 1; if (cmp == 0) { cmp = galilean1->scale < galilean2->scale ? -1 : galilean1->scale == galilean2->scale ? 0 : 1; if (cmp == 0) cmp = COMPARE(galilean1->unit, galilean2->unit); } } return cmp; } static void galileanFree( ut_unit* const unit) { if (unit != NULL) { assert(IS_GALILEAN(unit)); FREE(unit->galilean.unit); cv_free(unit->common.toProduct); unit->common.toProduct = NULL; cv_free(unit->common.fromProduct); unit->common.fromProduct = NULL; free((void*)unit); } } /* * Multiplies a Galilean-unit by another unit. Any offset is ignored. * * Arguments: * unit1 The Galilean-unit. * unit2 The other unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* galileanMultiply( const ut_unit* const unit1, const ut_unit* const unit2) { ut_unit* result = NULL; /* failure */ const GalileanUnit* galilean1; assert(unit1 != NULL); assert(unit2 != NULL); assert(IS_GALILEAN(unit1)); galilean1 = &unit1->galilean; if (IS_PRODUCT(unit2)) { ut_unit* tmp = MULTIPLY(galilean1->unit, unit2); if (tmp != NULL) { result = galileanNew(galilean1->scale, tmp, 0); FREE(tmp); } } else if (IS_GALILEAN(unit2)) { const GalileanUnit* const galilean2 = &unit2->galilean; ut_unit* tmp = MULTIPLY(galilean1->unit, galilean2->unit); if (tmp != NULL) { result = galileanNew(galilean1->scale * galilean2->scale, tmp, 0); FREE(tmp); } } else { result = MULTIPLY(unit2, unit1); } return result; } /* * Returns the result of raising a Galilean-unit to a power. Any offset is * ignored. * * Arguments: * unit The Galilean-unit. * power The power. Must be greater than -256 and less than 256. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* galileanRaise( const ut_unit* const unit, const int power) { const GalileanUnit* galilean; ut_unit* tmp; ut_unit* result = NULL; /* failure */ assert(unit != NULL); assert(IS_GALILEAN(unit)); assert(power >= -255 && power <= 255); assert(power != 0); assert(power != 1); galilean = &unit->galilean; tmp = RAISE(galilean->unit, power); if (tmp != NULL) { result = galileanNew(pow(galilean->scale, power), tmp, 0); ut_free(tmp); } return result; } /* * Returns the result of taking a root of a Galilean-unit. Any offset is * ignored. * * Arguments: * unit The Galilean-unit. * root The root. Must be greater than 1 and less than 256. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* galileanRoot( const ut_unit* const unit, const int root) { const GalileanUnit* galilean; ut_unit* tmp; ut_unit* result = NULL; /* failure */ assert(unit != NULL); assert(IS_GALILEAN(unit)); assert(root > 1 && root <= 255); galilean = &unit->galilean; tmp = ROOT(galilean->unit, root); if (tmp != NULL) { result = galileanNew(pow(galilean->scale, 1.0/root), tmp, 0); ut_free(tmp); } return result; } /* * Initializes the converter of numeric values from the given Galilean unit to * the underlying product-unit. * * Arguments: * unit The Galilean unit. * Returns: * -1 Failure. "ut_get_status()" will be: * UT_OS Operating-system fault. See "errno". * 0 Success. */ static int galileanInitConverterToProduct( ut_unit* const unit) { int retCode = -1; /* failure */ cv_converter* toUnderlying; assert(unit != NULL); assert(IS_GALILEAN(unit)); toUnderlying = cv_get_galilean( unit->galilean.scale, unit->galilean.offset * unit->galilean.scale); if (toUnderlying == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("galileanInitConverterToProduct(): " "Couldn't get converter to underlying unit"); } else { if (ENSURE_CONVERTER_TO_PRODUCT(unit->galilean.unit)) { assert(unit->common.toProduct == NULL); unit->common.toProduct = cv_combine( toUnderlying, unit->galilean.unit->common.toProduct); if (unit->common.toProduct == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("galileanInitConverterToProduct(): " "Couldn't combine converters"); } else { retCode = 0; } } cv_free(toUnderlying); } /* "toUnderlying" allocated */ return retCode; } /* * Initializes the converter of numeric values to the given Galilean unit from * the underlying product-unit. * * Arguments: * unit The Galilean unit. * Returns: * -1 Failure. "ut_get_status()" will be: * UT_OS Operating-system fault. See "errno". * 0 Success. */ static int galileanInitConverterFromProduct( ut_unit* const unit) { int retCode = -1; /* failure */ cv_converter* fromUnderlying; assert(unit != NULL); assert(IS_GALILEAN(unit)); fromUnderlying = cv_get_galilean( 1.0/unit->galilean.scale, -unit->galilean.offset); if (fromUnderlying == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("galileanInitConverterFromProduct(): " "Couldn't get converter from underlying unit"); } else { if (ENSURE_CONVERTER_FROM_PRODUCT(unit->galilean.unit)) { assert(unit->common.fromProduct == NULL); unit->common.fromProduct = cv_combine( unit->galilean.unit->common.fromProduct, fromUnderlying); if (unit->common.fromProduct == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("galileanInitConverterFromProduct(): " "Couldn't combine converters"); } else { retCode = 0; } } cv_free(fromUnderlying); } /* "fromUnderlying" allocated */ return retCode; } static ut_status galileanAcceptVisitor( const ut_unit* const unit, const ut_visitor* const visitor, void* const arg) { assert(unit != NULL); assert(IS_GALILEAN(unit)); assert(visitor != NULL); return visitor->visit_galilean(unit, unit->galilean.scale, unit->galilean.unit, unit->galilean.offset, arg); } static UnitOps galileanOps = { galileanGetProduct, galileanClone, galileanFree, galileanCompare, galileanMultiply, galileanRaise, galileanRoot, galileanInitConverterToProduct, galileanInitConverterFromProduct, galileanAcceptVisitor }; /****************************************************************************** * Timestamp Unit: ******************************************************************************/ static UnitOps timestampOps; /* * Returns a new unit instance. * * Arguments: * unit The underlying unit. May be freed upon return. * origin The timestamp origin. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_OS Operating-system error. See "errno". * UT_MEANINGLESS Creation of a timestamp unit based on * "unit" is not meaningful. * UT_NO_SECOND The associated unit-system doesn't * contain a second unit. * else The newly-allocated, timestamp-unit. */ static ut_unit* timestampNewOrigin( const ut_unit* unit, const double origin) { ut_unit* newUnit = NULL; /* failure */ ut_unit* secondUnit; assert(unit != NULL); assert(!IS_TIMESTAMP(unit)); secondUnit = unit->common.system->second; if (secondUnit == NULL) { ut_set_status(UT_NO_SECOND); ut_handle_error_message("galileanInitConverterFromProduct(): " "No \"second\" unit defined"); } else if (ut_are_convertible(secondUnit, unit)) { TimestampUnit* timestampUnit = malloc(sizeof(TimestampUnit)); if (timestampUnit == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("timestampNewOrigin(): " "Couldn't allocate %lu-byte timestamp-unit", sizeof(TimestampUnit)); } else { if (commonInit(×tampUnit->common, ×tampOps, unit->common.system, TIMESTAMP) == 0) { timestampUnit->origin = origin; timestampUnit->unit = CLONE(unit); } else { free(timestampUnit); timestampUnit = NULL; } } /* "timestampUnit" allocated */ newUnit = (ut_unit*)timestampUnit; } /* "secondUnit != NULL" && time unit */ return newUnit; } #if 0 /* * Returns a new unit instance. * * Arguments: * unit The underlying unit. May be freed upon return. * year The year of the origin. * month The month of the origin. * day The day of the origin. * hour The hour of the origin. * minute The minute of the origin. * second The second of the origin. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_OS Operating-system error. See "errno". * UT_MEANINGLESS Creation of a timestamp unit base on * "unit" is not meaningful. * UT_NO_SECOND The associated unit-system doesn't * contain a unit named "second". * else The newly-allocated, timestamp-unit. */ static ut_unit* timestampNew( ut_unit* unit, const int year, const int month, const int day, const int hour, const int minute, double second) { assert(unit != NULL); return timestampNewOrigin( unit, ut_encode_time(year, month, day, hour, minute, second)); } #endif static ProductUnit* timestampGetProduct( const ut_unit* const unit) { assert(unit != NULL); assert(IS_TIMESTAMP(unit)); return GET_PRODUCT(unit->timestamp.unit); } static ut_unit* timestampClone( const ut_unit* const unit) { assert(unit != NULL); assert(IS_TIMESTAMP(unit)); return timestampNewOrigin(unit->timestamp.unit, unit->timestamp.origin); } static int timestampCompare( const ut_unit* const unit1, const ut_unit* const unit2) { int cmp; assert(unit1 != NULL); assert(IS_TIMESTAMP(unit1)); assert(unit2 != NULL); if (!IS_TIMESTAMP(unit2)) { int diff = unit1->common.type - unit2->common.type; cmp = diff < 0 ? -1 : diff == 0 ? 0 : 1; } else { const TimestampUnit* const timestamp1 = &unit1->timestamp; const TimestampUnit* const timestamp2 = &unit2->timestamp; cmp = timestamp1->origin < timestamp2->origin ? -1 : timestamp1->origin == timestamp2->origin ? 0 : -1; if (cmp == 0) cmp = COMPARE(timestamp1->unit, timestamp2->unit); } return cmp; } static void timestampFree( ut_unit* const unit) { if (unit != NULL) { assert(IS_TIMESTAMP(unit)); FREE(unit->timestamp.unit); unit->timestamp.unit = NULL; cv_free(unit->common.toProduct); unit->common.toProduct = NULL; cv_free(unit->common.fromProduct); unit->common.fromProduct = NULL; free((void*)unit); } } /* * Multiplies a timestamp-unit by another unit. The origin is ignored. * * Arguments: * unit1 The timestamp-unit. * unit2 The other unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* timestampMultiply( const ut_unit* const unit1, const ut_unit* const unit2) { assert(unit1 != NULL); assert(IS_TIMESTAMP(unit1)); assert(unit2 != NULL); return MULTIPLY(unit1->timestamp.unit, unit2); } /* * Returns the result of raising a Timestamp-unit to a power. The origin is * ignored. * * Arguments: * unit The Timestamp-unit. * power The power. Must be greater than -256 and less than 256. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* timestampRaise( const ut_unit* const unit, const int power) { assert(unit != NULL); assert(IS_TIMESTAMP(unit)); assert(power != 0); assert(power != 1); return RAISE(unit->timestamp.unit, power); } /* * Returns the result of taking a root of a Timestamp-unit. The origin is * ignored. * * Arguments: * unit The Timestamp-unit. * root The root. Must be greater than 1 and less than 256. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* timestampRoot( const ut_unit* const unit, const int root) { assert(unit != NULL); assert(IS_TIMESTAMP(unit)); assert(root > 1 && root < 256); return ROOT(unit->timestamp.unit, root); } /* * Initializes the converter of numeric values from the given Timestamp unit to * the underlying product-unit. * * Arguments: * unit The Timestamp unit. * Returns: * -1 Failure. */ static int timestampInitConverterToProduct( ut_unit* const unit) { /* * This function is never called. */ assert(0); return -1; } /* * Initializes the converter of numeric values to the given Timestamp unit from * the underlying product-unit. * * Arguments: * unit The Timestamp unit. * Returns: * -1 Failure. */ static int timestampInitConverterFromProduct( ut_unit* const unit) { /* * This function is never called. */ assert(0); return -1; } static ut_status timestampAcceptVisitor( const ut_unit* const unit, const ut_visitor* const visitor, void* const arg) { assert(unit != NULL); assert(IS_TIMESTAMP(unit)); assert(visitor != NULL); return visitor->visit_timestamp(unit, unit->timestamp.unit, unit->timestamp.origin, arg); } static UnitOps timestampOps = { timestampGetProduct, timestampClone, timestampFree, timestampCompare, timestampMultiply, timestampRaise, timestampRoot, timestampInitConverterToProduct, timestampInitConverterFromProduct, timestampAcceptVisitor }; /****************************************************************************** * Logarithmic Unit: ******************************************************************************/ static UnitOps logOps; /* * Returns a new instance. * * Arguments: * base The logarithmic base (e.g., 2, M_E, 10). Must be * greater than one. * reference The reference value. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_OS Operating-system error. See "errno". * else The newly-allocated, logarithmic-unit. */ static ut_unit* logNew( const double base, const ut_unit* const reference) { LogUnit* logUnit; assert(base > 1); assert(reference != NULL); logUnit = malloc(sizeof(LogUnit)); if (logUnit == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "logNew(): Couldn't allocate %lu-byte logarithmic-unit", sizeof(LogUnit)); } else { if (commonInit(&logUnit->common, &logOps, reference->common.system, LOG) != 0) { free(logUnit); } else { logUnit->reference = CLONE(reference); if (logUnit->reference != NULL) { logUnit->base = base; } else { free(logUnit); logUnit = NULL; } } } return (ut_unit*)logUnit; } static ProductUnit* logGetProduct( const ut_unit* const unit) { assert(unit != NULL); assert(IS_LOG(unit)); return GET_PRODUCT(unit->log.reference); } static ut_unit* logClone( const ut_unit* const unit) { assert(unit != NULL); assert(IS_LOG(unit)); return logNew(unit->log.base, unit->log.reference); } static int logCompare( const ut_unit* const unit1, const ut_unit* const unit2) { int cmp; assert(unit1 != NULL); assert(IS_LOG(unit1)); assert(unit2 != NULL); if (!IS_LOG(unit2)) { int diff = unit1->common.type - unit2->common.type; cmp = diff < 0 ? -1 : diff == 0 ? 0 : 1; } else { const LogUnit* const u1 = &unit1->log; const LogUnit* const u2 = &unit2->log; cmp = ut_compare(u1->reference, u2->reference); if (cmp == 0) cmp = u1->base < u2->base ? -1 : u1->base == u2->base ? 0 : 1; } return cmp; } static void logFree( ut_unit* const unit) { if (unit != NULL) { assert(IS_LOG(unit)); FREE(unit->log.reference); unit->log.reference = NULL; cv_free(unit->common.toProduct); unit->common.toProduct = NULL; cv_free(unit->common.fromProduct); unit->common.fromProduct = NULL; free((void*)unit); } } /* * Multiplies a logarithmic-unit by another unit. * * Arguments: * unit1 The logarithmic-unit. * unit2 The other unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* logMultiply( const ut_unit* const unit1, const ut_unit* const unit2) { ut_unit* result = NULL; /* failure */ assert(unit1 != NULL); assert(IS_LOG(unit1)); assert(unit2 != NULL); if (!ut_is_dimensionless(unit2)) { ut_set_status(UT_MEANINGLESS); ut_handle_error_message("logMultiply(): Second unit not dimensionless"); } else if (IS_BASIC(unit2) || IS_PRODUCT(unit2)) { result = CLONE(unit1); } else if (IS_GALILEAN(unit2)) { result = galileanNew(unit2->galilean.scale, unit1, 0); } else { ut_set_status(UT_MEANINGLESS); ut_handle_error_message("logMultiply(): can't multiply second unit"); } return result; } /* * Returns the result of raising a logarithmic-unit to a power. * * Arguments: * unit The logarithmic-unit. * power The power. Must be greater than -256 and less than 256. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* logRaise( const ut_unit* const unit, const int power) { assert(unit != NULL); assert(IS_LOG(unit)); assert(power != 0); assert(power != 1); /* * We don't know how to raise a logarithmic unit to a non-zero power. */ ut_set_status(UT_MEANINGLESS); ut_handle_error_message( "logRaise(): Can't raise logarithmic-unit to non-zero power"); return NULL; } /* * Returns the result of taking a root of a logarithmic-unit. * * Arguments: * unit The logarithmic-unit. * root The root. Must be greater than 1 and less than 256. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_MEANINGLESS The operation on the given units is * meaningless. * else The resulting unit. */ static ut_unit* logRoot( const ut_unit* const unit, const int root) { assert(unit != NULL); assert(IS_LOG(unit)); assert(root > 1 && root < 256); /* * We don't know how to take a root of a logarithmic unit. */ ut_set_status(UT_MEANINGLESS); ut_handle_error_message( "logRoot(): Can't take a non-unity root of a logarithmic-unit"); return NULL; } /* * Initializes the converter of numeric values from the given logarithmic unit * to the underlying product-unit. * * Arguments: * unit The logarithmic unit. * Returns: * -1 Failure. "ut_get_status()" will be: * UT_OS Operating-system fault. See "errno". * 0 Success. */ static int logInitConverterToProduct( ut_unit* const unit) { int retCode = -1; /* failure */ cv_converter* toUnderlying; assert(unit != NULL); assert(IS_LOG(unit)); toUnderlying = cv_get_pow(unit->log.base); if (toUnderlying == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("logInitConverterToProduct(): " "Couldn't get converter to underlying unit"); } else { if (ENSURE_CONVERTER_TO_PRODUCT(unit->log.reference)) { assert(unit->common.toProduct == NULL); unit->common.toProduct = cv_combine( toUnderlying, unit->log.reference->common.toProduct); if (unit->common.toProduct == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("logInitConverterToProduct(): " "Couldn't combine converters"); } else { retCode = 0; } } cv_free(toUnderlying); } /* "toUnderlying" allocated */ return retCode; } /* * Initializes the converter of numeric values to the given logarithmic unit * from the underlying product-unit. * * Arguments: * unit The logarithmic unit. * Returns: * -1 Failure. "ut_get_status()" will be: * UT_OS Operating-system fault. See "errno". * 0 Success. */ static int logInitConverterFromProduct( ut_unit* const unit) { int retCode = -1; /* failure */ cv_converter* fromUnderlying; assert(unit != NULL); assert(IS_LOG(unit)); fromUnderlying = cv_get_log(unit->log.base); if (fromUnderlying == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("logInitConverterFromProduct(): " "Couldn't get converter from underlying unit"); } else { if (ENSURE_CONVERTER_FROM_PRODUCT(unit->log.reference)) { assert(unit->common.fromProduct == NULL); unit->common.fromProduct = cv_combine( unit->log.reference->common.fromProduct, fromUnderlying); if (unit->common.fromProduct == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("logInitConverterFromProduct(): " "Couldn't combine converters"); } else { retCode = 0; } } cv_free(fromUnderlying); } /* "fromUnderlying" allocated */ return retCode; } static ut_status logAcceptVisitor( const ut_unit* const unit, const ut_visitor* const visitor, void* const arg) { assert(unit != NULL); assert(IS_LOG(unit)); assert(visitor != NULL); return visitor->visit_logarithmic(unit, unit->log.base, unit->log.reference, arg); } static UnitOps logOps = { logGetProduct, logClone, logFree, logCompare, logMultiply, logRaise, logRoot, logInitConverterToProduct, logInitConverterFromProduct, logAcceptVisitor }; /****************************************************************************** * Public API: ******************************************************************************/ /* * Returns a new unit-system. On success, the unit-system will only contain * the dimensionless unit one. See "ut_get_dimensionless_unit_one()". * * Returns: * NULL Failure. "ut_get_status()" will be: * UT_OS Operating-system error. See "errno". * else Pointer to a new unit system. */ ut_system* ut_new_system(void) { ut_system* system = malloc(sizeof(ut_system)); ut_set_status(UT_SUCCESS); if (system == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "ut_new_system(): Couldn't allocate %lu-byte unit-system", sizeof(ut_system)); } else { system->second = NULL; system->basicUnits = NULL; system->basicCount = 0; system->one = (ut_unit*)productNew(system, NULL, NULL, 0); if (ut_get_status() != UT_SUCCESS) { ut_handle_error_message( "ut_new_system(): Couldn't create dimensionless unit one"); free(system); } } return system; } /* * Frees resources associated with a unit-system by this module. * * Arguments: * system Pointer to the unit-system. */ void coreFreeSystem( ut_system* system) { if (system != NULL) { int i; for (i = 0; i < system->basicCount; ++i) basicFree((ut_unit*)system->basicUnits[i]); free(system->basicUnits); if (system->second != NULL) FREE(system->second); if (system->one != NULL) productReallyFree(system->one); free(system); } } /* * Returns the dimensionless-unit one of a unit-system. * * Arguments: * system Pointer to the unit-system for which the dimensionless-unit one * will be returned. * Returns: * NULL Failure. "utgetStatus()" will be: * UT_BAD_ARG "system" is NULL. * else Pointer to the dimensionless-unit one associated with "system". * While not necessary, the pointer may be passed to ut_free() * when the unit is no longer needed by the client. */ ut_unit* ut_get_dimensionless_unit_one( const ut_system* const system) { ut_unit* one; ut_set_status(UT_SUCCESS); if (system == NULL) { one = NULL; ut_set_status(UT_BAD_ARG); ut_handle_error_message( "ut_get_dimensionless_unit_one(): NULL unit-system argument"); } else { one = system->one; } return one; } /* * Returns the unit-system to which a unit belongs. * * Arguments: * unit Pointer to the unit in question. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * else Pointer to the unit-system to which "unit" belongs. */ ut_system* ut_get_system( const ut_unit* const unit) { ut_system* system; ut_set_status(UT_SUCCESS); if (unit == NULL) { system = NULL; ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_get_system(): NULL unit argument"); } else { system = unit->common.system; } return system; } /* * Indicates if two units belong to the same unit-system. * * Arguments: * unit1 Pointer to a unit. * unit2 Pointer to another unit. * Returns: * 0 Failure or the units belong to different unit-systems. * "ut_get_status()" will be * UT_BAD_ARG "unit1" or "unit2" is NULL. * UT_SUCCESS The units belong to different * unit-systems. * else The units belong to the same unit-system. */ int ut_same_system( const ut_unit* const unit1, const ut_unit* const unit2) { int sameSystem = 0; if (unit1 == NULL || unit2 == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_same_system(): NULL argument"); } else { ut_set_status(UT_SUCCESS); sameSystem = unit1->common.system == unit2->common.system; } return sameSystem; } /* * Returns a new basic-unit that has been added to a unit-system. * * Arguments: * system The unit-system to which to add the new basic-unit. * isDimensionless Whether or not the basic-unit is dimensionless (e.g., * a radian). * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "system" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the new base-unit. */ static BasicUnit* newBasicUnit( ut_system* const system, const int isDimensionless) { BasicUnit* basicUnit = NULL; /* failure */ if (system == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("newBasicUnit(): NULL unit-system argument"); } else { basicUnit = basicNew(system, isDimensionless, system->basicCount); if (basicUnit != NULL) { int error = 1; BasicUnit* save = (BasicUnit*)basicClone((ut_unit*)basicUnit); if (save == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "newBasicUnit(): Couldn't clone basic-unit"); } else { BasicUnit** basicUnits = realloc(system->basicUnits, (system->basicCount+1)*sizeof(BasicUnit*)); if (basicUnits == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("newBasicUnit(): " "Couldn't allocate %d-element basic-unit array", system->basicCount+1); } else { basicUnits[system->basicCount++] = save; system->basicUnits = basicUnits; error = 0; } /* "system->basicUnits" re-allocated */ if (error) basicFree((ut_unit*)save); } /* "save" allocated */ if (error) { basicFree((ut_unit*)basicUnit); basicUnit = NULL; } } /* "basicUnit" allocated */ } /* valid arguments */ return basicUnit; } /* * Adds a base-unit to a unit-system. Clients that use ut_read_xml() should not * normally need to call this function. * * Arguments: * system Pointer to the unit-system to which to add the new base-unit. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "system" or "name" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the new base-unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client (the * unit will remain in the unit-system). */ ut_unit* ut_new_base_unit( ut_system* const system) { BasicUnit* basicUnit = newBasicUnit(system, 0); return (ut_unit*)basicUnit; } /* * Adds a dimensionless-unit to a unit-system. In the SI system of units, the * derived-unit radian is a dimensionless-unit. Clients that use ut_read_xml() * should not normally need to call this function. * * Arguments: * system Pointer to the unit-system to which to add the new * dimensionless-unit. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "system" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the new dimensionless-unit. The pointer should be * passed to ut_free() when the unit is no longer needed by the * client (the unit will remain in the unit-system). */ ut_unit* ut_new_dimensionless_unit( ut_system* const system) { return (ut_unit*)newBasicUnit(system, 1); } /* * Sets the "second" unit of a unit-system. This function must be called before * the first call to "ut_offset_by_time()". ut_read_xml() calls this function if the * resulting unit-system contains a unit named "second". * * Arguments: * second Pointer to the "second" unit. * Returns: * UT_BAD_ARG "second" is NULL. * UT_EXISTS The second unit of the unit-system to which "second" * belongs is set to a different unit. * UT_SUCCESS Success. */ ut_status ut_set_second( const ut_unit* const second) { ut_set_status(UT_SUCCESS); if (second == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message( "ut_set_second(): NULL \"second\" unit argument"); } else { ut_system* system = second->common.system; if (system->second == NULL) { system->second = CLONE(second); } else { if (ut_compare(system->second, second) != 0) { ut_set_status(UT_EXISTS); ut_handle_error_message( "ut_set_second(): Different \"second\" unit already " "defined"); } } } return ut_get_status(); } /* * Compares two units. Returns a value less than, equal to, or greater than * zero as the first unit is considered less than, equal to, or greater than * the second unit, respectively. Units from different unit-systems never * compare equal. * * Arguments: * unit1 Pointer to a unit or NULL. * unit2 Pointer to another unit or NULL. * Returns: * <0 The first unit is less than the second unit. * 0 The first and second units are equal or both units are NULL. * >0 The first unit is greater than the second unit. */ int ut_compare( const ut_unit* const unit1, const ut_unit* const unit2) { int cmp = 0; ut_set_status(UT_SUCCESS); if (unit1 == NULL) { cmp = unit2 != NULL ? -1 : 0; } else if (unit2 == NULL) { cmp = 1; } else if (unit1->common.system < unit2->common.system) { cmp = -1; } else if (unit1->common.system > unit2->common.system) { cmp = 1; } else { /* * NB: The comparison function is called if and only if the units * belong to the same unit-system. */ cmp = COMPARE(unit1, unit2); } return cmp; } /* * Returns a unit equivalent to another unit scaled by a numeric factor, * e.g., * const ut_unit* meter = ... * const ut_unit* kilometer = ut_scale(1000, meter); * * Arguments: * factor The numeric scale factor. * unit Pointer to the unit to be scaled. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "factor" is 0 or "unit" is NULL. * UT_OS Operating-system error. See * "errno". * else Pointer to the resulting unit. The pointer should be * passed to ut_free() when the unit is no longer needed by * the client. */ ut_unit* ut_scale( const double factor, const ut_unit* const unit) { ut_unit* result = NULL; /* failure */ ut_set_status(UT_SUCCESS); if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_scale(): NULL unit argument"); } else { if (factor == 0) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_scale(): NULL factor argument"); } else { result = factor == 1 ? CLONE(unit) : galileanNew(factor, unit, 0.0); } } return result; } /* * Returns a unit equivalent to another unit offset by a numeric amount, * e.g., * const ut_unit* kelvin = ... * const ut_unit* celsius = ut_offset(kelvin, 273.15); * * Arguments: * unit Pointer to the unit to be offset. * offset The numeric offset. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_OS Operating-system error. See * "errno". * else Pointer to the resulting unit. The pointer should be * passed to ut_free() when the unit is no longer needed by * the client. */ ut_unit* ut_offset( const ut_unit* const unit, const double offset) { ut_unit* result = NULL; /* failure */ ut_set_status(UT_SUCCESS); if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_offset(): NULL unit argument"); } else { result = offset == 0 ? CLONE(unit) : galileanNew(1.0, unit, offset); } return result; } /* * Returns a unit equivalent to another unit relative to a particular time. * e.g., * const ut_unit* second = ... * const ut_unit* secondsSinceTheEpoch = * ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0.0)); * * Arguments: * unit Pointer to the time-unit to be made relative to a time-origin. * origin The origin as returned by ut_encode_time(). * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_OS Operating-system error. See "errno". * UT_MEANINGLESS Creation of a timestamp unit based on * "unit" is not meaningful. * UT_NO_SECOND The associated unit-system doesn't * contain a "second" unit. See * ut_set_second(). * else Pointer to the resulting unit. The pointer should be passed * to ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_offset_by_time( const ut_unit* const unit, const double origin) { ut_unit* result = NULL; /* failure */ ut_set_status(UT_SUCCESS); if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_offset_by_time(): NULL unit argument"); } else { result = timestampNewOrigin(unit, origin); } return result; } /* * Returns the result of multiplying one unit by another unit. * * Arguments: * unit1 Pointer to a unit. * unit2 Pointer to another unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit1" or "unit2" is NULL. * UT_NOT_SAME_SYSTEM "unit1" and "unit2" belong to * different unit-systems. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed * to ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_multiply( const ut_unit* const unit1, const ut_unit* const unit2) { ut_unit* result = NULL; /* failure */ ut_set_status(UT_SUCCESS); if (unit1 == NULL || unit2 == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_multiply(): NULL argument"); } else if (unit1->common.system != unit2->common.system) { ut_set_status(UT_NOT_SAME_SYSTEM); ut_handle_error_message( "ut_multiply(): Units in different unit-systems"); } else { result = MULTIPLY(unit1, unit2); } return result; } /* * Returns the inverse (i.e., reciprocal) of a unit. This convenience function * is equal to "ut_raise(unit, -1)". * * Arguments: * unit Pointer to the unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_invert( const ut_unit* const unit) { return ut_raise(unit, -1); } /* * Returns the result of dividing one unit by another unit. This convenience * function is equivalent to the following sequence: * { * ut_unit* inverse = ut_invert(denom); * ut_multiply(numer, inverse); * ut_free(inverse); * } * * Arguments: * numer Pointer to the numerator (top, dividend) unit. * denom Pointer to the denominator (bottom, divisor) unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "numer" or "denom" is NULL. * UT_NOT_SAME_SYSTEM "unit1" and "unit2" belong to * different unit-systems. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_divide( const ut_unit* const numer, const ut_unit* const denom) { ut_unit* result = NULL; /* failure */ ut_set_status(UT_SUCCESS); if (numer == NULL || denom == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_divide(): NULL argument"); } else if (numer->common.system != denom->common.system) { ut_set_status(UT_NOT_SAME_SYSTEM); ut_handle_error_message("ut_divide(): Units in different unit-systems"); } else { ut_unit* inverse = RAISE(denom, -1); if (inverse != NULL) { result = MULTIPLY(numer, inverse); ut_free(inverse); } } return result; } /* * Returns the result of raising a unit to a power. * * Arguments: * unit Pointer to the unit. * power The power by which to raise "unit". Must be greater than or * equal to -255 and less than or equal to 255. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit" is NULL, or "power" is invalid. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_raise( const ut_unit* const unit, const int power) { ut_unit* result = NULL; /* failure */ ut_set_status(UT_SUCCESS); if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_raise(): NULL unit argument"); } else if (power < -255 || power > 255) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_raise(): Invalid power argument"); } else { result = power == 0 ? unit->common.system->one : power == 1 ? CLONE(unit) : RAISE(unit, power); } return result; } /* * Returns the result of taking the root of a unit. * * Arguments: * unit Pointer to the unit. * root The root to take of "unit". Must be greater than or * equal to 1 and less than or equal to 255. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit" is NULL, or "root" is invalid. * In particular, all powers of base units * in "unit" must be integral multiples of * "root". * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_root( const ut_unit* const unit, const int root) { ut_unit* result = NULL; /* failure */ ut_set_status(UT_SUCCESS); if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_root(): NULL unit argument"); } else if (root < 1 || root > 255) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_root(): Invalid root argument"); } else { result = root == 1 ? CLONE(unit) : ROOT(unit, root); } return result; } /* * Returns the logarithmic unit corresponding to a logarithmic base and a * reference level. For example, the following creates a decibel unit with a * one milliwatt reference level: * * const ut_unit* watt = ...; * const ut_unit* milliWatt = ut_scale(0.001, watt); * * if (milliWatt != NULL) { * const ut_unit* bel_1_mW = ut_log(10.0, milliWatt); * * if (bel_1_mW != NULL) { * const ut_unit* decibel_1_mW = ut_scale(0.1, bel_1_mW); * * if (decibel_1_mW != NULL) { * ... * ut_free(decibel_1_mW); * } // "decibel_1_mW" allocated * * ut_free(bel_1_mW); * } // "bel_1_mW" allocated * * ut_free(milliWatt); * } // "milliWatt" allocated * * Arguments: * base The logarithmic base (e.g., 2, M_E, 10). Must be * greater than one. "M_E" is defined in . * reference Pointer to the reference value as a unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "base" is invalid or "reference" * is NULL. * UT_OS Operating-system error. See * "errno". * else Pointer to the resulting unit. The pointer should be * passed to ut_free() when the unit is no longer needed by * the client. */ ut_unit* ut_log( const double base, const ut_unit* const reference) { ut_unit* result = NULL; /* failure */ ut_set_status(UT_SUCCESS); if (base <= 1) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_log(): Invalid logarithmic base, %g", base); } else if (reference == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_log(): NULL reference argument"); } else { result = logNew(base, reference); } return result; } /* * Indicates if numeric values in one unit are convertible to numeric values in * another unit via "ut_get_converter()". In making this determination, * dimensionless units are ignored. * * Arguments: * unit1 Pointer to a unit. * unit2 Pointer to another unit. * Returns: * 0 Failure. "ut_get_status()" will be * UT_BAD_ARG "unit1" or "unit2" is NULL. * UT_NOT_SAME_SYSTEM "unit1" and "unit2" belong to * different unit-sytems. * UT_SUCCESS Conversion between the units is * not possible (e.g., "unit1" is * "meter" and "unit2" is * "kilogram"). * else Numeric values can be converted between the units. */ int ut_are_convertible( const ut_unit* const unit1, const ut_unit* const unit2) { int areConvertible = 0; if (unit1 == NULL || unit2 == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_are_convertible(): NULL unit argument"); } else if (unit1->common.system != unit2->common.system) { ut_set_status(UT_NOT_SAME_SYSTEM); ut_handle_error_message( "ut_are_convertible(): Units in different unit-systems"); } else { ut_set_status(UT_SUCCESS); if (IS_TIMESTAMP(unit1) || IS_TIMESTAMP(unit2)) { areConvertible = IS_TIMESTAMP(unit1) && IS_TIMESTAMP(unit2); } else { ProductRelationship relationship = productRelationship(GET_PRODUCT(unit1), GET_PRODUCT(unit2)); areConvertible = relationship == PRODUCT_EQUAL || relationship == PRODUCT_INVERSE; } } return areConvertible; } /* * Returns a converter of numeric values in one unit to numeric values in * another unit. The returned converter should be passed to cv_free() when it * is no longer needed by the client. * * NOTE: Leap seconds are not taken into account when converting between * timestamp units. * * Arguments: * from Pointer to the unit from which to convert values. * to Pointer to the unit to which to convert values. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "from" or "to" is NULL. * UT_NOT_SAME_SYSTEM "from" and "to" belong to * different unit-systems. * UT_MEANINGLESS Conversion between the units is * not possible. See * "ut_are_convertible()". * else Pointer to the appropriate converter. The pointer * should be passed to cv_free() when no longer needed by * the client. */ cv_converter* ut_get_converter( ut_unit* const from, ut_unit* const to) { cv_converter* converter = NULL; /* failure */ if (from == NULL || to == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_get_converter(): NULL unit argument"); } else if (from->common.system != to->common.system) { ut_set_status(UT_NOT_SAME_SYSTEM); ut_handle_error_message( "ut_get_converter(): Units in different unit-systems"); } else { ut_set_status(UT_SUCCESS); if (!IS_TIMESTAMP(from) && !IS_TIMESTAMP(to)) { ProductRelationship relationship = productRelationship(GET_PRODUCT(from), GET_PRODUCT(to)); if (relationship == PRODUCT_UNCONVERTIBLE) { ut_set_status(UT_MEANINGLESS); ut_handle_error_message( "ut_get_converter(): Units not convertible"); } else if (ENSURE_CONVERTER_TO_PRODUCT(from) && ENSURE_CONVERTER_FROM_PRODUCT(to)) { if (relationship == PRODUCT_EQUAL) { converter = cv_combine( from->common.toProduct, to->common.fromProduct); } else { /* * The underlying product-units are reciprocals of each * other. */ cv_converter* invert = cv_get_inverse(); if (invert != NULL) { cv_converter* phase1 = cv_combine(from->common.toProduct, invert); if (phase1 != NULL) { converter = cv_combine(phase1, to->common.fromProduct); cv_free(phase1); } /* "phase1" allocated */ cv_free(invert); } /* "invert" allocated */ } /* reciprocal product-units */ if (converter == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "ut_get_converter(): Couldn't get converter"); } } /* got necessary product converters */ } /* neither unit is a timestamp */ else { cv_converter* toSeconds = ut_get_converter(from->timestamp.unit, from->common.system->second); if (toSeconds == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "ut_get_converter(): Couldn't get converter to seconds"); } else { cv_converter* shiftOrigin = cv_get_offset( from->timestamp.origin - to->timestamp.origin); if (shiftOrigin == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "ut_get_converter(): Couldn't get offset-converter"); } else { cv_converter* toToUnit = cv_combine(toSeconds, shiftOrigin); if (toToUnit == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "ut_get_converter(): Couldn't combine converters"); } else { cv_converter* fromSeconds = ut_get_converter( to->common.system->second, to->timestamp.unit); if (fromSeconds == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "ut_get_converter(): Couldn't get converter " "from seconds"); } else { converter = cv_combine(toToUnit, fromSeconds); if (converter == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("ut_get_converter(): " "Couldn't combine converters"); } cv_free(fromSeconds); } /* "fromSeconds" allocated */ cv_free(toToUnit); } /* "toToUnit" allocated */ cv_free(shiftOrigin); } /* "shiftOrigin" allocated */ cv_free(toSeconds); } /* "toSeconds" allocated */ } /* units are timestamps */ } /* valid arguments */ return converter; } /* * Indicates if a given unit is dimensionless or not. Note that logarithmic * units are dimensionless by definition. * * Arguments: * unit Pointer to the unit in question. * Returns: * 0 "unit" is dimensionfull or an error occurred. "ut_get_status()" * will be * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS "unit" is dimensionfull. * else "unit" is dimensionless. */ int ut_is_dimensionless( const ut_unit* const unit) { int isDimensionless = 0; ut_set_status(UT_SUCCESS); if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_is_dimensionless(): NULL unit argument"); } else { /* * Special case logarithmic units because logGetProduct() can be * dimensionfull. */ isDimensionless = IS_LOG(unit) ? 1 : productIsDimensionless(GET_PRODUCT(unit)); } return isDimensionless; } /* * Returns a clone of a unit. * * Arguments: * unit Pointer to the unit to be cloned. * Returns: * NULL Failure. ut_get_status() will be * UT_OS Operating-system failure. See "errno". * UT_BAD_ARG "unit" is NULL. * else Pointer to the clone of "unit". The pointer should be * passed to ut_free() when the unit is no longer needed by the * client. */ ut_unit* ut_clone( const ut_unit* const unit) { ut_unit* clone = NULL; /* failure */ ut_set_status(UT_SUCCESS); if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_clone(): NULL unit argument"); } else { clone = unit == unit->common.system->one ? (ut_unit*)unit : CLONE(unit); } return clone; } /* * Frees resources associated with a unit. This function should be invoked on * all units that are no longer needed by the client. Use of the unit upon * return from this function will result in undefined behavior. * * Arguments: * unit Pointer to the unit to have its resources freed or NULL. */ void ut_free( ut_unit* const unit) { ut_set_status(UT_SUCCESS); if (unit != NULL) { if (unit != unit->common.system->one) FREE(unit); } } /* * Accepts a visitor to a unit. * * Arguments: * unit Pointer to the unit to accept the visitor. * visitor Pointer to the visitor of "unit". * arg An arbitrary pointer that will be passed to "visitor". * Returns: * UT_BAD_ARG "unit" or "visitor" is NULL. * UT_VISIT_ERROR A error occurred in "visitor" while visiting "unit". * UT_SUCCESS Success. */ ut_status ut_accept_visitor( const ut_unit* const unit, const ut_visitor* const visitor, void* const arg) { ut_set_status(UT_SUCCESS); if (unit == NULL || visitor == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("ut_accept_visitor(): NULL argument"); } else { ut_set_status(ACCEPT_VISITOR(unit, visitor, arg)); } return ut_get_status(); } udunits-2.2.0/lib/udunits2lib.html0000644000175000017500000035607612260406756020271 0ustar amckinstryamckinstry The UDUNITS-2 C API Guide

    The UDUNITS-2 C API Guide


    Next: , Previous: (dir), Up: (dir)

    UDUNITS-2

    This manual describes how to use the C API of the UDUNITS-2 library. Among other things, the library allows C code to obtain a binary representation of a unit of a physical quantity, to operate on such units, and to convert numeric values between compatible units.

    The library comes with an extensive database of units all referenced to the SI system of units.

    Copyright 2013 University Corporation for Atmospheric Research. All rights reserved.

    This software was developed by the Unidata Program Center of the University Corporation for Atmospheric Research (UCAR) <http://www.unidata.ucar.edu>.

    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the names of the development group, the copyright holder, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4) This license shall terminate automatically and you may no longer exercise any of the rights granted to you by this license as of the date you commence an action, including a cross-claim or counterclaim, against the copyright holder or any contributor alleging that this software infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of this software with other software or hardware.

    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 CONTRIBUTORS 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 WITH THE SOFTWARE.


    Next: , Previous: Top, Up: Top

    1 Synopsis

    Coding:

         #include <udunits2.h>
         

    ut_system* ut_get_path_xml(const char* path);
    ut_system* ut_read_xml(const char* path);
    ut_system* ut_new_system(void);
    void ut_free_system(ut_system* system);
    ut_system* ut_get_system(const ut_unit* unit);
    ut_unit* ut_get_dimensionless_unit_one(const ut_system* system);
    ut_unit* ut_get_unit_by_name(const ut_system* system, const char* name);
    ut_unit* ut_get_unit_by_symbol(const ut_system* system, const char* symbol);
    ut_status ut_set_second(const ut_unit* second);
    ut_status ut_add_name_prefix(ut_system* system, const char* name, double value);
    ut_status ut_add_symbol_prefix(ut_system* system, const char* symbol, double value);
    ut_unit* ut_new_base_unit(ut_system* system);
    ut_unit* ut_new_dimensionless_unit(ut_system* system);
    ut_unit* ut_clone(const ut_unit* unit);
    void ut_free(ut_unit* unit);
    const char* ut_get_name(const ut_unit* unit, ut_encoding encoding);
    ut_status ut_map_name_to_unit(const char* name, const ut_encoding encoding, const ut_unit* unit);
    ut_status ut_unmap_name_to_unit(ut_system* system, const char* name, const ut_encoding encoding);
    ut_status ut_map_unit_to_name(const ut_unit* unit, const char* name, ut_encoding encoding);
    ut_status ut_unmap_unit_to_name(const ut_unit* unit, ut_encoding encoding);
    const char* ut_get_symbol(const ut_unit* unit, ut_encoding encoding);
    ut_status ut_map_symbol_to_unit(const char* symbol, const ut_encoding encoding, const ut_unit* unit);
    ut_status ut_unmap_symbol_to_unit(ut_system* system, const char* symbol, const ut_encoding encoding);
    ut_status ut_map_unit_to_symbol(const ut_unit* unit, const char* symbol, ut_encoding encoding);
    ut_status ut_unmap_unit_to_symbol(const ut_unit* unit, ut_encoding encoding);
    int ut_is_dimensionless(const ut_unit* unit);
    int ut_same_system(const ut_unit* unit1, const ut_unit* unit2);
    int ut_compare(const ut_unit* unit1, const ut_unit* unit2);
    int ut_are_convertible(const ut_unit* unit1, const ut_unit* unit2);
    cv_converter* ut_get_converter(ut_unit* from, ut_unit* to);
    ut_unit* ut_scale(double factor, const ut_unit* unit);
    ut_unit* ut_offset(const ut_unit* unit, double offset);
    ut_unit* ut_offset_by_time(const ut_unit* unit, double origin);
    ut_unit* ut_multiply(const ut_unit* unit1, const ut_unit* unit2);
    ut_unit* ut_invert(const ut_unit* unit);
    ut_unit* ut_divide(const ut_unit* numer, const ut_unit* denom);
    ut_unit* ut_raise(const ut_unit* unit, int power);
    ut_unit* ut_root(const ut_unit* unit, int root);
    ut_unit* ut_log(double base, const ut_unit* reference);
    ut_unit* ut_parse(const ut_system* system, const char* string, ut_encoding encoding);
    char* ut_trim(char* string, ut_encoding encoding);
    int ut_format(const ut_unit* unit, char* buf, size_t size, unsigned opts);
    ut_status ut_accept_visitor(const ut_unit* unit, const ut_visitor* visitor, void* arg);
    double ut_encode_date(int year, int month, int day);
    double ut_encode_clock(int hours, int minutes, double seconds);
    double ut_encode_time(int year, int month, int day, int hour, int minute, double second);
    void ut_decode_time(double value, int* year, int* month, int* day, int* hour, int* minute, double* second, double* resolution);
    ut_status ut_get_status(void);
    void ut_set_status(ut_status status);
    int ut_handle_error_message(const char* fmt, ...);
    ut_error_message_handlerut_set_error_message_handler(ut_error_message_handler handler);
    int ut_write_to_stderr(const char* fmt, va_list args);
    int ut_ignore(const char* fmt, va_list args);

    float cv_convert_float(const cv_converter* converter, float value);
    double cv_convert_double(const cv_converter* converter, double value);
    float* cv_convert_floats(const cv_converter* converter, const float* in, size_t count, float* out);
    double* cv_convert_doubles(const cv_converter* converter, const double* const in, size_t count, double* out);
    void cv_free(cv_converter* conv);

    Compiling:

         c89 -I includedir ...
    

    Where includedir is the installation-directory for C header files (e.g., /usr/local/include).

    Linking:

         c89 ... -Llibdir -ludunits2 -lexpat ... -lm
    

    Where libdir is the installation-directory for object code libraries (e.g., /usr/local/lib).


    Next: , Previous: Synopsis, Up: Top

    2 What's a Unit Package Good For?

    The existance of a software package is justified by what you can do with it. The three main things you can do with the UDUNIT-2 package are

    1. Convert numeric values between compatible units.
    2. Convert a string representation of a unit into a binary one — enabling the programatic manipulation of units. There are three ways to do this:
    3. Convert a binary representation of a unit into a string — enabling the printing and storing of units in a human-readable form.
    While the above might seem to be trivial activities, their general availability at the time might have helped prevent the Mars Climate Orbiter fiasco.


    Next: , Previous: Why, Up: Top

    3 Unit-Systems

    A unit-system is a set of units that are all defined in terms of the same set of base units. In the SI system of units, for example, the base units are the meter, kilogram, second, ampere, kelvin, mole, and candela. (For definitions of these base units, see http://physics.nist.gov/cuu/Units/current.html.)

    In the UDUNITS-2 package, every accessible unit belongs to one and only one unit-system. It is not possible to convert numeric values between units of different unit-systems. Similarly, units belonging to different unit-systems always compare unequal.

    There are several categories of operations on unit-systems:


    Next: , Up: Unit-Systems

    3.1 Obtaining a Unit-System

    Typically, you would obtain a unit-system of predefined units by reading the default unit database using ut_read_xml() with a NULL pathname argument. If this doesn't quite match your needs, then there are alternatives. Together with the typical solution, the means for obtaining a useful unit-system are (in order of increasing complexity):

    You should pass every unit-system pointer to ut_free_system() when you no longer need the corresponding unit-system.

    — Function: const char* ut_get_path_xml (const char* path, ut_status* status)

    Returns the pathname of the XML-formatted unit-database corresponding to path. If path is non-NULL, then it is returned; otherwise, if the environment variable UDUNITS2_XML_PATH is set, then its value is returned; otherwise, the pathname of the default unit-database is returned. The value of *status indicates which of these possibilities occurred:

    UT_OPEN_ARG
    path is non-NULL and was returned.
    UT_OPEN_ENV
    path is NULL, the environment variable UDUNITS2_XML_PATH is set, and its value was returned.
    UT_OPEN_DEFAULT
    path is NULL, the environment variable UDUNITS2_XML_PATH is unset, and the pathname of the default unit-database was returned.

    — Function: ut_system* ut_read_xml (const char* path)

    Reads the XML-formatted unit-database specified by path and returns the corresponding unit-sytem. If path is NULL, then the pathname specified by the environment variable UDUNITS2_XML_PATH is used if set; otherwise, the compile-time pathname of the installed, default, unit database is used. You should pass the returned pointer to ut_free_system() when you no longer need the unit-system. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return one of the following:

    UT_OPEN_ARG
    path is non-NULL but the file couldn't be opened. See errno for the reason.
    UT_OPEN_ENV
    path is NULL and environment variable UDUNITS2_XML_PATH is set but the file couldn't be opened. See errno for the reason.
    UT_OPEN_DEFAULT
    path is NULL, environment variable UDUNITS2_XML_PATH is unset, and the installed, default, unit database couldn't be opened. See errno for the reason.
    UT_OS
    Operating-system error. See errno.
    UT_PARSE
    The database file couldn't be parsed.

    — Function: ut_system* ut_new_system (void)

    Creates and returns a new unit-system. On success, the unit-system will be empty except for the dimensionless unit one. You should pass the returned pointer to ut_free_system() when you no longer need the unit-system. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return the following:

    UT_OS
    Operating-system error. See errno.


    Next: , Previous: Obtaining, Up: Unit-Systems

    3.2 Extracting Units from a Unit-System

    NOTE\: This section covers low-level access to the indidual units of a unit-system. General parsing of arbitrary unit specifications is coverted in the section Parsing.

    A unit-system contains mappings from identifiers to units (and vice versa). Consequently, once you have a unit-system, you can easily obtain a unit for which you know the name or symbol using the function ut_get_unit_by_name() or ut_get_unit_by_symbol().

    — Function: ut_unit* ut_get_unit_by_name (const ut_system* system, const char* name)

    Returns the unit to which name maps from the unit-system referenced by system or NULL if no such unit exists. Name comparisons are case-insensitive. If this function returns NULL, then ut_get_status() will return one of the following:

    UT_SUCCESS
    name doesn't map to a unit of system.
    UT_BAD_ARG
    system or name is NULL.

    — Function: ut_unit* ut_get_unit_by_symbol (const ut_system* system, const char* symbol)

    Returns the unit to which symbol maps from the unit-system referenced by system or NULL if no such unit exists. Symbol comparisons are case-sensitive. If this function returns NULL, then ut_get_status() will return one of the following:

    UT_SUCCESS
    symbol doesn't map to a unit of system.
    UT_BAD_ARG
    system or symbol is NULL.

    — Function: ut_unit* ut_get_dimensionless_unit_one (const ut_system* system)

    Returns the dimensionless unit one of the unit-system referenced by system. While not necessary, the returned pointer may be passed to ut_free() when you no longer need the unit. If system is NULL, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return UT_BAD_ARG.


    Next: , Previous: Extracting, Up: Unit-Systems

    3.3 Adding Units to a Unit-System

    If you use ut_read_xml(), then you should not normally need to add any new units to a unit-system.

    Because you get units via their names or symbols, adding a unit to a unit-system actually means mapping one or more identifiers (i.e., names or symbols) to the unit. Thereafter, you can use ut_get_unit_by_name() and ut_get_unit_by_symbol() to retrieve the unit. The mapping of identifiers to units is covered here.

    Having said that, it is possible to create a new base or dimensionless unit within a unit-system using ut_new_base_unit() or ut_new_dimensionless_unit()—you'll just also have to map identifiers to the newly-created unit in order to be able to retrieve it later by identifier.

    — Function: ut_unit* ut_new_base_unit (ut_system* system)

    Creates and adds a new base-unit to the unit-system referenced by system. This function returns the new base-unit. You should pass the returned pointer to ut_free() when you no longer need the unit. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return one of the following:

    UT_BAD_ARG
    system is NULL.
    UT_OS
    Operating-system failure. See errno.
    If you use ut_read_xml(), then you should not normally need to call this function.

    — Function: ut_unit* ut_new_dimensionless_unit (ut_system* system)

    Creates and adds a new dimensionless-unit to the unit-system referenced by system. This function returns the new dimensionless-unit. You should pass the returned pointer to ut_free() when you no longer need the unit. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return one of the following:

    UT_BAD_ARG
    system is NULL.
    UT_OS
    Operating-system failure. See errno.
    If you use ut_read_xml(), then you should not normally need to call this function.


    Next: , Previous: Adding, Up: Unit-Systems

    3.4 Adding Unit-Prefixes to a Unit-System

    A prefix is a word or symbol that is appended to the beginning of a word or symbol that represents a unit in order to modify the value of that unit. For example, the prefix “kilo” in the word “kiloamperes” changes the value from one ampere to one-thousand amperes.

    If you use ut_read_xml(), then you should not normally need to add any new prefixes to a unit-system.

    — Function: ut_status ut_add_name_prefix (ut_system* system, const char* name, double value)

    Adds the name-prefix name with the value value to the unit-system system. A name-prefix is something like “mega” or “milli”. Comparisons between name-prefixes are case-insensitive. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    system or name is NULL, or value is 0.
    UT_EXISTS
    name already maps to a different value.
    UT_OS
    Operating-system failure. See errno.

    — Function: ut_status ut_add_symbol_prefix (ut_system* system, const char* symbol, double value)

    Adds the symbol-prefix symbol with the value value to the unit-system system. A symbol-prefix is something like “M” or “m”. Comparisons between symbol-prefixes are case-sensitive. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    system or symbol is NULL, or value is 0.
    UT_EXISTS
    symbol already maps to a different value.
    UT_OS
    Operating-system failure. See errno.


    Previous: Prefixes, Up: Unit-Systems

    3.5 Miscelaneous Operations on Unit-Systems

    — Function: void ut_free_system (ut_system* system)

    Frees the unit-system referenced by system. All unit-to-identifier and identifier-to-unit mappings are removed. Use of system after this function returns results in undefined behavior.

    — Function: ut_status ut_set_second (const ut_unit* second)

    Sets the “second” unit of a unit-system. This function must be called before the first call to ut_offset_by_time() for a unit in the same unit-system. ut_read_xml() calls this function if the unit-system it's reading contains a unit named “second”. This function returns one of the following:

    UT_SUCCESS
    The “second” unit of system was successfully set.
    UT_EXISTS
    The “second” unit of system is set to a different unit.
    UT_BAD_ARG
    second is NULL.


    Next: , Previous: Unit-Systems, Up: Top

    4 Converting Values Between Units

    You can convert numeric values in one unit to equivalent values in another, compatible unit by means of a converter. For example

         #include <udunits2.h>
         ...
             ut_unit*      from = ...;
             ut_unit*      to = ...;
             cv_converter* converter = ut_get_converter(from, to);
             double       fromValue = ...;
             double       toValue = cv_convert_double(converter, fromValue);
         
             cv_free(converter);
    

    The converter API is declared in the header-file <converter.h>, which is automatically included by the UDUNITS-2 header-file (<udunits2.h>) so you don't need to explicitly include it.

    — Function: int ut_are_convertible (const ut_unit* unit1, uconst t_unit* unit2)

    Indicates if numeric values in unit unit1 are convertible to numeric values in unit unit2 via ut_get_converter(). In making this determination, dimensionless units are ignored. This function returns a non-zero value if conversion is possible; otherwise, 0 is returned and ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit1 or unit2 is NULL.
    UT_NOT_SAME_SYSTEM
    unit1 and unit2 belong to different unit-systems.
    UT_SUCCESS
    Conversion between the units is not possible (e.g., unit1 refers to a meter and unit2 refers to a kilogram.

    — Function: cv_converter* ut_get_converter (ut_unit* const from, ut_unit* const to)

    Creates and returns a converter of numeric values in the from unit to equivalent values in the to unit. You should pass the returned pointer to cv_free() when you no longer need the converter. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return one of the following:

    UT_BAD_ARG
    from or to is NULL.
    UT_NOT_SAME_SYSTEM
    The units from and to don't belong to the same unit-system.
    UT_MEANINGLESS
    The units belong to the same unit-system but conversion between them is meaningless (e.g., conversion between seconds and kilograms is meaningless).
    UT_OS
    Operating-system failure. See errno.

    — Function: float cv_convert_float (const cv_converter* converter, const float value)

    Converts the single floating-point value value and returns the new value.

    — Function: double cv_convert_double (const cv_converter* converter, const double value)

    Converts the single double-precision value value and returns the new value.

    — Function: float* cv_convert_floats (const cv_converter* converter, const float* in, size_t count, float* out)

    Converts the count floating-point values starting at in, writing the new values starting at out and, as a convenience, returns out. The input and output arrays may overlap or be identical.

    — Function: double* cv_convert_doubles (const cv_converter* converter, const double* in, size_t count, double* out)

    Converts the count double-precision values starting at in, writing the new values starting at out and, as a convenience, returns out. The input and output arrays may overlap or be identical.

    — Function: void cv_free (cv_converter* conv);

    Frees resources associated with the converter referenced by conv. You should call this function when you no longer need the converter. Use of conv upon return results in undefined behavior.


    Next: , Previous: Value Conversion, Up: Top

    5 Parsing a String into a Unit

    Here's an example of parsing a string representation of a unit into its binary representation:

         #include <stdlib.h>
         #include <udunits2.h>
         ...
             ut_system*   unitSystem = ut_read_xml(NULL);
             const char* string = "kg.m2/s3";
             ut_unit*     watt = ut_parse(unitSystem, string, UT_ASCII);
         
             if (watt == NULL) {
                 /* Unable to parse string. */
             }
             else {
                 /* Life is good. */
             }
    

    — Function: ut_unit* ut_parse (const ut_system* system, const char* string, ut_encoding encoding)

    Returns the binary unit representation corresponding to the string unit representation string in the character-set encoding using the unit-system system. string must have no leading or trailing whitespace (see ut_trim()). If an error occurs, then this function returns NULL and ut_get_status() will return one of the following:

    UT_BAD_ARG
    system or string is NULL.
    UT_SYNTAX
    string contained a syntax error.
    UT_UNKNOWN
    string contained an unknown identifier.
    UT_OS
    Operating-system failure. See errno for the reason.

    — Function: size_t ut_trim (char* string, ut_encoding encoding)

    Removes all leading and trailing whitespace from the NUL-terminated string string. Returns string, which is modified if it contained leading or trailing whitespace.


    Next: , Previous: Parsing, Up: Top

    6 Unit Syntax

    For the most part, the UDUNITS-2 package follows the syntax for unit-strings promulgated by the US National Institute for Standards and Technology (NIST). Details, of which, can be found at http://physics.nist.gov/cuu/Units/index.html. The one general exception to this is the invention of a syntax for “offset”-units (e.g., the definition of the degree Celsius is “K @ 273.15”).


    Next: , Up: Syntax

    6.1 Unit Specification Examples

    String Type Using Names Using Symbols Comment
    Simple meter m
    Raised meter^2 m2 higher precedence than multiplying or dividing
    Product newton meter N.m
    Quotient meter per second m/s
    Scaled 60 second 60 s
    Prefixed kilometer km
    Offset kelvin from 273.15 K @ 273.15 lower precedence than multiplying or dividing
    Logarithmic lg(re milliwatt) lg(re mW) "lg" is base 10, "ln" is base e, and "lb" is base 2
    Grouped (5 meter)/(30 second) (5 m)/(30 s)

    The above may be combined, e.g., "0.1 lg(re m/(5 s)^2) @ 50".

    You may also look at the <def> elements in the units database to see examples of string unit specifications.

    You may use the udunits2 utility to experiment with string unit specifications.


    Previous: Examples, Up: Syntax

    6.2 Unit Grammar

    Here is the unit-syntax understood by the UDUNITS-2 package. Words printed Thusly indicate non-terminals; words printed THUSLY indicate terminals; and words printed <thusly> indicate lexical elements.

         Unit-Spec: one of
                 nothing
                 Shift-Spec
         
         Shift-Spec: one of
                 Product-Spec
                 Product-Spec SHIFT REAL
                 Product-Spec SHIFT INT
                 Product-Spec SHIFT Timestamp
         
         Product-Spec: one of
                 Power-Spec
                 Product-Spec Power-Spec
                 Product-Spec MULTIPLY Power-Spec
                 Product-Spec DIVIDE Power-Spec
         
         Power-Spec: one of
                 Basic-Spec
                 Basic-Spec INT
                 Basic-Spec EXPONENT
                 Basic-Spec RAISE INT
         
         Basic-Spec: one of
                 ID
                 "(" Shift-Spec ")"
                 LOGREF Product_Spec ")"
                 Number
         
         Number: one of
                 INT
                 REAL
         
         Timestamp: one of
                 DATE
                 DATE CLOCK
                 DATE CLOCK CLOCK
                 DATE CLOCK INT
                 DATE CLOCK ID
                 TIMESTAMP
                 TIMESTAMP INT
                 TIMESTAMP ID
         
         SHIFT:
                 <space>* <shift_op> <space>*
         
         <shift_op>: one of
                 "@"
                 "after"
                 "from"
                 "since"
                 "ref"
         
         REAL:
                 the usual floating-point format
         
         INT:
                 the usual integer format
         
         MULTIPLY: one of
                 "-"
                 "."
                 "*"
                 <space>+
                 <centered middot>
         
         DIVIDE:
                 <space>* <divide_op> <space>*
         
         <divide_op>: one of
                 per
                 PER
                 "/"
         
         EXPONENT:
                 ISO-8859-9 or UTF-8 encoded exponent characters
         
         RAISE: one of
                 "^"
                 "**"
         
         ID: one of
                 <id>
                 "%"
                 "'"
                 "\""
                 degree sign
                 greek mu character
         
         <id>:
                 <alpha> <alphanum>*
         
         <alpha>:
                 [A-Za-z_]
                 ISO-8859-1 alphabetic characters
                 non-breaking space
         
         <alphanum>: one of
                 <alpha>
                 <digit>
         
         <digit>:
                 [0-9]
         
         LOGREF:
                 <log> <space>* <logref>
         
         <log>: one of
                 "log"
                 "lg"
                 "ln"
                 "lb"
         
         <logref>:
                 "(" <space>* <re> ":"? <space>*
         
         DATE:
                 <year> "-" <month> ("-" <day>)?
         
         <year>:
                 [+-]?[0-9]{1,4}
         
         <month>:
                 "0"?[1-9]|1[0-2]
         
         <day>:
                 "0"?[1-9]|[1-2][0-9]|"30"|"31"
         
         CLOCK:
                 <hour> ":" <minute> (":" <second>)?
         
         TIMSTAMP:
                 <year> (<month> <day>?)? "T" <hour> (<minute> <second>?)?
         
         <hour>:
                 [+-]?[0-1]?[0-9]|2[0-3]
         
         <minute>:
                 [0-5]?[0-9]
         
         <second>:
                 (<minute>|60) (\.[0-9]*)?
         
    


    Next: , Previous: Syntax, Up: Top

    7 Formatting a Unit into a String

    Use the ut_format() function to obtain the string representation of a binary unit. For example, the following gets the definition of the unit "watt" in ASCII characters using unit-symbols rather than unit-names:

         ut_unit*     watt = ...;
         char        buf[128];
         unsigned    opts = UT_ASCII | UT_DEFINITION;
         int         len = ut_format(watt, buf, sizeof(buf), opts);
         
         if (len == -1) {
             /* Couldn't get string */
         }
         else if (len == sizeof(buf)) {
             /* Entire buffer used: no terminating NUL */
         }
         else {
             /* Have string with terminating NUL */
         }
    

    — Function: int ut_format (const ut_unit* unit, char* buf, size_t size, unsigned opts)

    Formats the unit unit (i.e., returns its string representation) into the buffer pointed-to by buf of size size. The argument opts specifies how the formatting is to be done and is a bitwise OR of a ut_encoding value and zero or more of the following:

    UT_NAMES
    Use unit names instead of symbols.
    UT_DEFINITION
    The formatted string should be the definition of unit in terms of basic-units instead of stopping any expansion at the highest level possible.

    On success, this function returns either the number of bytes – excluding the terminating NUL – that were written into buf or the number of bytes that would have been written. The difference is due to the runtime snprinf() function that was used.

    On failure, this function returns -1 and ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit or buf is NULL, or opts contains the bit patterns of both UT_LATIN1 and UT_UTF8.
    UT_CANT_FORMAT
    unit can't be formatted in the desired manner (e.g., opts contains UT_ASCII but unit doesn't have an identifier in that character-set or opts doesn't contain UT_NAMES and a necessary symbol doesn't exist).


    Next: , Previous: Formatting, Up: Top

    8 Unit Operations

    You can use unit operations to construct new units, get information about units, or compare units.


    Next: , Up: Operations

    8.1 Unary Unit Operations

    — Function: void ut_free (ut_unit* unit)

    Frees resources associated with unit. You should invoke this function on every unit that you no longer need. Use of unit upon return from this function results in undefined behavior.

    — Function: ut_unit* ut_scale (double factor, const ut_unit* unit)

    Returns a unit equivalent to another unit scaled by a numeric factor. For example:

              const ut_unit*   meter = ...
              const ut_unit*   kilometer = ut_scale(1000, meter);
    

    The returned unit is equivalent to unit multiplied by factor. You should pass the returned pointer to ut_free() when you no longer need the unit.

    — Function: ut_unit* ut_offset (const ut_unit* unit, double offset)

    Returns a unit equivalent to another unit relative to a particular origin. For example:

              const ut_unit*   kelvin = ...
              const ut_unit*   celsius = ut_offset(kelvin, 273.15);
    

    The returned unit is equivalent to unit with an origin of offset. You should pass the returned pointer to ut_free() when you no longer need the unit. If an error occurs, then this function returns NULL and ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit is NULL.
    UT_OS
    Operating-system error. See errno for the reason.

    — Function: ut_unit* ut_offset_by_time (const ut_unit* const unit, const double origin)

    Returns a timestamp-unit equivalent to the time unit unit referenced to the time-origin origin (as returned by ut_encode_time()). For example:

              const ut_unit*   second = ...
              const ut_unit*   secondsSinceTheEpoch =
                  ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0.0));
    

    Leap seconds are not taken into account. You should pass the returned pointer to ut_free() when you no longer need the unit. If an error occurs, then this function returns NULL and ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit is NULL.
    UT_OS
    Operating-system error. See errno for the reason.
    UT_MEANINGLESS
    Creation of a timestamp unit based on unit is not meaningful. It might not be a time-unit, for example.
    UT_NO_SECOND
    The associated unit-system doesn't contain a “second” unit. See ut_set_second().

    CAUTION: The timestamp-unit was created to be analogous to, for example, the degree celsius—but for the time dimension. I've come to believe, however, that creating such a unit was a mistake, primarily because users try to use the unit in ways for which it was not designed (such as converting dates in a calendar whose year is exactly 365 days long). Such activities are much better handled by a dedicated calendar package. Please be careful about using timestamp-units. See also the section on The Handling of Time.

    — Function: ut_unit* ut_invert (const ut_unit* unit)

    Returns the inverse (i.e., reciprocal) of the unit unit. This convenience function is equal to ut_raise(unit,-1). You should pass the returned pointer to ut_free() when you no longer need the unit. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit is NULL.
    UT_OS
    Operating-system error. See errno for the reason.

    — Function: ut_unit* ut_raise (const ut_unit* unit, int power)

    Returns the unit equal to unit unit raised to the power power. You should pass the returned pointer to ut_free() when you no longer need the unit. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit is NULL.
    UT_OS
    Operating-system error. See errno for the reason.

    — Function: ut_unit* ut_root (const ut_unit* unit, int root)

    Returns the unit equal to the root root of unit unit. You should pass the returned pointer to ut_free() when you no longer need the unit. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit is NULL.
    UT_MEANINGLESS
    It's meaningless to take the given root of the given unit. This could be because the resulting unit would have fractional (i.e., non-integral) dimensionality, or because the unit is, for example, a logarithmic unit.
    UT_OS
    Operating-system error. See errno for the reason.

    — Function: ut_unit* ut_log (double base, const ut_unit* reference)

    Returns the logarithmic unit corresponding to the logarithmic base base and a reference level specified as the unit reference. For example, the following creates a decibel unit with a one milliwatt reference level:

                   const ut_unit* milliWatt = ...;
                   const ut_unit* bel_1_mW = ut_log(10.0, milliWatt);
              
                   if (bel_1_mW != NULL) {
                       const ut_unit* decibel_1_mW = ut_scale(0.1, bel_1_mW);
              
                       ut_free(bel_1_mW);   /* no longer needed */
              
                       if (decibel_1_mW != NULL) {
                           /* Have decibel unit with 1 mW reference */
                           ...
                           ut_free(decibel_1_mW);
                       }                 /* "decibel_1_mW" allocated */
                   }
    

    You should pass the returned pointer to ut_free() when you no longer need the unit. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return one of the following:

    UT_BAD_ARG
    reference is NULL.
    UT_OS
    Operating-system error. See errno for the reason.
    UT_BAD_ARG
    base is invalid (e.g., it must be greater than one).

    — Function: const char* ut_get_name (const ut_unit* unit, ut_encoding encoding)

    Returns the name to which the unit referenced by unit maps in the character-encoding specified by encoding. If this function returns NULL, then ut_get_status() will return one of the following:

    UT_BAD_ARG
    name is NULL.
    UT_SUCCESS
    unit doesn't map to a name in the given character-set.

    — Function: const char* ut_get_symbol (const ut_unit* unit, ut_encoding encoding)

    Returns the symbol to which the unit referenced by unit maps in the character-encoding specified by encoding. If this function returns NULL, then ut_get_status() will return one of the following:

    UT_BAD_ARG
    symbol is NULL.
    UT_SUCCESS
    unit doesn't map to a symbol in the given character-set.

    — Function: ut_system* ut_get_system (const ut_unit* unit)

    Returns the unit-system to which the unit referenced by unit belongs. If unit is NULL, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return UT_BAD_ARG.

    — Function: int ut_is_dimensionless (const ut_unit* unit)

    Indicates if unit unit is dimensionless (like “radian”). This function returns a non-zero value if the unit is dimensionfull; otherwise, 0 is returned and ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit1 is NULL.
    UT_SUCCESS
    The unit is dimensionless.

    — Function: ut_unit* ut_clone (const ut_unit* unit)

    Returns a copy of the unit referenced by unit. You should pass the returned pointer to ut_free() when you no longer need the unit. If an error occurs, then this function writes an error-message using ut_handle_error_message() and returns NULL. Also, ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit is NULL.
    UT_OS
    Operating-system failure. See errno.
    If you use ut_read_xml(), then you should not normally need to call this function.

    — Function: ut_status ut_accept_visitor (const ut_unit* unit, const ut_visitor* visitor, void* arg)

    Accepts the visitor visitor to the unit unit. The argument arg is passed to the visitor's functions. This function returns one of the following:

    UT_BAD_ARG
    visitor or unit is NULL.
    UT_VISIT_ERROR
    An error occurred in visitor while visiting unit.
    UT_SUCCESS
    Success.

    — Data type: ut_visitor int foo(int) int bar(int, int)

    You pass a pointer to a data object of this type if and when you call ut_accept_visitor(). It contains the following pointers to functions that implement your unit-visitor:

    ut_status (*visit_basic)(const ut_unit* unit, void* arg);
    Visits the basic-unit unit. A basic-unit is a base unit like “meter” or a non-dimensional but named unit like “radian”. This function returns UT_SUCCESS on and only on success.
    ut_status (*visit_product)(const ut_unit* unit, int count, const ut_unit* const* basicUnits, const int* powers, void* arg);
    Visits the product-unit unit. The product-unit is a product of the count basic-units referenced by basicUnits, each raised to their respective, non-zero power in powers. This function returns UT_SUCCESS on and only on success.
    ut_status (*visit_galilean)(const ut_unit* unit, double scale, const ut_unit* underlyingUnit, double origin, void* arg);
    Visits the Galilean-unit unit. The Galilean-unit has the underlying unit underlyingUnit and either the non-unity scale factor scale or the non-zero origin origin, or both. This function returns UT_SUCCESS on and only on success.
    ut_status (*visit_timestamp)(const ut_unit* unit, const ut_unit* timeUnit, double origin, void* arg);
    Visits the timestamp-unit unit. The timestamp-unit has the underlying unit of time timeUnit and the ut_encode_time()-encoded time-origin origin. This function returns UT_SUCCESS on and only on success.
    ut_status (*visit_logarithmic)(const ut_unit* unit, double base, const ut_unit* reference, void* arg);
    Visits the logarithmic-unit unit. The logarithmic-unit has the logarithmic base base and the reference-level is specified by the unit reference. This function returns UT_SUCCESS on and only on success.


    Previous: Unary, Up: Operations

    8.2 Binary Unit Operations

    Binary unit operations act on two units.

    NOTE\: The functions ut_are_convertible() and ut_get_converter() are also binary unit operations but are documented elsewhere.

    — Function: ut_unit* ut_multiply (const ut_unit* unit1, const ut_unit* unit2)

    Returns the result of multiplying unit unit1 by unit unit2. You should pass the pointer to ut_free() when you no longer need the unit On failure, this function returns NULL and ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit1 or unit2 is NULL.
    UT_NOT_SAME_SYSTEM
    unit1 and unit2 belong to different unit-systems.
    UT_OS
    Operating-system error. See errno for the reason.

    — Function: ut_unit* ut_divide (const ut_unit* numer, const ut_unit* denom)

    Returns the result of dividing unit numer by unit denom. You should pass the pointer to ut_free() when you no longer need the unit On failure, this function returns NULL and ut_get_status() will return one of the following:

    UT_BAD_ARG
    numer or denom is NULL.
    UT_NOT_SAME_SYSTEM
    unit1 and unit2 belong to different unit-systems.
    UT_OS
    Operating-system error. See errno for the reason.

    — Function: int ut_compare (const ut_unit* unit1, const ut_unit* unit2)

    Compares two units. Returns a value less than, equal to, or greater than zero as unit1 is considered less than, equal to, or greater than unit2, respectively. Units from different unit-systems never compare equal. The value zero is also returned if both unit pointers are NULL.

    — Function: int ut_same_system (const ut_unit* unit1, const ut_unit* unit2)

    Indicates if two units belong to the same unit-system. This function returns a non-zero value if the two units belong to the same unit-system; otherwise, 0 is returned and ut_get_status() will return one of the following:

    UT_BAD_ARG
    unit1 or unit2 is NULL.
    UT_SUCCESS
    The units belong to different unit-systems.


    Next: , Previous: Operations, Up: Top

    9 Mapping Between Identifiers and Units

    Within a unit-system, you can map an identifier to a unit and vice versa. If an identifier maps to a unit, then the unit can be retrieved from the unit-system via the identifier. Similarly, if a unit maps to an identifier, then the unit can be printed using the identifier.

    There a two kinds of identifiers: names and symbols.


    Next: , Up: Mapping

    9.1 Names

    You can map a name to a unit and vice versa. If you use ut_read_xml(), then you shouldn't normally need to do this.

    — Function: ut_status ut_map_name_to_unit (const char* name, const ut_encoding encoding, const ut_unit* unit)

    Maps the name referenced by name, in character-set encoding, to the unit referenced by unit in the unit-system that contains unit. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    name or unit is NULL.
    UT_OS
    Operating-system failure. See errno.
    UT_EXISTS
    name already maps to a different unit.

    — Function: ut_status ut_unmap_name_to_unit (ut_system* system, const char* name, const ut_encoding encoding)

    Removes any mapping from name name, in character-set encoding, to a unit in unit-system system. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    system or name is NULL.

    — Function: ut_status ut_map_unit_to_name (const ut_unit* unit, const char* name, ut_encoding encoding)

    Maps the unit unit to the name name, which is in character-set encoding, in the unit-system that contains the unit. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    unit or name is NULL, or name is not in the character-set encoding.
    UT_OS
    Operating-system failure. See errno.
    UT_EXISTS
    unit already maps to a different name.

    — Function: ut_status ut_unmap_unit_to_name (const ut_unit* unit, ut_encoding encoding)

    Removes any mapping from unit unit to a name in character-set encoding from the unit-system that contains the unit. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    unit is NULL.


    Previous: Names, Up: Mapping

    9.2 Symbols

    You can map a symbol to a unit and vice versa. If you use ut_read_xml(), then you shouldn't normally need to do this.

    — Function: ut_status ut_map_symbol_to_unit (const char* symbol, const ut_encoding encoding, const ut_unit* unit)

    Maps the symbol referenced by symbol, in character-set encoding, to the unit referenced by unit in the unit-system that contains unit. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    symbol or unit is NULL.
    UT_OS
    Operating-system failure. See errno.
    UT_EXISTS
    symbol already maps to a different unit.

    — Function: ut_status ut_unmap_symbol_to_unit (ut_system* system, const char* symbol, const ut_encoding encoding)

    Removes any mapping from symbol symbol, in character-set encoding, to a unit in unit-system system. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    system or symbol is NULL.

    — Function: ut_status ut_map_unit_to_symbol (const ut_unit* unit, const char* symbol, ut_encoding encoding)

    Maps the unit unit to the symbol symbol, which is in character-set encoding, in the unit-system that contains the unit. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    unit or symbol is NULL.
    UT_BAD_ARG
    Symbol symbol is not in the character-set encoding.
    UT_OS
    Operating-system failure. See errno.
    UT_EXISTS
    unit already maps to a different symbol.

    — Function: ut_status ut_unmap_unit_to_symbol (const ut_unit* unit, ut_encoding encoding)

    Removes any mapping from unit unit to a symbol in character-set encoding from the unit-system that contains the unit. This function returns one of the following:

    UT_SUCCESS
    Success.
    UT_BAD_ARG
    unit is NULL.


    Next: , Previous: Mapping, Up: Top

    10 The Handling of Time

    You should use a true calendar package rather than the UDUNITS-2 package to handle time. Having said that, many people use the time-handling capabilities of the UDUNITS-2 package because it supports "units" like "seconds since 1970-01-01". You should be aware, however, that the hybrid Gregorian/Julian calendar used by the UDUNITS-2 package cannot be changed. Dates on or after 1582-10-15 are assumed to be Gregorian dates; dates before that are assumed to be Julian dates. In particular, the year 1 BCE is immediately followed by the year 1 CE.

    In general, the UDUNITS-2 package handles time by encoding it as double-precision value, which can then be acted upon arithmetically.

    — Function: double ut_encode_time (int year, int month, int day, int hour, int minute, double second)

    Encodes a time as a double-precision value. This convenience function is equivalent to

              ut_encode_date(year,month,day) + ut_encode_clock(hour,minute,second)
    

    — Function: double ut_encode_date (int year, int month, int day)

    Encodes a date as a double-precision value. You probably won't use this function. Dates on or after 1582-10-15 are assumed to be Gregorian dates; dates before that are assumed to be Julian dates. In particular, the year 1 BCE is immediately followed by the year 1 CE.

    — Function: double ut_encode_clock (int hour, int minute, double second)

    Encodes a clock-time as a double-precision value. You probably won't use this function.

    — Function: void ut_decode_time (double time, int* year, int* month, int* day, int* hour, int* minute, double* second, double* resolution)

    Decodes a time from a double-precision value into its individual components. The variable referenced by resolution will be set to the resolution (i.e., uncertainty) of the time in seconds.


    Next: , Previous: Time, Up: Top

    11 Error Handling

    Error-handling in the units module has two aspects: the status of the last operation performed by the module and the handling of error-messages:


    Next: , Up: Errors

    11.1 Status of Last Operation

    UDUNITS-2 functions set their status by calling ut_set_status(). You can use the function ut_get_status() to retrieve that status.

    — Function: ut_status ut_get_status (void)

    Returns the value specified in the last call to ut_set_status()

    — Function: void ut_set_status (ut_status status)

    Set the status of the units module to status.

    — Data type: ut_status

    This enumeration has the following values:

    UT_SUCCESS
    Success
    UT_BAD_ARG
    An argument violates the the function's contract (e.g., it's NULL).
    UT_EXISTS
    Unit, prefix, or identifier already exists
    UT_NO_UNIT
    No such unit exists
    UT_OS
    Operating-system error. See errno for the reason.
    UT_NOT_SAME_SYSTEM
    The units belong to different unit-systems
    UT_MEANINGLESS
    The operation on the unit or units is meaningless
    UT_NO_SECOND
    The unit-system doesn't have a unit named “second”
    UT_VISIT_ERROR
    An error occurred while visiting a unit
    UT_CANT_FORMAT
    A unit can't be formatted in the desired manner
    UT_SYNTAX
    String unit representation contains syntax error
    UT_UNKNOWN
    String unit representation contains unknown word
    UT_OPEN_ARG
    Can't open argument-specified unit database
    UT_OPEN_ENV
    Can't open environment-specified unit database
    UT_OPEN_DEFAULT
    Can't open installed, default, unit database
    UT_PARSE
    Error parsing unit database


    Previous: Status, Up: Errors

    11.2 Error-Messages

    — Function: int ut_handle_error_message (const char* fmt, ...)

    Handles the error-message corresponding to the format-string fmt and any subsequent arguments referenced by it. The interpretation of the formatting-string is identical to that of the UNIX function printf(). On success, this function returns the number of bytes in the error-message; otherwise, this function returns -1.

    Use the function ut_set_error_message_handler() to change how error-messages are handled.

    — Function: ut_error_message_handler ut_set_error_message_handler (ut_error_message_handler handler)

    Sets the function that handles error-messages and returns the previous error-message handler. The initial error-message handler is ut_write_to_stderr().

    — Function: int ut_write_to_stderr (const char* fmt, va_list args)

    Writes the variadic error-message corresponding to formatting-string fmt and arguments args to the standard-error stream and appends a newline. The interpretation of the formatting-string is identical to that of the UNIX function printf(). On success, this function returns the number of bytes in the error-message; otherwise, this function returns -1.

    — Function: int ut_ignore (const char* fmt, va_list args)

    Does nothing. In particular, it ignores the variadic error-message corresponding to formatting-string fmt and arguments args. Pass this function to ut_set_error_message_handler() when you don't want the unit module to print any error-messages.

    — Data type: ut_error_message_handler

    This is the type of an error-message handler. It's definition is

              typedef int (*ut_error_message_handler)(const char* fmt, va_list args);
    


    Next: , Previous: Errors, Up: Top

    12 The Units Database

    The database of units that comes with the UDUNITS-2 package is an XML-formatted file that is based on the SI system of units. It contains the names and symbols of most of the units that you will ever encounter. The pathname of the installed file is datadir/udunits2.xml, where datadir is the installation-directory for read-only, architecture-independent data (e.g., /usr/local/share). This pathname is the default that ut_read_xml() uses.

    Naturally, because the database is a regular file, it can be edited to add new units or remove existing ones. Be very careful about doing this, however, because you might lose the benefit of exchanging unit-based information with others who haven't modified their database.


    Next: , Previous: Database, Up: Top

    13 Data Types

    The data types ut_visitor, ut_status, and ut_error_message_handler are documented elsewhere.

    — Data type: ut_encoding

    This enumeration has the following values:

    UT_ASCII
    US ASCII character-set.
    UT_ISO_8859_1
    The ISO-8859-1 character-set.
    UT_LATIN1
    Synonym for UT_ISO_8859_1.
    UT_UTF8
    The UTF-8 encoding of the Unicode character-set.


    Previous: Types, Up: Top

    Index

    udunits-2.2.0/lib/.exrc0000644000175000017500000000014712260406756016062 0ustar amckinstryamckinstryset nonu aw sm sw=4 nobf ts=8 expandtab ai terse ic ws wm=0 redraw set para=IPLPPPQPTPP\ LIpplpipnpbp' udunits-2.2.0/lib/udunits2lib.texi0000644000175000017500000017532212260406756020267 0ustar amckinstryamckinstry\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename udunits2lib.info @settitle The UDUNITS-2 C API Guide @c %**end of header @dircategory Software libraries @direntry * UDUNITS-2: (udunits2lib). The Unidata units library. @end direntry @syncodeindex fn cp @syncodeindex tp cp @copying @include COPYRIGHT @end copying @titlepage @title The UDUNITS-2 C API @author Steven R. Emmerson @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top, Synopsis, (dir), (dir) @top UDUNITS-2 This manual describes how to use the C API of the UDUNITS-2 library. Among other things, the library allows C code to obtain a binary representation of a unit of a physical quantity, to operate on such units, and to convert numeric values between compatible units. The library comes with an extensive database of units all referenced to the SI system of units. @insertcopying @end ifnottex @menu * Synopsis:: Terse usage display * Why:: What's a unit package good for? * Unit-Systems:: Explanation of unit-systems and how to get one * Parsing:: Converting strings into units * Syntax:: Syntax for string representation of units * Formatting:: Converting units into strings * Value Conversion:: Converting values between units * Prefixes:: Defining unit prefixes * Mapping:: Mapping between units and identifiers * Operations:: Operations on units * Time:: Handling time * Errors:: Error-handling * Database:: The units database * Types:: Data types * Complete Index:: Complete index @end menu @node Synopsis, Why, Top, Top @chapter Synopsis @cindex synopsis Coding: @example #include @quotation @multitable {ut_error_message_handler} {ut_get_dimensionless_unit_one(} @item ut_system* @tab ut_get_path_xml(const char* @var{path}); @item ut_system* @tab ut_read_xml(const char* @var{path}); @item ut_system* @tab ut_new_system(void); @item void @tab ut_free_system(ut_system* @var{system}); @item ut_system* @tab ut_get_system(const ut_unit* @var{unit}); @item ut_unit* @tab ut_get_dimensionless_unit_one(const ut_system* @var{system}); @item ut_unit* @tab ut_get_unit_by_name(const ut_system* @var{system}, const char* @var{name}); @item ut_unit* @tab ut_get_unit_by_symbol(const ut_system* @var{system}, const char* @var{symbol}); @item ut_status @tab ut_set_second(const ut_unit* @var{second}); @item ut_status @tab ut_add_name_prefix(ut_system* @var{system}, const char* @var{name}, double @var{value}); @item ut_status @tab ut_add_symbol_prefix(ut_system* @var{system}, const char* @var{symbol}, double @var{value}); @item ut_unit* @tab ut_new_base_unit(ut_system* @var{system}); @item ut_unit* @tab ut_new_dimensionless_unit(ut_system* @var{system}); @item ut_unit* @tab ut_clone(const ut_unit* @var{unit}); @item void @tab ut_free(ut_unit* @var{unit}); @item const char* @tab ut_get_name(const ut_unit* @var{unit}, ut_encoding @var{encoding}); @item ut_status @tab ut_map_name_to_unit(const char* @var{name}, const ut_encoding @var{encoding}, const ut_unit* @var{unit}); @item ut_status @tab ut_unmap_name_to_unit(ut_system* @var{system}, const char* @var{name}, const ut_encoding @var{encoding}); @item ut_status @tab ut_map_unit_to_name(const ut_unit* @var{unit}, const char* @var{name}, ut_encoding @var{encoding}); @item ut_status @tab ut_unmap_unit_to_name(const ut_unit* @var{unit}, ut_encoding @var{encoding}); @item const char* @tab ut_get_symbol(const ut_unit* @var{unit}, ut_encoding @var{encoding}); @item ut_status @tab ut_map_symbol_to_unit(const char* @var{symbol}, const ut_encoding @var{encoding}, const ut_unit* @var{unit}); @item ut_status @tab ut_unmap_symbol_to_unit(ut_system* @var{system}, const char* @var{symbol}, const ut_encoding @var{encoding}); @item ut_status @tab ut_map_unit_to_symbol(const ut_unit* @var{unit}, const char* @var{symbol}, ut_encoding @var{encoding}); @item ut_status @tab ut_unmap_unit_to_symbol(const ut_unit* @var{unit}, ut_encoding @var{encoding}); @item int @tab ut_is_dimensionless(const ut_unit* @var{unit}); @item int @tab ut_same_system(const ut_unit* @var{unit1}, const ut_unit* @var{unit2}); @item int @tab ut_compare(const ut_unit* @var{unit1}, const ut_unit* @var{unit2}); @item int @tab ut_are_convertible(const ut_unit* @var{unit1}, const ut_unit* @var{unit2}); @item cv_converter* @tab ut_get_converter(ut_unit* @var{from}, ut_unit* @var{to}); @item ut_unit* @tab ut_scale(double @var{factor}, const ut_unit* @var{unit}); @item ut_unit* @tab ut_offset(const ut_unit* @var{unit}, double @var{offset}); @item ut_unit* @tab ut_offset_by_time(const ut_unit* @var{unit}, double @var{origin}); @item ut_unit* @tab ut_multiply(const ut_unit* @var{unit1}, const ut_unit* @var{unit2}); @item ut_unit* @tab ut_invert(const ut_unit* @var{unit}); @item ut_unit* @tab ut_divide(const ut_unit* @var{numer}, const ut_unit* @var{denom}); @item ut_unit* @tab ut_raise(const ut_unit* @var{unit}, int @var{power}); @item ut_unit* @tab ut_root(const ut_unit* @var{unit}, int @var{root}); @item ut_unit* @tab ut_log(double @var{base}, const ut_unit* @var{reference}); @item ut_unit* @tab ut_parse(const ut_system* @var{system}, const char* @var{string}, ut_encoding @var{encoding}); @item char* @tab ut_trim(char* @var{string}, ut_encoding @var{encoding}); @item int @tab ut_format(const ut_unit* @var{unit}, char* @var{buf}, size_t @var{size}, unsigned @var{opts}); @item ut_status @tab ut_accept_visitor(const ut_unit* @var{unit}, const ut_visitor* @var{visitor}, void* @var{arg}); @item double @tab ut_encode_date(int @var{year}, int @var{month}, int @var{day}); @item double @tab ut_encode_clock(int @var{hours}, int @var{minutes}, double @var{seconds}); @item double @tab ut_encode_time(int @var{year}, int @var{month}, int @var{day}, int @var{hour}, int @var{minute}, double @var{second}); @item void @tab ut_decode_time(double @var{value}, int* @var{year}, int* @var{month}, int* @var{day}, int* @var{hour}, int* @var{minute}, double* @var{second}, double* @var{resolution}); @item ut_status @tab ut_get_status(void); @item void @tab ut_set_status(ut_status @var{status}); @item int @tab ut_handle_error_message(const char* @var{fmt}, ...); @item ut_error_message_handler@tab ut_set_error_message_handler(ut_error_message_handler @var{handler}); @item int @tab ut_write_to_stderr(const char* @var{fmt}, va_list @var{args}); @item int @tab ut_ignore(const char* @var{fmt}, va_list @var{args}); @item @item float @tab cv_convert_float(const cv_converter* @var{converter}, float @var{value}); @item double @tab cv_convert_double(const cv_converter* @var{converter}, double @var{value}); @item float* @tab cv_convert_floats(const cv_converter* @var{converter}, const float* @var{in}, size_t @var{count}, float* @var{out}); @item double* @tab cv_convert_doubles(const cv_converter* @var{converter}, const double* @var{const} in, @var{size_t} count, @var{double}* out); @item void @tab cv_free(cv_converter* @var{conv}); @end multitable @end quotation @end example Compiling: @example c89 -I @emph{includedir} ... @end example Where @emph{includedir} is the installation-directory for C header files (e.g., @code{/usr/local/include}). Linking: @example c89 ... -L@emph{libdir} -ludunits2 -lexpat ... -lm @end example Where @emph{libdir} is the installation-directory for object code libraries (e.g., @code{/usr/local/lib}). @node Why, Unit-Systems, Synopsis, Top @chapter What's a Unit Package Good For? The existance of a software package is justified by what you can do with it. The three main things you can do with the UDUNIT-2 package are @enumerate @item @ref{Value Conversion, Convert numeric values between compatible units}. @item Convert a string representation of a unit into a binary one --- enabling the programatic manipulation of units. There are three ways to do this: @itemize @item @ref{Extracting,Get the unit} from a @ref{unit-system}. This requires that you know the unit's name or symbol and that the unit is in a unit-system. @item @ref{Parsing,Parse a string representation of the unit into its binary representation}. This requires that the string be parsable by @code{@ref{ut_parse()}}. @item @ref{Operations,Explicity construct the unit from subcomponent units using unit operations}. @end itemize @item @ref{Formatting,Convert a binary representation of a unit into a string} --- enabling the printing and storing of units in a human-readable form. @end enumerate While the above might seem to be trivial activities, their general availability at the time might have helped prevent the @uref{http://en.wikipedia.org/wiki/Mars_Climate_Orbiter, Mars Climate Orbiter} fiasco. @anchor{unit-system} @node Unit-Systems, Value Conversion, Why, Top @chapter Unit-Systems @cindex unit-system @cindex system of units A unit-system is a set of units that are all defined in terms of the same set of @cindex unit, base @cindex base unit base units. In the SI system of units, for example, the base units are the meter, kilogram, second, ampere, kelvin, mole, and candela. (For definitions of these base units, see @uref{http://@/physics.nist.gov/@/cuu/@/Units/@/current.html}.) In the UDUNITS-2 package, every accessible unit belongs to one and only one unit-system. It is not possible to convert numeric values between units of different unit-systems. Similarly, units belonging to different unit-systems always compare unequal. There are several categories of operations on unit-systems: @menu * Obtaining:: How to obtain a unit-system. * Extracting:: Getting a unit from a unit-system. * Adding:: Adding new units to a unit-system. * Prefixes:: Add new unit-prefixes to a unit-system. * Misc:: Miscelaneous unit-system operations. @end menu @node Obtaining, Extracting, , Unit-Systems @section Obtaining a Unit-System @cindex database, unit, obtaining predefined @cindex unit database, obtaining predefined @cindex unit-system, obtaining predefined @cindex units, obtaining predefined @cindex @code{ut_read_xml()}, discussion of Typically, you would obtain a unit-system of predefined units by reading the default unit database using @code{@ref{ut_read_xml()}} with a @code{NULL} pathname argument. If this doesn't quite match your needs, then there are alternatives. Together with the typical solution, the means for obtaining a useful unit-system are (in order of increasing complexity): @itemize @bullet @item Obtain the default unit-system using @code{@ref{ut_read_xml(),ut_read_xml}(NULL)}. @item Copy and customize the unit database and then call @code{@ref{ut_read_xml()}} with the pathname of the customized database to obtain a customized unit-system. @item Same as either of the above but then adding new units to the unit-system using @code{@ref{ut_new_base_unit()}} and @code{@ref{ut_new_dimensionless_unit()}}. @item Same as the above but also deriving new units using @ref{Operations, unit operations} and then adding them to the unit-system using @ref{Mapping, unit mapping}. @item Same as the above but starting with an empty unit-system obtained from @code{@ref{ut_new_system()}}, in which case you will definitely have to start with @code{@ref{ut_new_base_unit()}} and @code{@ref{ut_new_dimensionless_unit()}}. @end itemize You should pass every unit-system pointer to @code{@ref{ut_free_system()}} when you no longer need the corresponding unit-system. @anchor{ut_get_path_xml()} @deftypefun @code{const char*} ut_get_path_xml @code{(const char* @var{path}, ut_status* status)} Returns the pathname of the XML-formatted unit-database corresponding to @var{path}. If @var{path} is non-@code{NULL}, then it is returned; otherwise, if the environment variable @code{UDUNITS2_XML_PATH} is set, then its value is returned; otherwise, the pathname of the default unit-database is returned. The value of @code{*status} indicates which of these possibilities occurred: @table @code @item UT_OPEN_ARG @var{path} is non-@code{NULL} and was returned. @item UT_OPEN_ENV @var{path} is @code{NULL}, the environment variable @code{UDUNITS2_XML_PATH} is set, and its value was returned. @item UT_OPEN_DEFAULT @var{path} is @code{NULL}, the environment variable @code{UDUNITS2_XML_PATH} is unset, and the pathname of the default unit-database was returned. @end table @end deftypefun @anchor{ut_read_xml()} @deftypefun @code{ut_system*} ut_read_xml @code{(const char* @var{path})} Reads the XML-formatted unit-database specified by @var{path} and returns the corresponding unit-sytem. If @var{path} is @code{NULL}, then the pathname specified by the environment variable @code{UDUNITS2_XML_PATH} is used if set; otherwise, the compile-time pathname of the installed, default, unit database is used. You should pass the returned pointer to @code{ut_free_system()} when you no longer need the unit-system. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_OPEN_ARG @var{path} is non-@code{NULL} but the file couldn't be opened. See @code{errno} for the reason. @item UT_OPEN_ENV @var{path} is @code{NULL} and environment variable @code{UDUNITS2_XML_PATH} is set but the file couldn't be opened. See @code{errno} for the reason. @item UT_OPEN_DEFAULT @var{path} is @code{NULL}, environment variable @code{UDUNITS2_XML_PATH} is unset, and the installed, default, unit database couldn't be opened. See @code{errno} for the reason. @item UT_OS Operating-system error. See @code{errno}. @item UT_PARSE The database file couldn't be parsed. @end table @end deftypefun @anchor{ut_new_system()} @deftypefun @code{ut_system*} ut_new_system @code{(void)} Creates and returns a new unit-system. On success, the unit-system will be empty except for the dimensionless unit one. You should pass the returned pointer to @code{ut_free_system()} when you no longer need the unit-system. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return the following: @table @code @item UT_OS Operating-system error. See @code{errno}. @end table @end deftypefun @node Extracting, Adding, Obtaining, Unit-Systems @section Extracting Units from a Unit-System @strong{NOTE\:} This section covers low-level access to the indidual units of a @ref{unit-system}. General parsing of arbitrary unit specifications is coverted in the section @ref{Parsing}. A @ref{unit-system} contains mappings from identifiers to units (and vice versa). Consequently, once you have a unit-system, you can easily obtain a unit for which you know the name or symbol using the function @code{@ref{ut_get_unit_by_name()}} or @code{@ref{ut_get_unit_by_symbol()}}. @cindex getting a unit by its name @cindex unit, getting by name @anchor{ut_get_unit_by_name()} @deftypefun @code{ut_unit*} ut_get_unit_by_name @code{(const ut_system* @var{system}, const char* @var{name})} Returns the unit to which @var{name} maps from the unit-system referenced by @var{system} or @code{NULL} if no such unit exists. Name comparisons are case-insensitive. If this function returns @code{NULL}, then @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_SUCCESS @var{name} doesn't map to a unit of @var{system}. @item UT_BAD_ARG @var{system} or @var{name} is @code{NULL}. @end table @end deftypefun @cindex getting a unit by its symbol @cindex unit, getting by symbol @anchor{ut_get_unit_by_symbol()} @deftypefun @code{ut_unit*} ut_get_unit_by_symbol @code{(const ut_system* @var{system}, const char* @var{symbol})} Returns the unit to which @var{symbol} maps from the unit-system referenced by @var{system} or @code{NULL} if no such unit exists. Symbol comparisons are case-sensitive. If this function returns @code{NULL}, then @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_SUCCESS @var{symbol} doesn't map to a unit of @var{system}. @item UT_BAD_ARG @var{system} or @var{symbol} is @code{NULL}. @end table @end deftypefun @anchor{ut_get_dimensionless_unit_one()} @deftypefun @code{ut_unit*} ut_get_dimensionless_unit_one @code{(const ut_system* @var{system})} Returns the dimensionless unit one of the unit-system referenced by @var{system}. While not necessary, the returned pointer may be passed to @code{ut_free()} when you no longer need the unit. If @var{system} is @code{NULL}, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return @code{UT_BAD_ARG}. @end deftypefun @node Adding, Prefixes, Extracting, Unit-Systems @section Adding Units to a Unit-System @cindex adding units to a unit-system @cindex unit, adding to a unit-system @cindex unit-system, adding a unit to If you use @code{@ref{ut_read_xml()}}, then you should not normally need to add any new units to a unit-system. Because you get units via their names or symbols, adding a unit to a unit-system actually means mapping one or more identifiers (i.e., names or symbols) to the unit. Thereafter, you can use @code{@ref{ut_get_unit_by_name()}} and @code{@ref{ut_get_unit_by_symbol()}} to retrieve the unit. The mapping of identifiers to units is covered @ref{Mapping,here}. Having said that, it is possible to create a new base or dimensionless unit within a unit-system using @code{@ref{ut_new_base_unit()}} or @code{@ref{ut_new_dimensionless_unit()}}---you'll just also have to map identifiers to the newly-created unit in order to be able to retrieve it later by identifier. @anchor{ut_new_base_unit()} @deftypefun @code{ut_unit*} ut_new_base_unit @code{(ut_system* @var{system})} Creates and adds a new base-unit to the unit-system referenced by @var{system}. This function returns the new base-unit. You should pass the returned pointer to @code{ut_free()} when you no longer need the unit. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{system} is @code{NULL}. @item UT_OS Operating-system failure. See @code{errno}. @end table If you use @code{@ref{ut_read_xml()}}, then you should not normally need to call this function. @end deftypefun @anchor{ut_new_dimensionless_unit()} @deftypefun @code{ut_unit*} ut_new_dimensionless_unit @code{(ut_system* @var{system})} Creates and adds a new dimensionless-unit to the unit-system referenced by @var{system}. This function returns the new dimensionless-unit. You should pass the returned pointer to @code{ut_free()} when you no longer need the unit. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{system} is @code{NULL}. @item UT_OS Operating-system failure. See @code{errno}. @end table If you use @code{@ref{ut_read_xml()}}, then you should not normally need to call this function. @end deftypefun @node Prefixes, Misc, Adding, Unit-Systems @section Adding Unit-Prefixes to a Unit-System @cindex prefixes, adding to a unit-system @cindex adding prefixes to a unit-system @cindex unit-system, adding prefixes to a A prefix is a word or symbol that is appended to the beginning of a word or symbol that represents a unit in order to modify the value of that unit. For example, the prefix ``kilo'' in the word ``kiloamperes'' changes the value from one ampere to one-thousand amperes. If you use @code{@ref{ut_read_xml()}}, then you should not normally need to add any new prefixes to a unit-system. @anchor{ut_add_name_prefix()} @deftypefun @code{@ref{ut_status}} ut_add_name_prefix @code{(ut_system* @var{system}, const char* @var{name}, double @var{value})} Adds the name-prefix @var{name} with the value @var{value} to the unit-system @var{system}. A name-prefix is something like ``mega'' or ``milli''. Comparisons between name-prefixes are case-insensitive. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{system} or @var{name} is @code{NULL}, or @var{value} is @code{0}. @item UT_EXISTS @var{name} already maps to a different value. @item UT_OS Operating-system failure. See @code{errno}. @end table @end deftypefun @anchor{ut_add_symbol_prefix()} @deftypefun @code{@ref{ut_status}} ut_add_symbol_prefix @code{(ut_system* @var{system}, const char* @var{symbol}, double @var{value})} Adds the symbol-prefix @var{symbol} with the value @var{value} to the unit-system @var{system}. A symbol-prefix is something like ``M'' or ``m''. Comparisons between symbol-prefixes are case-sensitive. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{system} or @var{symbol} is @code{NULL}, or @var{value} is @code{0}. @item UT_EXISTS @var{symbol} already maps to a different value. @item UT_OS Operating-system failure. See @code{errno}. @end table @end deftypefun @node Misc, , Prefixes, Unit-Systems @section Miscelaneous Operations on Unit-Systems @anchor{ut_free_system()} @deftypefun @code{void} ut_free_system @code{(ut_system* @var{system})} Frees the unit-system referenced by @var{system}. All unit-to-identifier and identifier-to-unit mappings are removed. Use of @code{system} after this function returns results in undefined behavior. @end deftypefun @anchor{ut_set_second()} @deftypefun @code{@ref{ut_status}} ut_set_second @code{(const ut_unit* @var{second})} Sets the ``second'' unit of a unit-system. This function must be called before the first call to @code{ut_offset_by_time()} for a unit in the same unit-system. @code{@ref{ut_read_xml()}} calls this function if the unit-system it's reading contains a unit named ``second''. This function returns one of the following: @table @code @item UT_SUCCESS The ``second'' unit of @var{system} was successfully set. @item UT_EXISTS The ``second'' unit of @var{system} is set to a different unit. @item UT_BAD_ARG @var{second} is @code{NULL}. @end table @end deftypefun @node Value Conversion, Parsing, Unit-Systems, Top @chapter Converting Values Between Units @cindex converting values between units @cindex unit conversion You can convert numeric values in one unit to equivalent values in another, compatible unit by means of a converter. For example @example #include ... ut_unit* from = ...; ut_unit* to = ...; cv_converter* converter = ut_get_converter(from, to); double fromValue = ...; double toValue = cv_convert_double(converter, fromValue); cv_free(converter); @end example The converter API is declared in the header-file @code{}, which is automatically included by the UDUNITS-2 header-file (@code{}) so you don't need to explicitly include it. @anchor{ut_are_convertible()} @deftypefun @code{int} ut_are_convertible @code{(const ut_unit* @var{unit1}, uconst t_unit* @var{unit2})} Indicates if numeric values in unit @var{unit1} are convertible to numeric values in unit @var{unit2} via @ref{ut_get_converter()}. In making this determination, dimensionless units are ignored. This function returns a non-zero value if conversion is possible; otherwise, @code{0} is returned and @ref{ut_get_status()} will return one of the following: @table @code @item UT_BAD_ARG @var{unit1} or @var{unit2} is @code{NULL}. @item UT_NOT_SAME_SYSTEM @var{unit1} and @var{unit2} belong to different @ref{unit-system}s. @item UT_SUCCESS Conversion between the units is not possible (e.g., @var{unit1} refers to a meter and @var{unit2} refers to a kilogram. @end table @end deftypefun @anchor{ut_get_converter()} @deftypefun @code{cv_converter*} ut_get_converter @code{(ut_unit* const @var{from}, ut_unit* const @var{to})} Creates and returns a converter of numeric values in the @var{from} unit to equivalent values in the @var{to} unit. You should pass the returned pointer to @code{cv_free()} when you no longer need the converter. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{from} or @var{to} is @code{NULL}. @item UT_NOT_SAME_SYSTEM The units @var{from} and @var{to} don't belong to the same unit-system. @item UT_MEANINGLESS The units belong to the same unit-system but conversion between them is meaningless (e.g., conversion between seconds and kilograms is meaningless). @item UT_OS Operating-system failure. See @code{errno}. @end table @end deftypefun @anchor{cv_convert_float()} @deftypefun @code{float} cv_convert_float @code{(const cv_converter* @var{converter}, const float @var{value})} Converts the single floating-point value @var{value} and returns the new value. @end deftypefun @anchor{cv_convert_double()} @deftypefun @code{double} cv_convert_double @code{(const cv_converter* @var{converter}, const double @var{value})} Converts the single double-precision value @var{value} and returns the new value. @end deftypefun @anchor{cv_convert_floats()} @deftypefun @code{float*} cv_convert_floats @code{(const cv_converter* @var{converter}, const float* @var{in}, size_t @var{count}, float* @var{out})} Converts the @var{count} floating-point values starting at @var{in}, writing the new values starting at @var{out} and, as a convenience, returns @var{out}. The input and output arrays may overlap or be identical. @end deftypefun @anchor{cv_convert_doubles()} @deftypefun @code{double*} cv_convert_doubles @code{(const cv_converter* @var{converter}, const double* @var{in}, size_t @var{count}, double* @var{out})} Converts the @var{count} double-precision values starting at @var{in}, writing the new values starting at @var{out} and, as a convenience, returns @var{out}. The input and output arrays may overlap or be identical. @end deftypefun @anchor{cv_free()} @deftypefun @code{void} cv_free @code{(cv_converter* @var{conv})}; Frees resources associated with the converter referenced by @var{conv}. You should call this function when you no longer need the converter. Use of @var{conv} upon return results in undefined behavior. @end deftypefun @node Parsing, Syntax, Value Conversion, Top @chapter Parsing a String into a Unit @cindex parsing a string into a unit @cindex string, parsing into a unit Here's an example of parsing a string representation of a unit into its binary representation: @example #include #include ... ut_system* unitSystem = @ref{ut_read_xml(),ut_read_xml(NULL)}; const char* string = "kg.m2/s3"; ut_unit* watt = @ref{ut_parse(),ut_parse}(unitSystem, string, UT_ASCII); if (watt == NULL) @{ /* Unable to parse string. */ @} else @{ /* Life is good. */ @} @end example @anchor{ut_parse()} @deftypefun @code{ut_unit*} ut_parse @code{(const ut_system* @var{system}, const char* @var{string}, ut_encoding @var{encoding})} Returns the binary unit representation corresponding to the string unit representation @var{string} in the character-set @var{encoding} using the unit-system @var{system}. @var{string} must have no leading or trailing whitespace (see @code{@ref{ut_trim()}}). If an error occurs, then this function returns @code{NULL} and @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{system} or @var{string} is @code{NULL}. @item UT_SYNTAX @var{string} contained a syntax error. @item UT_UNKNOWN @var{string} contained an unknown identifier. @item UT_OS Operating-system failure. See @code{errno} for the reason. @end table @end deftypefun @anchor{ut_trim()} @deftypefun @code{size_t} ut_trim @code{(char* @var{string}, ut_encoding @var{encoding})} Removes all leading and trailing whitespace from the NUL-terminated string @var{string}. Returns @var{string}, which is modified if it contained leading or trailing whitespace. @end deftypefun @node Syntax, Formatting, Parsing, Top @chapter Unit Syntax @cindex unit syntax @cindex syntax, unit For the most part, the UDUNITS-2 package follows the syntax for unit-strings promulgated by the US National Institute for Standards and Technology (NIST). Details, of which, can be found at @uref{http://physics.nist.gov/cuu/Units/index.html}. The one general exception to this is the invention of a syntax for ``offset''-units (e.g., the definition of the degree Celsius is ``K @@ 273.15''). @menu * Examples:: Examples of unit specifications * Grammar:: Formal unit grammar @end menu @node Examples, Grammar, , Syntax @section Unit Specification Examples @cindex unit specification examples @cindex examples, unit specification @quotation @multitable {Logarithmic} {(5 meter)/(30 second)} {lg(re mW)} {"lg" is base 10, "ln" is base e, and "lb" is base 2} @headitem String Type @tab Using Names @tab Using Symbols @tab Comment @item Simple @tab meter @tab m @item Raised @tab meter^2 @tab m2 @tab higher precedence than multiplying or dividing @item Product @tab newton meter @tab N.m @item Quotient @tab meter per second @tab m/s @item Scaled @tab 60 second @tab 60 s @item Prefixed @tab kilometer @tab km @item Offset @tab kelvin from 273.15 @tab K @@ 273.15 @tab lower precedence than multiplying or dividing @item Logarithmic @tab lg(re milliwatt) @tab lg(re mW) @tab "lg" is base 10, "ln" is base e, and "lb" is base 2 @item Grouped @tab (5 meter)/(30 second) @tab (5 m)/(30 s) @end multitable @end quotation The above may be combined, e.g., "0.1 lg(re m/(5 s)^2) @@ 50". You may also look at the @code{} elements in @ref{Database,the units database} to see examples of string unit specifications. You may use the @code{@ref{Top, , udunits2, udunits2prog}} utility to experiment with string unit specifications. @node Grammar, , Examples, Syntax @section Unit Grammar @cindex unit grammar @cindex grammar, unit Here is the unit-syntax understood by the UDUNITS-2 package. Words printed @emph{Thusly} indicate non-terminals; words printed THUSLY indicate terminals; and words printed indicate lexical elements. @example @emph{Unit-Spec: one of} nothing @emph{Shift-Spec} @emph{Shift-Spec: one of} @emph{Product-Spec} @emph{Product-Spec} SHIFT REAL @emph{Product-Spec} SHIFT INT @emph{Product-Spec} SHIFT @emph{Timestamp} @emph{Product-Spec: one of} @emph{Power-Spec} @emph{Product-Spec} @emph{Power-Spec} @emph{Product-Spec} MULTIPLY @emph{Power-Spec} @emph{Product-Spec} DIVIDE @emph{Power-Spec} @emph{Power-Spec: one of} @emph{Basic-Spec} @emph{Basic-Spec} INT @emph{Basic-Spec} EXPONENT @emph{Basic-Spec} RAISE INT @emph{Basic-Spec: one of} ID "(" @emph{Shift-Spec} ")" LOGREF @emph{Product_Spec} ")" @emph{Number} @emph{Number: one of} INT REAL @emph{Timestamp: one of} DATE DATE CLOCK DATE CLOCK CLOCK DATE CLOCK INT DATE CLOCK ID TIMESTAMP TIMESTAMP INT TIMESTAMP ID SHIFT: * * : one of "@@" "after" "from" "since" "ref" REAL: the usual floating-point format INT: the usual integer format MULTIPLY: one of "-" "." "*" + DIVIDE: * * : one of per PER "/" EXPONENT: ISO-8859-9 or UTF-8 encoded exponent characters RAISE: one of "^" "**" ID: one of "%" "'" "\"" degree sign greek mu character : * : [A-Za-z_] ISO-8859-1 alphabetic characters non-breaking space : one of : [0-9] LOGREF: * : one of "log" "lg" "ln" "lb" : "(" * ":"? * DATE: "-" ("-" )? : [+-]?[0-9]@{1,4@} : "0"?[1-9]|1[0-2] : "0"?[1-9]|[1-2][0-9]|"30"|"31" CLOCK: ":" (":" )? TIMSTAMP: ( ?)? "T" ( ?)? : [+-]?[0-1]?[0-9]|2[0-3] : [0-5]?[0-9] : (|60) (\.[0-9]*)? @end example @node Formatting, Operations, Syntax, Top @chapter Formatting a Unit into a String @cindex formatting a unit into a string @cindex unit, formatting into a string @cindex string, formatting a unit into a Use the @code{@ref{ut_format()}} function to obtain the string representation of a binary unit. For example, the following gets the definition of the unit "watt" in ASCII characters using unit-symbols rather than unit-names: @example ut_unit* watt = ...; char buf[128]; unsigned opts = @ref{ut_encoding,UT_ASCII} | UT_DEFINITION; int len = @ref{ut_format(),ut_format}(watt, buf, sizeof(buf), opts); if (len == -1) @{ /* Couldn't get string */ @} else if (len == sizeof(buf)) @{ /* Entire buffer used: no terminating NUL */ @} else @{ /* Have string with terminating NUL */ @} @end example @anchor{ut_format()} @deftypefun @code{int} ut_format @code{(const ut_unit* @var{unit}, char* @var{buf}, size_t @var{size}, unsigned @var{opts})} Formats the unit @var{unit} (i.e., returns its string representation) into the buffer pointed-to by @var{buf} of size @var{size}. The argument @var{opts} specifies how the formatting is to be done and is a bitwise OR of a @ref{ut_encoding} value and zero or more of the following: @table @code @item UT_NAMES Use unit names instead of symbols. @item UT_DEFINITION The formatted string should be the definition of @var{unit} in terms of basic-units instead of stopping any expansion at the highest level possible. @end table On success, this function returns either the number of bytes -- excluding the terminating @code{NUL} -- that were written into @code{buf} or the number of bytes that @emph{would have been written}. The difference is due to the runtime @code{snprinf()} function that was used. On failure, this function returns @code{-1} and @ref{ut_get_status()} will return one of the following: @table @code @item UT_BAD_ARG @var{unit} or @var{buf} is @code{NULL}, or @var{opts} contains the bit patterns of both @code{UT_LATIN1} and @code{UT_UTF8}. @item UT_CANT_FORMAT @var{unit} can't be formatted in the desired manner (e.g., @var{opts} contains @code{UT_ASCII} but @var{unit} doesn't have an identifier in that character-set or @var{opts} doesn't contain UT_NAMES and a necessary symbol doesn't exist). @end table @end deftypefun @node Operations, Mapping, Formatting, Top @chapter Unit Operations @cindex unit operations @cindex operations, unit You can use unit operations to construct new units, get information about units, or compare units. @menu * Unary:: Operations on a single unit * Binary:: Operations on pairs of units @end menu @node Unary, Binary, , Operations @section Unary Unit Operations @cindex unary unit operations @anchor{ut_free()} @deftypefun @code{void} ut_free @code{(ut_unit* @var{unit})} Frees resources associated with @var{unit}. You should invoke this function on every unit that you no longer need. Use of @var{unit} upon return from this function results in undefined behavior. @end deftypefun @anchor{ut_scale()} @deftypefun @code{ut_unit*} ut_scale @code{(double @var{factor}, const ut_unit* @var{unit})} Returns a unit equivalent to another unit scaled by a numeric factor. For example: @example const ut_unit* meter = ... const ut_unit* kilometer = ut_scale(1000, meter); @end example The returned unit is equivalent to @var{unit} multiplied by @var{factor}. You should pass the returned pointer to @code{@ref{ut_free()}} when you no longer need the unit. @end deftypefun @anchor{ut_offset()} @deftypefun @code{ut_unit*} ut_offset @code{(const ut_unit* @var{unit}, double @var{offset})} Returns a unit equivalent to another unit relative to a particular origin. For example: @example const ut_unit* kelvin = ... const ut_unit* celsius = ut_offset(kelvin, 273.15); @end example The returned unit is equivalent to @var{unit} with an origin of @var{offset}. You should pass the returned pointer to @code{@ref{ut_free()}} when you no longer need the unit. If an error occurs, then this function returns @code{NULL} and @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{unit} is @code{NULL}. @item UT_OS Operating-system error. See @code{errno} for the reason. @end table @end deftypefun @anchor{ut_offset_by_time()} @deftypefun @code{ut_unit*} ut_offset_by_time @code{(const ut_unit* const @var{unit}, const double @var{origin})} Returns a timestamp-unit equivalent to the time unit @var{unit} referenced to the time-origin @var{origin} (as returned by @code{@ref{ut_encode_time()}}). For example: @example const ut_unit* second = ... const ut_unit* secondsSinceTheEpoch = ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0.0)); @end example Leap seconds are not taken into account. You should pass the returned pointer to @code{@ref{ut_free()}} when you no longer need the unit. If an error occurs, then this function returns @code{NULL} and @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{unit} is @code{NULL}. @item UT_OS Operating-system error. See @code{errno} for the reason. @item UT_MEANINGLESS Creation of a timestamp unit based on @var{unit} is not meaningful. It might not be a time-unit, for example. @item UT_NO_SECOND The associated unit-system doesn't contain a ``second'' unit. See @code{@ref{ut_set_second()}}. @end table @strong{CAUTION:} The timestamp-unit was created to be analogous to, for example, the degree celsius---but for the time dimension. I've come to believe, however, that creating such a unit was a mistake, primarily because users try to use the unit in ways for which it was not designed (such as converting dates in a calendar whose year is exactly 365 days long). Such activities are much better handled by a dedicated calendar package. Please be careful about using timestamp-units. See also the section on @ref{Time, The Handling of Time}. @end deftypefun @anchor{ut_invert()} @deftypefun @code{ut_unit*} ut_invert @code{(const ut_unit* @var{unit})} Returns the inverse (i.e., reciprocal) of the unit @var{unit}. This convenience function is equal to @code{@ref{ut_raise(),ut_raise(@var{unit}@comma{}-1)}}. You should pass the returned pointer to @code{@ref{ut_free()}} when you no longer need the unit. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{unit} is @code{NULL}. @item UT_OS Operating-system error. See @code{errno} for the reason. @end table @end deftypefun @anchor{ut_raise()} @deftypefun @code{ut_unit*} ut_raise @code{(const ut_unit* @var{unit}, int @var{power})} Returns the unit equal to unit @var{unit} raised to the power @var{power}. You should pass the returned pointer to @code{ut_free()} when you no longer need the unit. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{unit} is @code{NULL}. @item UT_OS Operating-system error. See @code{errno} for the reason. @end table @end deftypefun @anchor{ut_root()} @deftypefun @code{ut_unit*} ut_root @code{(const ut_unit* @var{unit}, int @var{root})} Returns the unit equal to the @var{root} root of unit @var{unit}. You should pass the returned pointer to @code{ut_free()} when you no longer need the unit. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{unit} is @code{NULL}. @item UT_MEANINGLESS It's meaningless to take the given root of the given unit. This could be because the resulting unit would have fractional (i.e., non-integral) dimensionality, or because the unit is, for example, a logarithmic unit. @item UT_OS Operating-system error. See @code{errno} for the reason. @end table @end deftypefun @anchor{ut_log()} @deftypefun @code{ut_unit*} ut_log @code{(double @var{base}, const ut_unit* @var{reference})} Returns the logarithmic unit corresponding to the logarithmic base @var{base} and a reference level specified as the unit @var{reference}. For example, the following creates a decibel unit with a one milliwatt reference level: @example const ut_unit* milliWatt = ...; const ut_unit* bel_1_mW = ut_log(10.0, milliWatt); if (bel_1_mW != NULL) @{ const ut_unit* decibel_1_mW = @ref{ut_scale(),ut_scale}(0.1, bel_1_mW); @ref{ut_free(),ut_free}(bel_1_mW); /* no longer needed */ if (decibel_1_mW != NULL) @{ /* Have decibel unit with 1 mW reference */ ... @ref{ut_free(),ut_free}(decibel_1_mW); @} /* "decibel_1_mW" allocated */ @} @end example You should pass the returned pointer to @code{ut_free()} when you no longer need the unit. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{reference} is @code{NULL}. @item UT_OS Operating-system error. See @code{errno} for the reason. @item UT_BAD_ARG @var{base} is invalid (e.g., it must be greater than one). @end table @end deftypefun @anchor{ut_get_name()} @deftypefun @code{const char*} ut_get_name @code{(const ut_unit* @var{unit}, ut_encoding @var{encoding})} Returns the name to which the unit referenced by @var{unit} maps in the character-encoding specified by @var{encoding}. If this function returns @code{NULL}, then @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{name} is @code{NULL}. @item UT_SUCCESS @var{unit} doesn't map to a name in the given character-set. @end table @end deftypefun @anchor{ut_get_symbol()} @deftypefun @code{const char*} ut_get_symbol @code{(const ut_unit* @var{unit}, ut_encoding @var{encoding})} Returns the symbol to which the unit referenced by @var{unit} maps in the character-encoding specified by @var{encoding}. If this function returns @code{NULL}, then @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{symbol} is @code{NULL}. @item UT_SUCCESS @var{unit} doesn't map to a symbol in the given character-set. @end table @end deftypefun @anchor{ut_get_system()} @deftypefun @code{ut_system*} ut_get_system @code{(const ut_unit* @var{unit})} Returns the unit-system to which the unit referenced by @var{unit} belongs. If @var{unit} is @code{NULL}, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return @code{UT_BAD_ARG}. @end deftypefun @anchor{ut_is_dimensionless()} @deftypefun @code{int} ut_is_dimensionless @code{(const ut_unit* @var{unit})} Indicates if unit @var{unit} is dimensionless (like ``radian''). This function returns a non-zero value if the unit is dimensionfull; otherwise, @code{0} is returned and @ref{ut_get_status()} will return one of the following: @table @code @item UT_BAD_ARG @var{unit1} is @code{NULL}. @item UT_SUCCESS The unit is dimensionless. @end table @end deftypefun @anchor{ut_clone()} @deftypefun @code{ut_unit*} ut_clone @code{(const ut_unit* @var{unit})} Returns a copy of the unit referenced by @var{unit}. You should pass the returned pointer to @code{ut_free()} when you no longer need the unit. If an error occurs, then this function writes an error-message using @code{@ref{ut_handle_error_message()}} and returns @code{NULL}. Also, @code{@ref{ut_get_status()}} will return one of the following: @table @code @item UT_BAD_ARG @var{unit} is @code{NULL}. @item UT_OS Operating-system failure. See @code{errno}. @end table If you use @code{@ref{ut_read_xml()}}, then you should not normally need to call this function. @end deftypefun @anchor{ut_accept_visitor()} @deftypefun @code{@ref{ut_status}} ut_accept_visitor @code{(const ut_unit* @var{unit}, const @ref{ut_visitor,ut_visitor}* @var{visitor}, void* @var{arg})} Accepts the visitor @var{visitor} to the unit @var{unit}. The argument @var{arg} is passed to the visitor's functions. This function returns one of the following: @table @code @item UT_BAD_ARG @var{visitor} or @var{unit} is @code{NULL}. @item UT_VISIT_ERROR An error occurred in @var{visitor} while visiting @var{unit}. @item UT_SUCCESS Success. @end table @end deftypefun @anchor{ut_visitor} @deftp {Data type} {ut_visitor} {int foo(int)} {int bar(int, int)} You pass a pointer to a data object of this type if and when you call @code{@ref{ut_accept_visitor()}}. It contains the following pointers to functions that implement your unit-visitor: @table @code @item @ref{ut_status} (*visit_basic)(const ut_unit* @var{unit}, void* @var{arg}); Visits the basic-unit @var{unit}. A basic-unit is a base unit like ``meter'' or a non-dimensional but named unit like ``radian''. This function returns @code{@ref{ut_status,UT_SUCCESS}} on and only on success. @item @ref{ut_status} (*visit_product)(const ut_unit* @var{unit}, int @var{count}, const ut_unit* const* @var{basicUnits}, const int* @var{powers}, void* @var{arg}); Visits the product-unit @var{unit}. The product-unit is a product of the @var{count} basic-units referenced by @var{basicUnits}, each raised to their respective, non-zero power in @var{powers}. This function returns @code{@ref{ut_status,UT_SUCCESS}} on and only on success. @item @ref{ut_status} (*visit_galilean)(const ut_unit* @var{unit}, double @var{scale}, const ut_unit* @var{underlyingUnit}, double @var{origin}, void* arg); Visits the Galilean-unit @var{unit}. The Galilean-unit has the underlying unit @var{underlyingUnit} and either the non-unity scale factor @var{scale} or the non-zero origin @var{origin}, or both. This function returns @code{@ref{ut_status,UT_SUCCESS}} on and only on success. @item @ref{ut_status} (*visit_timestamp)(const ut_unit* @var{unit}, const ut_unit* @var{timeUnit}, double @var{origin}, void* @var{arg}); Visits the timestamp-unit @var{unit}. The timestamp-unit has the underlying unit of time @var{timeUnit} and the @code{@ref{ut_encode_time()}}-encoded time-origin @var{origin}. This function returns @code{@ref{ut_status,UT_SUCCESS}} on and only on success. @item @ref{ut_status} (*visit_logarithmic)(const ut_unit* @var{unit}, double @var{base}, const ut_unit* @var{reference}, void* @var{arg}); Visits the logarithmic-unit @var{unit}. The logarithmic-unit has the logarithmic base @var{base} and the reference-level is specified by the unit @var{reference}. This function returns @code{@ref{ut_status,UT_SUCCESS}} on and only on success. @end table @end deftp @node Binary, , Unary, Operations @section Binary Unit Operations @cindex binary unit operations Binary unit operations act on two units. @strong{NOTE\:} The functions @code{@ref{ut_are_convertible()}} and @code{@ref{ut_get_converter()}} are also binary unit operations but are documented elsewhere. @anchor{ut_multiply()} @deftypefun @code{ut_unit*} ut_multiply @code{(const ut_unit* @var{unit1}, const ut_unit* @var{unit2})} Returns the result of multiplying unit @var{unit1} by unit @var{unit2}. You should pass the pointer to @ref{ut_free()} when you no longer need the unit On failure, this function returns @code{NULL} and @ref{ut_get_status()} will return one of the following: @table @code @item UT_BAD_ARG @var{unit1} or @var{unit2} is @code{NULL}. @item UT_NOT_SAME_SYSTEM @var{unit1} and @var{unit2} belong to different @ref{unit-system}s. @item UT_OS Operating-system error. See @var{errno} for the reason. @end table @end deftypefun @anchor{ut_divide} @deftypefun @code{ut_unit*} ut_divide @code{(const ut_unit* @var{numer}, const ut_unit* @var{denom})} Returns the result of dividing unit @var{numer} by unit @var{denom}. You should pass the pointer to @ref{ut_free()} when you no longer need the unit On failure, this function returns @code{NULL} and @ref{ut_get_status()} will return one of the following: @table @code @item UT_BAD_ARG @var{numer} or @var{denom} is @code{NULL}. @item UT_NOT_SAME_SYSTEM @var{unit1} and @var{unit2} belong to different @ref{unit-system}s. @item UT_OS Operating-system error. See @code{errno} for the reason. @end table @end deftypefun @anchor{ut_compare()} @deftypefun @code{int} ut_compare @code{(const ut_unit* @var{unit1}, const ut_unit* @var{unit2})} Compares two units. Returns a value less than, equal to, or greater than zero as @var{unit1} is considered less than, equal to, or greater than @var{unit2}, respectively. Units from different @ref{unit-system}s never compare equal. The value zero is also returned if both unit pointers are @code{NULL}. @end deftypefun @anchor{ut_same_system()} @deftypefun @code{int} ut_same_system @code{(const ut_unit* @var{unit1}, const ut_unit* @var{unit2})} Indicates if two units belong to the same unit-system. This function returns a non-zero value if the two units belong to the same @ref{unit-system}; otherwise, @code{0} is returned and @ref{ut_get_status()} will return one of the following: @table @code @item UT_BAD_ARG @var{unit1} or @var{unit2} is @code{NULL}. @item UT_SUCCESS The units belong to different @ref{unit-system}s. @end table @end deftypefun @node Mapping, Time, Operations, Top @chapter Mapping Between Identifiers and Units @cindex mapping units @cindex mapping identifiers @cindex units, mapping to identifiers Within a unit-system, you can map an identifier to a unit and vice versa. If an identifier maps to a unit, then the unit can be retrieved from the unit-system via the identifier. Similarly, if a unit maps to an identifier, then the unit can be printed using the identifier. There a two kinds of identifiers: names and symbols. @menu * Names:: Mapping between units and names. * Symbols:: Mapping between units and symbols. @end menu @node Names, Symbols, , Mapping @section Names @cindex names You can map a name to a unit and vice versa. If you use @code{@ref{ut_read_xml()}}, then you shouldn't normally need to do this. @anchor{ut_map_name_to_unit()} @deftypefun @code{@ref{ut_status}} ut_map_name_to_unit @code{(const char* @var{name}, const ut_encoding @var{encoding}, const ut_unit* @var{unit})} Maps the name referenced by @var{name}, in character-set @var{encoding}, to the unit referenced by @var{unit} in the unit-system that contains @var{unit}. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{name} or @var{unit} is @code{NULL}. @item UT_OS Operating-system failure. See @code{errno}. @item UT_EXISTS @var{name} already maps to a different unit. @end table @end deftypefun @anchor{ut_unmap_name_to_unit()} @deftypefun @code{@ref{ut_status}} ut_unmap_name_to_unit @code{(ut_system* @var{system}, const char* @var{name}, const ut_encoding @var{encoding})} Removes any mapping from name @var{name}, in character-set @var{encoding}, to a unit in unit-system @var{system}. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{system} or @var{name} is @code{NULL}. @end table @end deftypefun @anchor{ut_map_unit_to_name()} @deftypefun @code{@ref{ut_status}} ut_map_unit_to_name @code{(const ut_unit* @var{unit}, const char* @var{name}, ut_encoding @var{encoding})} Maps the unit @var{unit} to the name @var{name}, which is in character-set @var{encoding}, in the unit-system that contains the unit. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{unit} or @var{name} is @code{NULL}, or @var{name} is not in the character-set @var{encoding}. @item UT_OS Operating-system failure. See @code{errno}. @item UT_EXISTS @var{unit} already maps to a different name. @end table @end deftypefun @anchor{ut_unmap_unit_to_name()} @deftypefun @code{@ref{ut_status}} ut_unmap_unit_to_name @code{(const ut_unit* @var{unit}, ut_encoding @var{encoding})} Removes any mapping from unit @var{unit} to a name in character-set @var{encoding} from the unit-system that contains the unit. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{unit} is @code{NULL}. @end table @end deftypefun @node Symbols, , Names, Mapping @section Symbols @cindex symbols You can map a symbol to a unit and vice versa. If you use @code{@ref{ut_read_xml()}}, then you shouldn't normally need to do this. @anchor{ut_map_symbol_to_unit()} @deftypefun @code{@ref{ut_status}} ut_map_symbol_to_unit @code{(const char* @var{symbol}, const ut_encoding @var{encoding}, const ut_unit* @var{unit})} Maps the symbol referenced by @var{symbol}, in character-set @var{encoding}, to the unit referenced by @var{unit} in the unit-system that contains @var{unit}. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{symbol} or @var{unit} is @code{NULL}. @item UT_OS Operating-system failure. See @code{errno}. @item UT_EXISTS @var{symbol} already maps to a different unit. @end table @end deftypefun @anchor{ut_unmap_symbol_to_unit()} @deftypefun @code{@ref{ut_status}} ut_unmap_symbol_to_unit @code{(ut_system* @var{system}, const char* @var{symbol}, const ut_encoding @var{encoding})} Removes any mapping from symbol @var{symbol}, in character-set @var{encoding}, to a unit in unit-system @var{system}. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{system} or @var{symbol} is @code{NULL}. @end table @end deftypefun @anchor{ut_map_unit_to_symbol()} @deftypefun @code{@ref{ut_status}} ut_map_unit_to_symbol @code{(const ut_unit* @var{unit}, const char* @var{symbol}, ut_encoding @var{encoding})} Maps the unit @var{unit} to the symbol @var{symbol}, which is in character-set @var{encoding}, in the unit-system that contains the unit. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{unit} or @var{symbol} is @code{NULL}. @item UT_BAD_ARG Symbol @var{symbol} is not in the character-set @var{encoding}. @item UT_OS Operating-system failure. See @code{errno}. @item UT_EXISTS @var{unit} already maps to a different symbol. @end table @end deftypefun @anchor{ut_unmap_unit_to_symbol()} @deftypefun @code{@ref{ut_status}} ut_unmap_unit_to_symbol @code{(const ut_unit* @var{unit}, ut_encoding @var{encoding})} Removes any mapping from unit @var{unit} to a symbol in character-set @var{encoding} from the unit-system that contains the unit. This function returns one of the following: @table @code @item UT_SUCCESS Success. @item UT_BAD_ARG @var{unit} is @code{NULL}. @end table @end deftypefun @node Time, Errors, Mapping, Top @chapter The Handling of Time @cindex time, handling of You should use a true calendar package rather than the UDUNITS-2 package to handle time. Having said that, many people use the time-handling capabilities of the UDUNITS-2 package because it supports "units" like "@code{seconds since 1970-01-01}". You should be aware, however, that the hybrid Gregorian/Julian calendar used by the UDUNITS-2 package @emph{cannot be changed}. Dates on or after 1582-10-15 are assumed to be Gregorian dates; dates before that are assumed to be Julian dates. In particular, the year 1 BCE is immediately followed by the year 1 CE. In general, the UDUNITS-2 package handles time by encoding it as double-precision value, which can then be acted upon arithmetically. @anchor{ut_encode_time()} @deftypefun @code{double} ut_encode_time @code{(int @var{year}, int @var{month}, int @var{day}, int @var{hour}, int @var{minute}, double @var{second})} Encodes a time as a double-precision value. This convenience function is equivalent to @example @ref{ut_encode_date(),ut_encode_date}(@var{year},@var{month},@var{day}) + @ref{ut_encode_clock(),ut_encode_clock}(@var{hour},@var{minute},@var{second}) @end example @end deftypefun @anchor{ut_encode_date()} @deftypefun @code{double} ut_encode_date @code{(int @var{year}, int @var{month}, int @var{day})} Encodes a date as a double-precision value. You probably won't use this function. Dates on or after 1582-10-15 are assumed to be Gregorian dates; dates before that are assumed to be Julian dates. In particular, the year 1 BCE is immediately followed by the year 1 CE. @end deftypefun @anchor{ut_encode_clock()} @deftypefun @code{double} ut_encode_clock @code{(int @var{hour}, int @var{minute}, double @var{second})} Encodes a clock-time as a double-precision value. You probably won't use this function. @end deftypefun @anchor{ut_decode_time()} @deftypefun @code{void} ut_decode_time @code{(double @var{time}, int* @var{year}, int* @var{month}, int* @var{day}, int* @var{hour}, int* @var{minute}, double* @var{second}, double* @var{resolution})} Decodes a time from a double-precision value into its individual components. The variable referenced by @var{resolution} will be set to the resolution (i.e., uncertainty) of the time in seconds. @end deftypefun @node Errors, Database, Time, Top @chapter Error Handling @cindex error handling Error-handling in the units module has two aspects: the status of the last operation performed by the module and the handling of error-messages: @menu * Status:: The status of the last operation. * Messages:: The handling of error-messages. @end menu @node Status, Messages, , Errors @section Status of Last Operation @cindex status of last operation @cindex module status UDUNITS-2 functions set their status by calling @code{@ref{ut_set_status()}}. You can use the function @code{@ref{ut_get_status()}} to retrieve that status. @anchor{ut_get_status()} @deftypefun @code{@ref{ut_status}} ut_get_status @code{(void)} Returns the value specified in the last call to @code{@ref{ut_set_status()}} @end deftypefun @anchor{ut_set_status()} @deftypefun @code{void} ut_set_status @code{(@ref{ut_status} @var{status})} Set the status of the units module to @var{status}. @end deftypefun @anchor{ut_status} @deftp {Data type} {ut_status} This enumeration has the following values: @table @code @item UT_SUCCESS Success @item UT_BAD_ARG An argument violates the the function's contract (e.g., it's @code{NULL}). @item UT_EXISTS Unit, prefix, or identifier already exists @item UT_NO_UNIT No such unit exists @item UT_OS Operating-system error. See @code{errno} for the reason. @item UT_NOT_SAME_SYSTEM The units belong to different unit-systems @item UT_MEANINGLESS The operation on the unit or units is meaningless @item UT_NO_SECOND The unit-system doesn't have a unit named ``second'' @item UT_VISIT_ERROR An error occurred while visiting a unit @item UT_CANT_FORMAT A unit can't be formatted in the desired manner @item UT_SYNTAX String unit representation contains syntax error @item UT_UNKNOWN String unit representation contains unknown word @item UT_OPEN_ARG Can't open argument-specified unit database @item UT_OPEN_ENV Can't open environment-specified unit database @item UT_OPEN_DEFAULT Can't open installed, default, unit database @item UT_PARSE Error parsing unit database @end table @end deftp @node Messages, , Status, Errors @section Error-Messages @cindex messages, error @cindex error-messages @anchor{ut_handle_error_message()} @deftypefun @code{int} ut_handle_error_message @code{(const char* @var{fmt}, ...)} Handles the error-message corresponding to the format-string @var{fmt} and any subsequent arguments referenced by it. The interpretation of the formatting-string is identical to that of the UNIX function @code{printf()}. On success, this function returns the number of bytes in the error-message; otherwise, this function returns @code{-1}. Use the function @code{@ref{ut_set_error_message_handler()}} to change how error-messages are handled. @end deftypefun @anchor{ut_set_error_message_handler()} @deftypefun @code{@ref{ut_error_message_handler}} ut_set_error_message_handler @code{(@ref{ut_error_message_handler} @var{handler})} Sets the function that handles error-messages and returns the previous error-message handler. The initial error-message handler is @code{@ref{ut_write_to_stderr()}}. @end deftypefun @anchor{ut_write_to_stderr()} @deftypefun @code{int} ut_write_to_stderr @code{(const char* @var{fmt}, va_list @var{args})} Writes the variadic error-message corresponding to formatting-string @var{fmt} and arguments @var{args} to the standard-error stream and appends a newline. The interpretation of the formatting-string is identical to that of the UNIX function @code{printf()}. On success, this function returns the number of bytes in the error-message; otherwise, this function returns @code{-1}. @end deftypefun @anchor{ut_ignore()} @deftypefun @code{int} ut_ignore @code{(const char* @var{fmt}, va_list @var{args})} Does nothing. In particular, it ignores the variadic error-message corresponding to formatting-string @var{fmt} and arguments @var{args}. Pass this function to @code{@ref{ut_set_error_message_handler()}} when you don't want the unit module to print any error-messages. @end deftypefun @anchor{ut_error_message_handler} @deftp {Data type} {ut_error_message_handler} This is the type of an error-message handler. It's definition is @example typedef int (*ut_error_message_handler)(const char* fmt, va_list args); @end example @end deftp @node Database, Types, Errors, Top @chapter The Units Database @cindex units database @cindex database, units The database of units that comes with the UDUNITS-2 package is an XML-formatted file that is based on the SI system of units. It contains the names and symbols of most of the units that you will ever encounter. The pathname of the installed file is @code{@emph{datadir}/udunits2.xml}, where @emph{datadir} is the installation-directory for read-only, architecture-independent data (e.g., @code{/usr/local/share}). This pathname is the default that @code{@ref{ut_read_xml()}} uses. Naturally, because the database is a regular file, it can be edited to add new units or remove existing ones. Be very careful about doing this, however, because you might lose the benefit of exchanging unit-based information with others who haven't modified their database. @node Types, Complete Index, Database, Top @chapter Data Types @cindex data types @cindex types, data The data types @code{@ref{ut_visitor}}, @code{@ref{ut_status}}, and @code{@ref{ut_error_message_handler}} are documented elsewhere. @anchor{ut_encoding} @deftp {Data type} {ut_encoding} This enumeration has the following values: @table @code @item UT_ASCII @uref{http://en.wikipedia.org/wiki/Ascii,US ASCII} character-set. @item UT_ISO_8859_1 The @uref{http://en.wikipedia.org/wiki/Iso-8859-1,ISO-8859-1} character-set. @item UT_LATIN1 Synonym for @code{UT_ISO_8859_1}. @item UT_UTF8 The @uref{http://en.wikipedia.org/wiki/Utf-8,UTF-8} encoding of the Unicode character-set. @end table @end deftp @node Complete Index, , Types, Top @unnumbered Index @printindex cp @bye udunits-2.2.0/lib/CMakeLists.txt0000644000175000017500000000432312260406756017660 0ustar amckinstryamckinstryINCLUDE_DIRECTORIES("." "${CMAKE_BINARY_DIR}") INCLUDE_DIRECTORIES("${EXPAT_INCLUDE_DIRS}") IF (CUNIT_INCLUDE_DIR) INCLUDE_DIRECTORIES("${CUNIT_INCLUDE_DIR}") ENDIF() # Ensure that the C source-files for the scanner and parser are up-to-date # on a Unix system. if (UNIX) add_custom_command( OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/scanner.c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND flex -d -Put -o scanner.c scanner.l DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/scanner.l) add_custom_command( OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/parser.c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND bison -t -p ut -o parser.c parser.y DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/parser.y) set_source_files_properties(parser.c PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/scanner.c) endif() add_library(libudunits2 converter.c error.c formatter.c idToUnitMap.c parser.c prefix.c status.c systemMap.c unitAndId.c unitcore.c unitToIdMap.c ut_free_system.c xml.c) set_target_properties(libudunits2 PROPERTIES LIBRARY_OUTPUT_NAME udunits2) set_target_properties(libudunits2 PROPERTIES ARCHIVE_OUTPUT_NAME udunits2) set_target_properties(libudunits2 PROPERTIES RUNTIME_OUTPUT_NAME udunits2) target_link_libraries(libudunits2 ${EXPAT_LIBRARIES}) if (CUNIT_LIBRARY) add_executable(testUnits testUnits.c) target_link_libraries (testUnits libudunits2) target_link_libraries (testUnits ${EXPAT_LIBRARY}) target_link_libraries (testUnits ${CUNIT_LIBRARY}) target_link_libraries (testUnits ${MATH_LIBRARY}) add_test( NAME testUnits COMMAND testUnits ${CMAKE_CURRENT_SOURCE_DIR}/udunits2.xml) endif() # The documentation is in multiple texinfo(5) format files texi_doc(udunits2lib.texi ${CMAKE_SOURCE_DIR}/COPYRIGHT) install(TARGETS libudunits2 ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin) install(FILES udunits2.h DESTINATION include) install(FILES udunits2.xml udunits2-accepted.xml udunits2-base.xml udunits2-common.xml udunits2-derived.xml udunits2-prefixes.xml DESTINATION share/udunits)udunits-2.2.0/lib/parser.c0000644000175000017500000017622512260406756016573 0ustar amckinstryamckinstry/* A Bison parser, made by GNU Bison 2.5. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. This program 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 3 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.5" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Using locations. */ #define YYLSP_NEEDED 0 /* Substitute the variable and function names. */ #define yyparse utparse #define yylex utlex #define yyerror uterror #define yylval utlval #define yychar utchar #define yydebug utdebug #define yynerrs utnerrs /* Copy the first part of user declarations. */ /* Line 268 of yacc.c */ #line 1 "parser.y" /* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * bison(1)-based parser for decoding formatted unit specifications. * * This module is thread-compatible but not thread-safe. Multi-threaded * access must be externally synchronized. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include "udunits2.h" static ut_unit* _finalUnit; /* fully-parsed specification */ static ut_system* _unitSystem; /* The unit-system to use */ static char* _errorMessage; /* last error-message */ static ut_encoding _encoding; /* encoding of string to be parsed */ static int _restartScanner;/* restart scanner? */ /* * Removes leading and trailing whitespace from a string. * * Arguments: * string NUL-terminated string. Will be modified if it * contains whitespace. * encoding The character-encoding of "string". * Returns: * "string" */ char* ut_trim( char* const string, const ut_encoding encoding) { static const char* asciiSpace = " \t\n\r\f\v"; static const char* latin1Space = " \t\n\r\f\v\xa0"; /* add NBSP */ const char* whiteSpace; char* start; char* stop; size_t len; whiteSpace = encoding == UT_LATIN1 ? latin1Space : asciiSpace; start = string + strspn(string, whiteSpace); for (stop = start + strlen(start); stop > start; --stop) if (strchr(whiteSpace, stop[-1]) == NULL) break; len = stop - start; (void)memmove(string, start, len); string[len] = 0; ut_set_status(UT_SUCCESS); return start; } /* * YACC error routine: */ void uterror( char *s) { static char* nomem = "uterror(): out of memory"; if (_errorMessage != NULL && _errorMessage != nomem) free(_errorMessage); _errorMessage = strdup(s); if (_errorMessage == NULL) _errorMessage = nomem; } /* Line 268 of yacc.c */ #line 182 "parser.c" /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 1 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* Enabling the token table. */ #ifndef YYTOKEN_TABLE # define YYTOKEN_TABLE 0 #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { ERR = 258, SHIFT = 259, MULTIPLY = 260, DIVIDE = 261, INT = 262, EXPONENT = 263, REAL = 264, ID = 265, DATE = 266, CLOCK = 267, TIMESTAMP = 268, LOGREF = 269 }; #endif #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { /* Line 293 of yacc.c */ #line 103 "parser.y" char* id; /* identifier */ ut_unit* unit; /* "unit" structure */ double rval; /* floating-point numerical value */ long ival; /* integer numerical value */ /* Line 293 of yacc.c */ #line 241 "parser.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif /* Copy the second part of user declarations. */ /* Line 343 of yacc.c */ #line 253 "parser.c" #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ # define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(e) ((void) (e)) #else # define YYUSE(e) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else static int YYID (yyi) int yyi; #endif { return yyi; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (YYID (0)) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 15 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 95 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 17 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 8 /* YYNRULES -- Number of rules. */ #define YYNRULES 37 /* YYNRULES -- Number of states. */ #define YYNSTATES 45 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 269 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint8 yyprhs[] = { 0, 0, 3, 4, 6, 8, 10, 14, 18, 22, 26, 28, 31, 34, 38, 42, 46, 50, 52, 55, 58, 61, 63, 67, 71, 75, 79, 81, 83, 85, 87, 90, 94, 98, 102, 104, 107, 110 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { 18, 0, -1, -1, 19, -1, 1, -1, 20, -1, 20, 4, 9, -1, 20, 4, 7, -1, 20, 4, 24, -1, 20, 4, 1, -1, 21, -1, 20, 21, -1, 20, 1, -1, 20, 5, 21, -1, 20, 5, 1, -1, 20, 6, 21, -1, 20, 6, 1, -1, 22, -1, 22, 7, -1, 22, 8, -1, 22, 1, -1, 10, -1, 15, 19, 16, -1, 15, 19, 1, -1, 14, 20, 16, -1, 14, 20, 1, -1, 23, -1, 7, -1, 9, -1, 11, -1, 11, 12, -1, 11, 12, 12, -1, 11, 12, 7, -1, 11, 12, 10, -1, 13, -1, 13, 12, -1, 13, 7, -1, 13, 10, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 133, 133, 137, 141, 146, 149, 155, 161, 167, 175, 178, 185, 191, 198, 204, 211, 219, 222, 228, 234, 242, 295, 298, 304, 310, 316, 322, 325, 330, 333, 336, 339, 352, 371, 374, 377, 390 }; #endif #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "ERR", "SHIFT", "MULTIPLY", "DIVIDE", "INT", "EXPONENT", "REAL", "ID", "DATE", "CLOCK", "TIMESTAMP", "LOGREF", "'('", "')'", "$accept", "unit_spec", "shift_exp", "product_exp", "power_exp", "basic_exp", "number", "timestamp", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 40, 41 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 17, 18, 18, 18, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 0, 1, 1, 1, 3, 3, 3, 3, 1, 2, 2, 3, 3, 3, 3, 1, 2, 2, 2, 1, 3, 3, 3, 3, 1, 1, 1, 1, 2, 3, 3, 3, 1, 2, 2, 2 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. Performed when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 0, 4, 27, 28, 21, 0, 0, 0, 3, 0, 10, 0, 26, 0, 0, 1, 12, 0, 0, 0, 11, 20, 18, 19, 12, 24, 23, 22, 9, 7, 6, 29, 34, 8, 14, 13, 16, 15, 30, 36, 37, 35, 32, 33, 31 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { -1, 7, 8, 9, 10, 11, 12, 33 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -10 static const yytype_int8 yypact[] = { 40, -10, -10, -10, -10, 80, 80, 2, -10, 17, -10, 0, -10, 29, 12, -10, -10, 70, 50, 60, -10, -10, -10, -10, 48, -10, -10, -10, -10, -10, -10, -9, 56, -10, -10, -10, -10, -10, 81, -10, -10, -10, -10, -10, -10 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -10, -10, 5, 7, 67, -10, -10, -10 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -26 static const yytype_int8 yytable[] = { -17, 21, 15, 38, -17, -17, -17, 22, 23, -17, -17, 14, 13, 26, -17, -17, -17, -5, 16, 0, 0, 17, 18, 19, 2, 0, 3, 4, 27, 0, 24, 5, 6, -5, 18, 19, 2, 0, 3, 4, -2, 1, 0, 5, 6, 25, 0, 2, -25, 3, 4, 34, -25, 0, 5, 6, -25, 2, 0, 3, 4, 36, 0, 39, 5, 6, 40, 2, 41, 3, 4, 28, 0, 0, 5, 6, 20, 29, 0, 30, 20, 31, 0, 32, 0, 35, 37, 2, 42, 3, 4, 43, 0, 44, 5, 6 }; #define yypact_value_is_default(yystate) \ ((yystate) == (-10)) #define yytable_value_is_error(yytable_value) \ YYID (0) static const yytype_int8 yycheck[] = { 0, 1, 0, 12, 4, 5, 6, 7, 8, 9, 10, 6, 5, 1, 14, 15, 16, 0, 1, -1, -1, 4, 5, 6, 7, -1, 9, 10, 16, -1, 1, 14, 15, 16, 5, 6, 7, -1, 9, 10, 0, 1, -1, 14, 15, 16, -1, 7, 0, 9, 10, 1, 4, -1, 14, 15, 8, 7, -1, 9, 10, 1, -1, 7, 14, 15, 10, 7, 12, 9, 10, 1, -1, -1, 14, 15, 9, 7, -1, 9, 13, 11, -1, 13, -1, 18, 19, 7, 7, 9, 10, 10, -1, 12, 14, 15 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 1, 7, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 20, 19, 0, 1, 4, 5, 6, 21, 1, 7, 8, 1, 16, 1, 16, 1, 7, 9, 11, 13, 24, 1, 21, 1, 21, 12, 7, 10, 12, 7, 10, 12 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. However, YYFAIL appears to be in use. Nevertheless, it is formally deprecated in Bison 2.4.2's NEWS entry, where a plan to phase it out is discussed. */ #define YYFAIL goto yyerrlab #if defined YYFAIL /* This is here to suppress warnings from the GCC cpp's -Wunused-macros. Normally we don't worry about that warning, but some users do, and we want to make it easy for users to remove YYFAIL uses, which will produce warnings from Bison 2.5. */ #endif #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (1); \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif /* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void yy_stack_print (yybottom, yytop) yytype_int16 *yybottom; yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = 0; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - Assume YYFAIL is not used. It's too flawed to consider. See for details. YYERROR is fine as it does not invoke this function. - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (0, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; #endif { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: `yyss': related to states. `yyvs': related to semantic values. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yytoken = 0; yyss = yyssa; yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: /* Line 1806 of yacc.c */ #line 133 "parser.y" { _finalUnit = ut_get_dimensionless_unit_one(_unitSystem); YYACCEPT; } break; case 3: /* Line 1806 of yacc.c */ #line 137 "parser.y" { _finalUnit = (yyvsp[(1) - (1)].unit); YYACCEPT; } break; case 4: /* Line 1806 of yacc.c */ #line 141 "parser.y" { YYABORT; } break; case 5: /* Line 1806 of yacc.c */ #line 146 "parser.y" { (yyval.unit) = (yyvsp[(1) - (1)].unit); } break; case 6: /* Line 1806 of yacc.c */ #line 149 "parser.y" { (yyval.unit) = ut_offset((yyvsp[(1) - (3)].unit), (yyvsp[(3) - (3)].rval)); ut_free((yyvsp[(1) - (3)].unit)); if ((yyval.unit) == NULL) YYERROR; } break; case 7: /* Line 1806 of yacc.c */ #line 155 "parser.y" { (yyval.unit) = ut_offset((yyvsp[(1) - (3)].unit), (yyvsp[(3) - (3)].ival)); ut_free((yyvsp[(1) - (3)].unit)); if ((yyval.unit) == NULL) YYERROR; } break; case 8: /* Line 1806 of yacc.c */ #line 161 "parser.y" { (yyval.unit) = ut_offset_by_time((yyvsp[(1) - (3)].unit), (yyvsp[(3) - (3)].rval)); ut_free((yyvsp[(1) - (3)].unit)); if ((yyval.unit) == NULL) YYERROR; } break; case 9: /* Line 1806 of yacc.c */ #line 167 "parser.y" { ut_status prev = ut_get_status(); ut_free((yyvsp[(1) - (3)].unit)); ut_set_status(prev); YYERROR; } break; case 10: /* Line 1806 of yacc.c */ #line 175 "parser.y" { (yyval.unit) = (yyvsp[(1) - (1)].unit); } break; case 11: /* Line 1806 of yacc.c */ #line 178 "parser.y" { (yyval.unit) = ut_multiply((yyvsp[(1) - (2)].unit), (yyvsp[(2) - (2)].unit)); ut_free((yyvsp[(1) - (2)].unit)); ut_free((yyvsp[(2) - (2)].unit)); if ((yyval.unit) == NULL) YYERROR; } break; case 12: /* Line 1806 of yacc.c */ #line 185 "parser.y" { ut_status prev = ut_get_status(); ut_free((yyvsp[(1) - (2)].unit)); ut_set_status(prev); YYERROR; } break; case 13: /* Line 1806 of yacc.c */ #line 191 "parser.y" { (yyval.unit) = ut_multiply((yyvsp[(1) - (3)].unit), (yyvsp[(3) - (3)].unit)); ut_free((yyvsp[(1) - (3)].unit)); ut_free((yyvsp[(3) - (3)].unit)); if ((yyval.unit) == NULL) YYERROR; } break; case 14: /* Line 1806 of yacc.c */ #line 198 "parser.y" { ut_status prev = ut_get_status(); ut_free((yyvsp[(1) - (3)].unit)); ut_set_status(prev); YYERROR; } break; case 15: /* Line 1806 of yacc.c */ #line 204 "parser.y" { (yyval.unit) = ut_divide((yyvsp[(1) - (3)].unit), (yyvsp[(3) - (3)].unit)); ut_free((yyvsp[(1) - (3)].unit)); ut_free((yyvsp[(3) - (3)].unit)); if ((yyval.unit) == NULL) YYERROR; } break; case 16: /* Line 1806 of yacc.c */ #line 211 "parser.y" { ut_status prev = ut_get_status(); ut_free((yyvsp[(1) - (3)].unit)); ut_set_status(prev); YYERROR; } break; case 17: /* Line 1806 of yacc.c */ #line 219 "parser.y" { (yyval.unit) = (yyvsp[(1) - (1)].unit); } break; case 18: /* Line 1806 of yacc.c */ #line 222 "parser.y" { (yyval.unit) = ut_raise((yyvsp[(1) - (2)].unit), (yyvsp[(2) - (2)].ival)); ut_free((yyvsp[(1) - (2)].unit)); if ((yyval.unit) == NULL) YYERROR; } break; case 19: /* Line 1806 of yacc.c */ #line 228 "parser.y" { (yyval.unit) = ut_raise((yyvsp[(1) - (2)].unit), (yyvsp[(2) - (2)].ival)); ut_free((yyvsp[(1) - (2)].unit)); if ((yyval.unit) == NULL) YYERROR; } break; case 20: /* Line 1806 of yacc.c */ #line 234 "parser.y" { ut_status prev = ut_get_status(); ut_free((yyvsp[(1) - (2)].unit)); ut_set_status(prev); YYERROR; } break; case 21: /* Line 1806 of yacc.c */ #line 242 "parser.y" { double prefix = 1; ut_unit* unit = NULL; char* cp = (yyvsp[(1) - (1)].id); int symbolPrefixSeen = 0; while (*cp) { size_t nchar; double value; unit = ut_get_unit_by_name(_unitSystem, cp); if (unit != NULL) break; unit = ut_get_unit_by_symbol(_unitSystem, cp); if (unit != NULL) break; if (utGetPrefixByName(_unitSystem, cp, &value, &nchar) == UT_SUCCESS) { prefix *= value; cp += nchar; } else { if (!symbolPrefixSeen && utGetPrefixBySymbol(_unitSystem, cp, &value, &nchar) == UT_SUCCESS) { symbolPrefixSeen = 1; prefix *= value; cp += nchar; } else { break; } } } free((yyvsp[(1) - (1)].id)); if (unit == NULL) { ut_set_status(UT_UNKNOWN); YYERROR; } (yyval.unit) = ut_scale(prefix, unit); ut_free(unit); if ((yyval.unit) == NULL) YYERROR; } break; case 22: /* Line 1806 of yacc.c */ #line 295 "parser.y" { (yyval.unit) = (yyvsp[(2) - (3)].unit); } break; case 23: /* Line 1806 of yacc.c */ #line 298 "parser.y" { ut_status status = ut_get_status(); ut_free((yyvsp[(2) - (3)].unit)); ut_set_status(status); YYERROR; } break; case 24: /* Line 1806 of yacc.c */ #line 304 "parser.y" { (yyval.unit) = ut_log((yyvsp[(1) - (3)].rval), (yyvsp[(2) - (3)].unit)); ut_free((yyvsp[(2) - (3)].unit)); if ((yyval.unit) == NULL) YYERROR; } break; case 25: /* Line 1806 of yacc.c */ #line 310 "parser.y" { ut_status status = ut_get_status(); ut_free((yyvsp[(2) - (3)].unit)); ut_set_status(status); YYERROR; } break; case 26: /* Line 1806 of yacc.c */ #line 316 "parser.y" { (yyval.unit) = ut_scale((yyvsp[(1) - (1)].rval), ut_get_dimensionless_unit_one(_unitSystem)); } break; case 27: /* Line 1806 of yacc.c */ #line 322 "parser.y" { (yyval.rval) = (yyvsp[(1) - (1)].ival); } break; case 28: /* Line 1806 of yacc.c */ #line 325 "parser.y" { (yyval.rval) = (yyvsp[(1) - (1)].rval); } break; case 29: /* Line 1806 of yacc.c */ #line 330 "parser.y" { (yyval.rval) = (yyvsp[(1) - (1)].rval); } break; case 30: /* Line 1806 of yacc.c */ #line 333 "parser.y" { (yyval.rval) = (yyvsp[(1) - (2)].rval) + (yyvsp[(2) - (2)].rval); } break; case 31: /* Line 1806 of yacc.c */ #line 336 "parser.y" { (yyval.rval) = (yyvsp[(1) - (3)].rval) + ((yyvsp[(2) - (3)].rval) - (yyvsp[(3) - (3)].rval)); } break; case 32: /* Line 1806 of yacc.c */ #line 339 "parser.y" { int mag = (yyvsp[(3) - (3)].ival) >= 0 ? (yyvsp[(3) - (3)].ival) : -(yyvsp[(3) - (3)].ival); if (mag <= 24) { (yyval.rval) = (yyvsp[(1) - (3)].rval) + ((yyvsp[(2) - (3)].rval) - ut_encode_clock((yyvsp[(3) - (3)].ival), 0, 0)); } else if (mag >= 100 && mag <= 2400) { (yyval.rval) = (yyvsp[(1) - (3)].rval) + ((yyvsp[(2) - (3)].rval) - ut_encode_clock((yyvsp[(3) - (3)].ival)/100, (yyvsp[(3) - (3)].ival)%100, 0)); } else { ut_set_status(UT_SYNTAX); YYERROR; } } break; case 33: /* Line 1806 of yacc.c */ #line 352 "parser.y" { int error = 0; if (strcasecmp((yyvsp[(3) - (3)].id), "UTC") != 0 && strcasecmp((yyvsp[(3) - (3)].id), "GMT") != 0 && strcasecmp((yyvsp[(3) - (3)].id), "Z") != 0) { ut_set_status(UT_UNKNOWN); error = 1; } free((yyvsp[(3) - (3)].id)); if (!error) { (yyval.rval) = (yyvsp[(1) - (3)].rval) + (yyvsp[(2) - (3)].rval); } else { YYERROR; } } break; case 34: /* Line 1806 of yacc.c */ #line 371 "parser.y" { (yyval.rval) = (yyvsp[(1) - (1)].rval); } break; case 35: /* Line 1806 of yacc.c */ #line 374 "parser.y" { (yyval.rval) = (yyvsp[(1) - (2)].rval) - (yyvsp[(2) - (2)].rval); } break; case 36: /* Line 1806 of yacc.c */ #line 377 "parser.y" { int mag = (yyvsp[(2) - (2)].ival) >= 0 ? (yyvsp[(2) - (2)].ival) : -(yyvsp[(2) - (2)].ival); if (mag <= 24) { (yyval.rval) = (yyvsp[(1) - (2)].rval) - ut_encode_clock((yyvsp[(2) - (2)].ival), 0, 0); } else if (mag >= 100 && mag <= 2400) { (yyval.rval) = (yyvsp[(1) - (2)].rval) - ut_encode_clock((yyvsp[(2) - (2)].ival)/100, (yyvsp[(2) - (2)].ival)%100, 0); } else { ut_set_status(UT_SYNTAX); YYERROR; } } break; case 37: /* Line 1806 of yacc.c */ #line 390 "parser.y" { int error = 0; if (strcasecmp((yyvsp[(2) - (2)].id), "UTC") != 0 && strcasecmp((yyvsp[(2) - (2)].id), "GMT") != 0 && strcasecmp((yyvsp[(2) - (2)].id), "Z") != 0) { ut_set_status(UT_UNKNOWN); error = 1; } free((yyvsp[(2) - (2)].id)); if (!error) { (yyval.rval) = (yyvsp[(1) - (2)].rval); } else { YYERROR; } } break; /* Line 1806 of yacc.c */ #line 1999 "parser.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } *++yyvsp = yylval; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined(yyoverflow) || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); } /* Line 2067 of yacc.c */ #line 411 "parser.y" #define yymaxdepth utmaxdepth #define yylval utlval #define yychar utchar #define yypact utpact #define yyr1 utr1 #define yyr2 utr2 #define yydef utdef #define yychk utchk #define yypgo utpgo #define yyact utact #define yyexca utexca #define yyerrflag uterrflag #define yynerrs utnerrs #define yyps utps #define yypv utpv #define yys uts #define yy_yys utyys #define yystate utstate #define yytmp uttmp #define yyv utv #define yy_yyv utyyv #define yyval utval #define yylloc utlloc #define yyreds utreds #define yytoks uttoks #define yylhs utyylhs #define yylen utyylen #define yydefred utyydefred #define yydgoto utyydgoto #define yysindex utyysindex #define yyrindex utyyrindex #define yygindex utyygindex #define yytable utyytable #define yycheck utyycheck #define yyname utyyname #define yyrule utyyrule #include "scanner.c" /* * Converts a string in the Latin-1 character set (ISO 8859-1) to the UTF-8 * character set. * * Arguments: * latin1String Pointer to the string to be converted. May be freed * upon return. * Returns: * NULL Failure. ut_handle_error_message() was called. * else Pointer to UTF-8 representation of "string". Must not * be freed. Subsequent calls may overwrite. */ static const char* latin1ToUtf8( const char* const latin1String) { static char* utf8String = NULL; static size_t bufSize = 0; size_t size; const unsigned char* in; unsigned char* out; assert(latin1String != NULL); size = 2 * strlen(latin1String) + 1; if (size > bufSize) { char* buf = realloc(utf8String, size); if (buf != NULL) { utf8String = buf; bufSize = size; } else { ut_handle_error_message("Couldn't allocate %ld-byte buffer: %s", (unsigned long)size, strerror(errno)); return NULL; } } for (in = (const unsigned char*)latin1String, out = (unsigned char*)utf8String; *in; ++in) { # define IS_ASCII(c) (((c) & 0x80) == 0) if (IS_ASCII(*in)) { *out++ = *in; } else { *out++ = 0xC0 | ((0xC0 & *in) >> 6); *out++ = 0x80 | (0x3F & *in); } } *out = 0; return utf8String; } /* * Returns the binary representation of a unit corresponding to a string * representation. * * Arguments: * system Pointer to the unit-system in which the parsing will * occur. * string The string to be parsed (e.g., "millimeters"). There * should be no leading or trailing whitespace in the * string. See ut_trim(). * encoding The encoding of "string". * Returns: * NULL Failure. "ut_get_status()" will be one of * UT_BAD_ARG "system" or "string" is NULL. * UT_SYNTAX "string" contained a syntax * error. * UT_UNKNOWN "string" contained an unknown * identifier. * UT_OS Operating-system failure. See * "errno". * else Pointer to the unit corresponding to "string". */ ut_unit* ut_parse( const ut_system* const system, const char* const string, ut_encoding encoding) { ut_unit* unit = NULL; /* failure */ if (system == NULL || string == NULL) { ut_set_status(UT_BAD_ARG); } else { const char* utf8String; if (encoding != UT_LATIN1) { utf8String = string; } else { utf8String = latin1ToUtf8(string); encoding = UT_UTF8; if (utf8String == NULL) ut_set_status(UT_OS); } if (utf8String != NULL) { YY_BUFFER_STATE buf = ut_scan_string(utf8String); _unitSystem = (ut_system*)system; _encoding = encoding; _restartScanner = 1; #if YYDEBUG utdebug = 0; ut_flex_debug = 0; #endif _finalUnit = NULL; if (utparse() == 0) { int status; int n = yy_c_buf_p - buf->yy_ch_buf; if (n >= strlen(utf8String)) { unit = _finalUnit; /* success */ status = UT_SUCCESS; } else { /* * Parsing terminated before the end of the string. */ ut_free(_finalUnit); status = UT_SYNTAX; } ut_set_status(status); } ut_delete_buffer(buf); } /* utf8String != NULL */ } /* valid arguments */ return unit; } udunits-2.2.0/lib/udunits2-derived.xml0000644000175000017500000000751512260406756021045 0ustar amckinstryamckinstry radian rad rad^2 steradian sr 1/s hertz Hz 1e-3 kg gram g m.kg/s^2 newton N N/m^2 pascal Pa N.m joule J J/s watt W s.A coulomb C W/A volt V C/V farad F V/A ohm Ω A/V siemens S V.s weber Wb Wb/m^2 tesla T Wb/A henry H K @ 273.15 degree_Celsius degrees_Celsius °C cd.sr lumen lm lm/m^2 lux lx mol/s katal kat 1/s becquerel Bq J/kg gray Gy J/kg sievert Sv udunits-2.2.0/lib/testUnits.c0000644000175000017500000022724712260406756017302 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include #include #include #include "udunits2.h" static const char* xmlPath; static ut_system* unitSystem; static ut_unit* kilogram; static ut_unit* meter; static ut_unit* radian; static ut_unit* kelvin; static ut_unit* second; static ut_unit* minute; static ut_unit* kilometer; static ut_unit* micron; static ut_unit* rankine; static ut_unit* celsius; static ut_unit* fahrenheit; static ut_unit* meterPerSecondSquared; static ut_unit* meterSquaredPerSecondSquared; static ut_unit* joulePerKilogram; static ut_unit* watt; static ut_unit* wattSquared; static ut_unit* cubicMeter; static ut_unit* cubicMicron; static ut_unit* BZ; static ut_unit* dBZ; static ut_unit* secondsSinceTheEpoch; static ut_unit* minutesSinceTheMillenium; static ut_unit* hertz; static ut_unit* megahertz; static unsigned asciiName = UT_ASCII | UT_NAMES; static unsigned asciiNameDef = UT_ASCII | UT_NAMES | UT_DEFINITION; static unsigned asciiSymbolDef = UT_ASCII | UT_DEFINITION; static unsigned latin1SymbolDef = UT_LATIN1 | UT_DEFINITION; static unsigned utf8SymbolDef = UT_UTF8 | UT_DEFINITION; /* * Only called once. */ static int setup( void) { return ((unitSystem = ut_new_system()) == NULL) ? -1 : 0; } /* * Only called once. */ static int teardown( void) { ut_free_system(unitSystem); return 0; } static void test_unitSystem(void) { ut_system* system = ut_new_system(); ut_unit* unit; char buf[80]; CU_ASSERT_PTR_NOT_NULL(system); ut_set_status(UT_SUCCESS); unit = ut_new_base_unit(system); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_map_unit_to_name(unit, "name", UT_ASCII), UT_SUCCESS); ut_free(unit); unit = ut_get_dimensionless_unit_one(system); CU_ASSERT_PTR_NOT_NULL_FATAL(unit); CU_ASSERT_EQUAL(ut_format(unit, buf, sizeof(buf)-1, asciiSymbolDef), 1); CU_ASSERT_STRING_EQUAL(buf, "1"); ut_free(unit); ut_free_system(system); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); } static void test_utNewBaseUnit(void) { kilogram = ut_new_base_unit(unitSystem); CU_ASSERT_PTR_NOT_NULL(kilogram); CU_ASSERT_EQUAL(ut_map_unit_to_name(kilogram, "kilogram", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_symbol(kilogram, "kg", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("kg", UT_ASCII, kilogram), UT_SUCCESS); meter = ut_new_base_unit(unitSystem); CU_ASSERT_PTR_NOT_NULL(meter); CU_ASSERT_EQUAL(ut_map_name_to_unit("meter", UT_ASCII, meter), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_name(meter, "meter", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_symbol(meter, "m", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("m", UT_ASCII, meter), UT_SUCCESS); kelvin = ut_new_base_unit(unitSystem); CU_ASSERT_PTR_NOT_NULL(kelvin); CU_ASSERT_EQUAL(ut_map_unit_to_name(kelvin, "kelvin", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_name_to_unit("kelvin", UT_ASCII, kelvin), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_symbol(kelvin, "K", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("K", UT_ASCII, kelvin), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_name(kilogram, "dummy", UT_ASCII), UT_EXISTS); second = ut_new_base_unit(unitSystem); CU_ASSERT_PTR_NOT_NULL(second); CU_ASSERT_PTR_NULL(ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0))); CU_ASSERT_EQUAL(ut_get_status(), UT_NO_SECOND); CU_ASSERT_EQUAL(ut_set_second(second), UT_SUCCESS); CU_ASSERT_EQUAL(ut_set_second(NULL), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_map_unit_to_name(second, "second", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_name_to_unit("second", UT_ASCII, second), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_symbol(second, "s", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("s", UT_ASCII, second), UT_SUCCESS); CU_ASSERT_PTR_NULL(ut_new_base_unit(NULL)); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_map_unit_to_name(kilogram, "\xc5ngstr\xf6m", UT_UTF8), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_set_second(second), UT_SUCCESS); CU_ASSERT_EQUAL(ut_set_second(meter), UT_EXISTS); CU_ASSERT_EQUAL(ut_set_second(NULL), UT_BAD_ARG); } static void test_utNewDimensionlessUnit(void) { radian = ut_new_dimensionless_unit(unitSystem); CU_ASSERT_PTR_NOT_NULL(radian); CU_ASSERT_EQUAL(ut_map_unit_to_name(radian, "radian", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_name_to_unit("radian", UT_ASCII, radian), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_symbol(radian, "rad", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("rad", UT_ASCII, radian), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_name(radian, "dummy", UT_ASCII), UT_EXISTS); CU_ASSERT_EQUAL(ut_map_unit_to_symbol(radian, "f", UT_ASCII), UT_EXISTS); CU_ASSERT_EQUAL(ut_map_unit_to_symbol(NULL, "f", UT_ASCII), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_map_unit_to_name(radian, "\xc5ngstr\xf6m", UT_UTF8), UT_BAD_ARG); } static void test_utGetUnitByName(void) { ut_unit* altMeter = ut_get_unit_by_name(unitSystem, "meter"); CU_ASSERT_PTR_NOT_NULL(altMeter); CU_ASSERT_EQUAL(ut_compare(altMeter, meter), 0); ut_free(altMeter); CU_ASSERT_PTR_NULL(ut_get_unit_by_name(unitSystem, NULL)); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); CU_ASSERT_PTR_NULL(ut_get_unit_by_name(unitSystem, "foo")); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); } static void test_utGetUnitBySymbol(void) { ut_unit* altMeter = ut_get_unit_by_symbol(unitSystem, "m"); CU_ASSERT_PTR_NOT_NULL(altMeter); CU_ASSERT_EQUAL(ut_compare(altMeter, meter), 0); ut_free(altMeter); CU_ASSERT_PTR_NULL(ut_get_unit_by_symbol(unitSystem, NULL)); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); CU_ASSERT_PTR_NULL(ut_get_unit_by_symbol(unitSystem, "M")); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); } static void test_utAddNamePrefix(void) { CU_ASSERT_EQUAL(ut_add_name_prefix(unitSystem, "mega", 1e6), UT_SUCCESS); CU_ASSERT_EQUAL(ut_add_name_prefix(unitSystem, "mega", 1e6), UT_SUCCESS); CU_ASSERT_EQUAL(ut_add_name_prefix(unitSystem, "MEGA", 1e6), UT_SUCCESS); CU_ASSERT_EQUAL(ut_add_name_prefix(unitSystem, "mega", 1e5), UT_EXISTS); CU_ASSERT_EQUAL(ut_add_name_prefix(unitSystem, "MEGA", 1e5), UT_EXISTS); CU_ASSERT_EQUAL(ut_add_name_prefix(NULL, "foo", 1), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_add_name_prefix(unitSystem, "", 2), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_add_name_prefix(unitSystem, NULL, 3), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_add_name_prefix(unitSystem, "foo", 0), UT_BAD_ARG); } static void test_utAddSymbolPrefix(void) { CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, "M", 1e6), UT_SUCCESS); CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, "M", 1e6), UT_SUCCESS); CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, "u", 1e-6), UT_SUCCESS); CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, "\xb5", 1e-6), UT_SUCCESS); CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, "\xc2\xb5", 1e-6), UT_SUCCESS); /* "\xc2\xb5" is "mu" character in UTF-8 */ CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, "k", 1e3), UT_SUCCESS); CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, "M", 1e5), UT_EXISTS); CU_ASSERT_EQUAL(ut_add_symbol_prefix(NULL, "foo", 1), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, "", 2), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, NULL, 3), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_add_symbol_prefix(unitSystem, "f", 0), UT_BAD_ARG); } static void test_utMapNameToUnit(void) { ut_unit* metre; CU_ASSERT_PTR_NULL(ut_get_unit_by_name(unitSystem, "metre")); CU_ASSERT_EQUAL(ut_map_name_to_unit("metre", UT_ASCII, meter), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_name_to_unit("metre", UT_ASCII, meter), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_name_to_unit("metre", UT_ASCII, second), UT_EXISTS); CU_ASSERT_EQUAL(ut_map_name_to_unit("metre", UT_ASCII, NULL), UT_BAD_ARG); metre = ut_get_unit_by_name(unitSystem, "metre"); CU_ASSERT_PTR_NOT_NULL(metre); CU_ASSERT_EQUAL(ut_compare(metre, meter), 0); ut_free(metre); } static void test_utMapSymbolToUnit(void) { ut_unit* degK; /* "\xb0" is the degree symbol in Latin-1 */ CU_ASSERT_EQUAL(ut_map_symbol_to_unit("\xb0K", UT_LATIN1, kelvin), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("\xb0K", UT_LATIN1, kelvin), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("\xb0K", UT_LATIN1, second), UT_EXISTS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("\xb0K", UT_LATIN1, NULL), UT_BAD_ARG); degK = ut_get_unit_by_symbol(unitSystem, "\xb0K"); CU_ASSERT_PTR_NOT_NULL(degK); CU_ASSERT_EQUAL(ut_compare(degK, kelvin), 0); ut_free(degK); /* "\xc2\xb0" is the degree symbol in UTF-8 */ CU_ASSERT_EQUAL(ut_map_symbol_to_unit("\xc2\xb0K", UT_UTF8, kelvin), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("\xc2\xb0K", UT_UTF8, kelvin), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("\xc2\xb0K", UT_UTF8, second), UT_EXISTS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("\xc2\xb0K", UT_UTF8, NULL), UT_BAD_ARG); degK = ut_get_unit_by_symbol(unitSystem, "\xc2\xb0K"); CU_ASSERT_PTR_NOT_NULL(degK); CU_ASSERT_EQUAL(ut_compare(degK, kelvin), 0); ut_free(degK); } static void test_utToString(void) { char buf[80]; int nchar = ut_format(meter, buf, sizeof(buf)-1, asciiSymbolDef); int n; ut_unit* unit; const char* string = "s @ 1-01-01 00:00:00.000000 UTC"; CU_ASSERT_EQUAL(nchar, 1); CU_ASSERT_STRING_EQUAL(buf, "m"); n = ut_format(kilogram, buf, 1, asciiSymbolDef); CU_ASSERT_EQUAL(n, 2); nchar = ut_format(meter, buf, sizeof(buf)-1, asciiName); CU_ASSERT_STRING_EQUAL(buf, "meter"); n = ut_format(celsius, buf, sizeof(buf)-1, asciiName); CU_ASSERT_TRUE(n > 0); CU_ASSERT_STRING_EQUAL(buf, "degrees_celsius"); unit = ut_parse(unitSystem, "second since 1-01-01T00:00:00Z", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT(ut_format(unit, buf, sizeof(buf), asciiSymbolDef) != -1); CU_ASSERT_STRING_EQUAL(buf, string); n = ut_format(unit, buf, 1, asciiSymbolDef); CU_ASSERT_EQUAL(n, strlen(string)); ut_free(unit); } static void test_utScale(void) { ut_unit* metre; char buf[80]; int nchar; kilometer = ut_scale(1000, meter); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(kilometer); CU_ASSERT_EQUAL(ut_get_system(meter), ut_get_system(kilometer)); CU_ASSERT_EQUAL(ut_compare(meter, kilometer), -1); CU_ASSERT_EQUAL(ut_compare(kilometer, meter), 1); nchar = ut_format(kilometer, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "1000 m"); nchar = ut_format(kilometer, buf, sizeof(buf)-1, asciiNameDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "1000 meter"); micron = ut_scale(1e-6, meter); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(micron); CU_ASSERT_EQUAL(ut_get_system(meter), ut_get_system(micron)); CU_ASSERT_EQUAL(ut_compare(meter, micron), -1); CU_ASSERT_EQUAL(ut_compare(micron, meter), 1); CU_ASSERT_EQUAL(ut_compare(kilometer, micron), 1); CU_ASSERT_EQUAL(ut_compare(micron, kilometer), -1); metre = ut_scale(1, meter); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(metre); CU_ASSERT_EQUAL(ut_get_system(meter), ut_get_system(metre)); CU_ASSERT_EQUAL(ut_compare(meter, metre), 0); ut_free(metre); minute = ut_scale(60, second); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(minute); nchar = ut_format(minute, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "60 s"); nchar = ut_format(minute, buf, sizeof(buf)-1, asciiNameDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "60 second"); metre = ut_scale(1/1000., kilometer); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(metre); CU_ASSERT_EQUAL(ut_get_system(meter), ut_get_system(metre)); ut_free(metre); CU_ASSERT_PTR_NULL(ut_scale(0, meter)); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); CU_ASSERT_PTR_NULL(ut_scale(0, NULL)); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); rankine = ut_scale(1/1.8, kelvin); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(rankine); } static void test_utOffset(void) { ut_unit* dupKelvin; char buf[80]; int nchar; celsius = ut_offset(kelvin, 273.15); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(celsius); CU_ASSERT_EQUAL(ut_get_system(kelvin), ut_get_system(celsius)); CU_ASSERT_EQUAL(ut_compare(kelvin, celsius), -1); CU_ASSERT_EQUAL(ut_compare(celsius, kelvin), 1); fahrenheit = ut_offset(rankine, 459.67); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(fahrenheit); CU_ASSERT_EQUAL(ut_get_system(rankine), ut_get_system(fahrenheit)); CU_ASSERT_EQUAL(ut_compare(rankine, fahrenheit), -1); CU_ASSERT_EQUAL(ut_compare(fahrenheit, rankine), 1); CU_ASSERT_EQUAL(ut_compare(celsius, fahrenheit), -1); CU_ASSERT_EQUAL(ut_compare(fahrenheit, celsius), 1); CU_ASSERT_EQUAL(ut_map_name_to_unit("degrees_fahrenheit", UT_ASCII, fahrenheit), UT_SUCCESS); nchar = ut_format(celsius, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "K @ 273.15"); nchar = ut_format(celsius, buf, sizeof(buf)-1, asciiNameDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "kelvin from 273.15"); dupKelvin = ut_offset(kelvin, 0); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(dupKelvin); CU_ASSERT_EQUAL(ut_get_system(kelvin), ut_get_system(dupKelvin)); CU_ASSERT_EQUAL(ut_compare(kelvin, dupKelvin), 0); ut_free(dupKelvin); dupKelvin = ut_offset(celsius, -273.15); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_PTR_NOT_NULL(dupKelvin); CU_ASSERT_EQUAL(ut_get_system(kelvin), ut_get_system(dupKelvin)); ut_free(dupKelvin); (void)ut_offset(NULL, 5); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); } static void test_utMapUnitToName(void) { ut_unit* metre; CU_ASSERT_EQUAL(ut_map_unit_to_name(meter, "metre", UT_ASCII), UT_EXISTS); CU_ASSERT_EQUAL(ut_map_name_to_unit("metre", UT_ASCII, second), UT_EXISTS); CU_ASSERT_EQUAL(ut_map_name_to_unit("metre", UT_ASCII, NULL), UT_BAD_ARG); metre = ut_get_unit_by_name(unitSystem, "metre"); CU_ASSERT_PTR_NOT_NULL(metre); CU_ASSERT_EQUAL(ut_compare(metre, meter), 0); CU_ASSERT_EQUAL(ut_map_unit_to_name(celsius, "degrees_celsius", UT_ASCII), UT_SUCCESS); ut_free(metre); } static void test_utGetName(void) { CU_ASSERT_STRING_EQUAL(ut_get_name(meter, UT_ASCII), "meter"); CU_ASSERT_STRING_EQUAL(ut_get_name(celsius, UT_ASCII), "degrees_celsius"); CU_ASSERT_STRING_EQUAL(ut_get_name(kilogram, UT_ASCII), "kilogram"); CU_ASSERT_STRING_EQUAL(ut_get_name(kelvin, UT_ASCII), "kelvin"); CU_ASSERT_STRING_EQUAL(ut_get_name(second, UT_ASCII), "second"); CU_ASSERT_STRING_EQUAL(ut_get_name(radian, UT_ASCII), "radian"); } static void test_utGetSymbol(void) { CU_ASSERT_STRING_EQUAL(ut_get_symbol(kilogram, UT_ASCII), "kg"); CU_ASSERT_STRING_EQUAL(ut_get_symbol(meter, UT_ASCII), "m"); CU_ASSERT_STRING_EQUAL(ut_get_symbol(kelvin, UT_ASCII), "K"); CU_ASSERT_STRING_EQUAL(ut_get_symbol(second, UT_ASCII), "s"); CU_ASSERT_STRING_EQUAL(ut_get_symbol(radian, UT_ASCII), "rad"); CU_ASSERT_STRING_EQUAL(ut_get_symbol(hertz, UT_ASCII), "Hz"); } static void test_utMultiply(void) { ut_unit* squareMeter; ut_unit* meterSecond; ut_unit* meterCelsius; ut_unit* meterRadian; ut_unit* kilometerMinute; ut_unit* unit; char buf[80]; int nchar; squareMeter = ut_multiply(meter, meter); CU_ASSERT_PTR_NOT_NULL(squareMeter); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(squareMeter, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m2"); nchar = ut_format(squareMeter, buf, sizeof(buf)-1, asciiNameDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "meter^2"); meterSecond = ut_multiply(meter, second); CU_ASSERT_PTR_NOT_NULL(meterSecond); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(meterSecond, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m.s"); nchar = ut_format(meterSecond, buf, sizeof(buf)-1, asciiNameDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "meter-second"); meterCelsius = ut_multiply(meter, celsius); CU_ASSERT_PTR_NOT_NULL(meterCelsius); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(meterCelsius, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m.K"); meterRadian = ut_multiply(meter, radian); CU_ASSERT_PTR_NOT_NULL(meterRadian); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(meterRadian, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m.rad"); kilometerMinute = ut_multiply(kilometer, minute); CU_ASSERT_PTR_NOT_NULL(kilometerMinute); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(kilometerMinute, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "60000 m.s"); nchar = ut_format(kilometerMinute, buf, sizeof(buf)-1, asciiNameDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "60000 meter-second"); unit = ut_multiply(secondsSinceTheEpoch, meter); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); ut_free(squareMeter); ut_free(meterSecond); ut_free(meterCelsius); ut_free(meterRadian); ut_free(kilometerMinute); CU_ASSERT_PTR_NULL(ut_multiply(NULL, meter)); CU_ASSERT_PTR_NULL(ut_multiply(meter, NULL)); } static void test_utInvert(void) { ut_unit* inverseMeter; ut_unit* inverseMinute; ut_unit* inverseCelsius; ut_unit* inverseRadian; ut_unit* inverseMeterSecond; ut_unit* unit; char buf[80]; int nchar; inverseMeter = ut_invert(meter); CU_ASSERT_PTR_NOT_NULL(inverseMeter); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(inverseMeter, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m-1"); inverseMinute = ut_invert(minute); CU_ASSERT_PTR_NOT_NULL(inverseMinute); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(inverseMinute, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "0.0166666666666667 s-1"); inverseRadian = ut_invert(radian); CU_ASSERT_PTR_NOT_NULL(inverseRadian); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(inverseRadian, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "rad-1"); inverseCelsius = ut_invert(celsius); CU_ASSERT_PTR_NOT_NULL(inverseCelsius); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(inverseCelsius, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "K-1"); unit = ut_multiply(meter, second); inverseMeterSecond = ut_invert(unit); ut_free(unit); CU_ASSERT_PTR_NOT_NULL(inverseMeterSecond); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(inverseMeterSecond, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m-1.s-1"); ut_free(inverseMeter); ut_free(inverseMinute); ut_free(inverseCelsius); ut_free(inverseRadian); ut_free(inverseMeterSecond); hertz = ut_invert(second); CU_ASSERT_PTR_NOT_NULL(hertz); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_name(hertz, "hertz", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_name_to_unit("hertz", UT_ASCII, hertz), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_unit_to_symbol(hertz, "Hz", UT_ASCII), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("Hz", UT_ASCII, hertz), UT_SUCCESS); unit = ut_invert(second); megahertz = ut_scale(1e6, unit); ut_free(unit); CU_ASSERT_PTR_NOT_NULL(megahertz); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); } static void test_utDivide(void) { ut_unit* meterPerSecond; ut_unit* kilometerPerMinute; ut_unit* celsiusPerMeter; ut_unit* meterPerCelsius; ut_unit* unit; ut_unit* unit2; ut_unit* unit3; char buf[80]; int nchar; meterPerSecond = ut_divide(meter, second); CU_ASSERT_PTR_NOT_NULL(meterPerSecond); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(meterPerSecond, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m.s-1"); kilometerPerMinute = ut_divide(kilometer, minute); CU_ASSERT_PTR_NOT_NULL(kilometerPerMinute); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(kilometerPerMinute, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "16.6666666666667 m.s-1"); celsiusPerMeter = ut_divide(celsius, meter); CU_ASSERT_PTR_NOT_NULL(celsiusPerMeter); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(celsiusPerMeter, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m-1.K"); meterPerCelsius = ut_divide(meter, celsius); CU_ASSERT_PTR_NOT_NULL(meterPerCelsius); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(meterPerCelsius, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m.K-1"); unit = ut_raise(second, 2); meterPerSecondSquared = ut_divide(meter, unit); ut_free(unit); CU_ASSERT_PTR_NOT_NULL(meterPerSecondSquared); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(meterPerSecondSquared, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m.s-2"); unit = ut_divide(meter, second); meterSquaredPerSecondSquared = ut_raise(unit, 2); ut_free(unit); CU_ASSERT_PTR_NOT_NULL(meterSquaredPerSecondSquared); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(meterSquaredPerSecondSquared, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m2.s-2"); unit = ut_divide(meter, second); unit2 = ut_raise(unit, 2); ut_free(unit); unit3 = ut_multiply(kilogram, unit2); ut_free(unit2); joulePerKilogram = ut_divide(unit3, kilogram); ut_free(unit3); CU_ASSERT_PTR_NOT_NULL(joulePerKilogram); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(joulePerKilogram, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m2.s-2"); unit = ut_divide(meter, second); unit2 = ut_raise(unit, 2); ut_free(unit); unit3 = ut_multiply(kilogram, unit2); ut_free(unit2); watt = ut_divide(unit3, second); ut_free(unit3); CU_ASSERT_PTR_NOT_NULL(watt); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(watt, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "kg.m2.s-3"); ut_free(meterPerSecond); ut_free(kilometerPerMinute); ut_free(celsiusPerMeter); ut_free(meterPerCelsius); CU_ASSERT_PTR_NULL(ut_divide(NULL, meter)); CU_ASSERT_PTR_NULL(ut_divide(meter, NULL)); } static void test_utRaise(void) { ut_unit* perCubicMeter; ut_unit* celsiusCubed; ut_unit* minutesPerKilometer; ut_unit* kilometersSquaredPerMinuteSquared; ut_unit* unit; char buf[80]; int nchar; wattSquared = ut_raise(watt, 2); CU_ASSERT_PTR_NOT_NULL(wattSquared); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(wattSquared, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "kg2.m4.s-6"); perCubicMeter = ut_raise(meter, -3); CU_ASSERT_PTR_NOT_NULL(perCubicMeter); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(perCubicMeter, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m-3"); celsiusCubed = ut_raise(celsius, 3); CU_ASSERT_PTR_NOT_NULL(celsiusCubed); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(celsiusCubed, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "K3"); minutesPerKilometer = ut_divide(minute, kilometer); kilometersSquaredPerMinuteSquared = ut_raise(minutesPerKilometer, -2); ut_free(minutesPerKilometer); CU_ASSERT_PTR_NOT_NULL(kilometersSquaredPerMinuteSquared); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(kilometersSquaredPerMinuteSquared, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "277.777777777778 m2.s-2"); ut_free(perCubicMeter); ut_free(celsiusCubed); ut_free(kilometersSquaredPerMinuteSquared); unit = ut_raise(meter, 0); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, ut_get_dimensionless_unit_one(unitSystem)), 0); ut_free(unit); unit = ut_raise(meter, 1); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, meter), 0); ut_free(unit); unit = ut_raise(secondsSinceTheEpoch, 2); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); CU_ASSERT_PTR_NULL(ut_raise(dBZ, 2)); CU_ASSERT_PTR_NULL(ut_raise(NULL, 2)); } static void test_utRoot(void) { ut_unit* unit; ut_unit* unit2; CU_ASSERT_PTR_NULL(ut_root(watt, -1)); CU_ASSERT_PTR_NULL(ut_root(watt, 0)); unit = ut_root(watt, 1); CU_ASSERT_EQUAL(ut_compare(watt, unit), 0); ut_free(unit); unit = ut_get_dimensionless_unit_one(unitSystem); CU_ASSERT_EQUAL(ut_compare(unit, ut_root(unit, 1)), 0); ut_free(unit); unit = ut_root(watt, 1); CU_ASSERT_EQUAL(ut_compare(watt, unit), 0); ut_free(unit); unit = ut_raise(watt, 2); unit2 = ut_root(unit, 2); ut_free(unit); CU_ASSERT_EQUAL(ut_compare(watt, unit2), 0); ut_free(unit2); unit = ut_raise(celsius, 2); unit2 = ut_root(unit, 2); ut_free(unit); CU_ASSERT_EQUAL(ut_compare(kelvin, unit2), 0); ut_free(unit2); unit = ut_raise(secondsSinceTheEpoch, 2); unit2 = ut_root(unit, 2); ut_free(unit); CU_ASSERT_EQUAL(ut_compare(second, unit2), 0); ut_free(unit2); CU_ASSERT_PTR_NULL(ut_root(BZ, 2)); } static void test_utLog(void) { ut_unit* milliwatt = ut_scale(0.001, watt); ut_unit* bel_1_mW = ut_log(10, milliwatt); ut_unit* decibel_1_mW; ut_unit* unit; char buf[80]; int nchar; CU_ASSERT_PTR_NOT_NULL(bel_1_mW); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(bel_1_mW, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "lg(re 0.001 kg.m2.s-3)"); decibel_1_mW = ut_scale(0.1, bel_1_mW); CU_ASSERT_PTR_NOT_NULL(decibel_1_mW); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(decibel_1_mW, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "0.1 lg(re 0.001 kg.m2.s-3)"); unit = ut_log(-10, milliwatt); CU_ASSERT_PTR_NULL(unit); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); cubicMeter = ut_raise(meter, 3); unit = ut_scale(1e-6, meter); cubicMicron = ut_raise(unit, 3); ut_free(unit); CU_ASSERT_PTR_NOT_NULL(cubicMicron); BZ = ut_log(10, cubicMicron); CU_ASSERT_PTR_NOT_NULL(BZ); CU_ASSERT_EQUAL(ut_is_dimensionless(BZ), 1); CU_ASSERT_PTR_NULL(ut_raise(BZ, 2)); CU_ASSERT_EQUAL(ut_get_status(), UT_MEANINGLESS); dBZ = ut_scale(0.1, BZ); CU_ASSERT_PTR_NOT_NULL(dBZ); CU_ASSERT_EQUAL(ut_get_status(), UT_SUCCESS); nchar = ut_format(dBZ, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_TRUE(strcmp(buf, "0.1 lg(re 1e-18 m3)") == 0 || strcmp(buf, "0.1 lg(re 1e-018 m3)") == 0); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("dBZ", UT_ASCII, dBZ), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("dBZ", UT_ASCII, dBZ), UT_SUCCESS); CU_ASSERT_EQUAL(ut_map_symbol_to_unit("dBZ", UT_ASCII, meter), UT_EXISTS); { ut_unit* unit = ut_get_unit_by_symbol(unitSystem, "dBZ"); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, dBZ), 0); CU_ASSERT_PTR_NULL(ut_get_unit_by_symbol(unitSystem, "DBZ")); ut_free(unit); } ut_free(milliwatt); ut_free(bel_1_mW); ut_free(decibel_1_mW); CU_ASSERT_PTR_NULL(ut_log(2, NULL)); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); CU_ASSERT_PTR_NULL(ut_log(1, meter)); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); CU_ASSERT_PTR_NULL(ut_multiply(dBZ, meter)); unit = ut_multiply(dBZ, radian); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, dBZ), 0); ut_free(unit); CU_ASSERT_PTR_NULL(ut_multiply(dBZ, dBZ)); } static int areCloseFloats( float x, float y) { int areClose; if (x == 0 || y == 0) { areClose = fabs(x - y) < 1000*FLT_EPSILON; } else { areClose = fabs(1.0 - x / y) < 1000*FLT_EPSILON; } return areClose; } static int areCloseDoubles( double x, double y) { int areClose; if (x == 0 || y == 0) { areClose = fabs(x - y) < 1000*DBL_EPSILON; } else { areClose = fabs(1.0 - x / y) < 1000*DBL_EPSILON; } return areClose; } static void test_utGetDimensionlessUnitOne(void) { CU_ASSERT_PTR_NOT_NULL(ut_get_dimensionless_unit_one(unitSystem)); CU_ASSERT_PTR_NULL(ut_get_dimensionless_unit_one(NULL)); } static void test_utGetSystem(void) { CU_ASSERT_PTR_NOT_NULL(ut_get_system(meter)); CU_ASSERT_PTR_NULL(ut_get_system(NULL)); } static void test_utSameSystem(void) { ut_system* system; CU_ASSERT_EQUAL(ut_same_system(meter, kilogram), 1); CU_ASSERT_EQUAL(ut_same_system(NULL, kilogram), 0); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); CU_ASSERT_EQUAL(ut_same_system(kilogram, NULL), 0); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); system = ut_new_system(); CU_ASSERT_PTR_NOT_NULL(system); CU_ASSERT_EQUAL(ut_same_system(meter, ut_get_dimensionless_unit_one(system)), 0); ut_free_system(system); } static void test_utIsDimensionless(void) { ut_unit* unit; CU_ASSERT_EQUAL(ut_is_dimensionless(meter), 0); CU_ASSERT_EQUAL(ut_is_dimensionless(radian), 1); CU_ASSERT_EQUAL(ut_is_dimensionless(secondsSinceTheEpoch), 0); CU_ASSERT_EQUAL(ut_is_dimensionless(NULL), 0); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); unit = ut_raise(radian, 2); CU_ASSERT_EQUAL(ut_is_dimensionless(unit), 1); ut_free(unit); } static void test_utClone(void) { ut_unit* unit; unit = ut_clone(secondsSinceTheEpoch); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_are_convertible(unit, secondsSinceTheEpoch), 1); ut_free(unit); CU_ASSERT_PTR_NULL(ut_clone(NULL)); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); } static void test_utAreConvertible(void) { ut_unit* unit; CU_ASSERT_EQUAL(ut_are_convertible(meter, meter), 1); CU_ASSERT_EQUAL(ut_are_convertible(radian, radian), 1); CU_ASSERT_EQUAL(ut_are_convertible(radian, meter), 0); CU_ASSERT_EQUAL(ut_are_convertible(cubicMicron, cubicMicron), 1); CU_ASSERT_EQUAL(ut_are_convertible(cubicMicron, cubicMeter), 1); CU_ASSERT_EQUAL(ut_are_convertible(watt, watt), 1); CU_ASSERT_EQUAL(ut_are_convertible(watt, cubicMicron), 0); CU_ASSERT_EQUAL(ut_are_convertible(cubicMicron, watt), 0); CU_ASSERT_EQUAL(ut_are_convertible(secondsSinceTheEpoch, secondsSinceTheEpoch), 1); CU_ASSERT_EQUAL(ut_are_convertible(secondsSinceTheEpoch, second), 0); CU_ASSERT_EQUAL(ut_are_convertible(joulePerKilogram, meterSquaredPerSecondSquared), 1); CU_ASSERT_EQUAL(ut_are_convertible(joulePerKilogram, meterPerSecondSquared), 0); unit = ut_raise(radian, 2); CU_ASSERT_EQUAL(ut_are_convertible(radian, unit), 1); ut_free(unit); CU_ASSERT_EQUAL(ut_are_convertible(NULL, meter), 0); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); } static void test_utGetConverter(void) { cv_converter* converter = ut_get_converter(meter, meter); double doubles[2]; float floats[2]; CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_EQUAL(cv_convert_double(converter, 1.0), 1.0); floats[0] = 1; floats[1] = 2; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_EQUAL(floats[0], 1); CU_ASSERT_EQUAL(floats[1], 2); doubles[0] = 1; doubles[1] = 2; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], 1); CU_ASSERT_EQUAL(doubles[1], 2); CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_EQUAL(floats[1], 1); CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_EQUAL(doubles[1], 1); floats[0] = 1; floats[1] = 2; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_EQUAL(floats[0], 2); doubles[0] = 1; doubles[1] = 2; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], 2); cv_free(converter); converter = ut_get_converter(radian, radian); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_EQUAL(cv_convert_double(converter, 1.0), 1.0); cv_free(converter); converter = ut_get_converter(meter, radian); CU_ASSERT_PTR_NULL(converter); converter = ut_get_converter(meter, kelvin); CU_ASSERT_PTR_NULL(converter); converter = ut_get_converter(meter, celsius); CU_ASSERT_PTR_NULL(converter); converter = ut_get_converter(meter, fahrenheit); CU_ASSERT_PTR_NULL(converter); converter = ut_get_converter(meter, dBZ); CU_ASSERT_PTR_NULL(converter); converter = ut_get_converter(dBZ, radian); CU_ASSERT_PTR_NULL(converter); converter = ut_get_converter(kilometer, kilometer); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_EQUAL(cv_convert_double(converter, 1.0), 1.0); cv_free(converter); converter = ut_get_converter(meter, kilometer); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 1000.0), 1.0)); floats[0] = 0; floats[1] = 1000; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_EQUAL(floats[0], 0); CU_ASSERT_EQUAL(floats[1], 1); doubles[0] = 0; doubles[1] = 1000; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], 0); CU_ASSERT_EQUAL(doubles[1], 1); floats[0] = 0; floats[1] = 1000; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_EQUAL(floats[1], 0); doubles[0] = 0; doubles[1] = 1000; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_EQUAL(doubles[1], 0); floats[0] = 0; floats[1] = 1000; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_EQUAL(floats[0], 1); doubles[0] = 0; doubles[1] = 1000; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], 1); cv_free(converter); converter = ut_get_converter(kilometer, meter); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_EQUAL(cv_convert_double(converter, 1.0), 1000.0); floats[0] = 0; floats[1] = 1; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_EQUAL(floats[0], 0); CU_ASSERT_EQUAL(floats[1], 1000); doubles[0] = 0; doubles[1] = 1; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], 0); CU_ASSERT_EQUAL(doubles[1], 1000); floats[0] = 0; floats[1] = 1; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_EQUAL(floats[1], 0); doubles[0] = 0; doubles[1] = 1; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_EQUAL(doubles[1], 0); floats[0] = 0; floats[1] = 1; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_EQUAL(floats[0], 1000); doubles[0] = 0; doubles[1] = 1; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], 1000); cv_free(converter); converter = ut_get_converter(kelvin, celsius); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_EQUAL(cv_convert_double(converter, 273.15), 0.0); floats[0] = 0; floats[1] = 273.15; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], -273.15)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 0)); doubles[0] = 0; doubles[1] = 273.15; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], -273.15); CU_ASSERT_EQUAL(doubles[1], 0); floats[0] = 0; floats[1] = 273.15; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_TRUE(areCloseFloats(floats[1], -273.15)); doubles[0] = 0; doubles[1] = 273.15; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_EQUAL(doubles[1], -273.15); floats[0] = 0; floats[1] = 273.15; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 0)); doubles[0] = 0; doubles[1] = 273.15; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], 0); cv_free(converter); converter = ut_get_converter(celsius, kelvin); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_EQUAL(cv_convert_double(converter, 0.0), 273.15); floats[0] = 0; floats[1] = -273.15; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 273.15)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 0)); doubles[0] = 0; doubles[1] = -273.15; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], 273.15); CU_ASSERT_EQUAL(doubles[1], 0); floats[0] = 0; floats[1] = -273.15; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_TRUE(areCloseFloats(floats[1], 273.15)); doubles[0] = 0; doubles[1] = -273.15; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_EQUAL(doubles[1], 273.15); floats[0] = 0; floats[1] = -273.15; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 0)); doubles[0] = 0; doubles[1] = -273.15; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_EQUAL(doubles[0], 0); cv_free(converter); converter = ut_get_converter(celsius, fahrenheit); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 0.0), 32)); floats[0] = 0; floats[1] = 100; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 32)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 212)); doubles[0] = 0; doubles[1] = 100; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 32)); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 212)); floats[0] = 0; floats[1] = 100; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_TRUE(areCloseFloats(floats[1], 32)); doubles[0] = 0; doubles[1] = 100; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 32)); floats[0] = 0; floats[1] = 100; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 212)); doubles[0] = 0; doubles[1] = 100; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 212)); cv_free(converter); converter = ut_get_converter(fahrenheit, celsius); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 32.0), 0.0)); floats[0] = 32; floats[1] = 212; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 0)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 100)); doubles[0] = 32; doubles[1] = 212; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 0)); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 100)); floats[0] = 32; floats[1] = 212; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_TRUE(areCloseFloats(floats[1], 0)); doubles[0] = 32; doubles[1] = 212; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 0)); floats[0] = 32; floats[1] = 212; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 100)); doubles[0] = 32; doubles[1] = 212; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 100)); cv_free(converter); converter = ut_get_converter(cubicMeter, dBZ); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 1e-18), 0.0)); cv_free(converter); converter = ut_get_converter(cubicMicron, dBZ); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 1000), 30.0)); floats[0] = 10; floats[1] = 1000; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 10)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 30)); doubles[0] = 10; doubles[1] = 1000; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 10)); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 30)); floats[0] = 10; floats[1] = 1000; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_TRUE(areCloseFloats(floats[1], 10)); doubles[0] = 10; doubles[1] = 1000; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 10)); floats[0] = 10; floats[1] = 1000; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 30)); doubles[0] = 10; doubles[1] = 1000; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 30)); cv_free(converter); converter = ut_get_converter(dBZ, cubicMicron); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseFloats(cv_convert_float(converter, 10), 10.0)); CU_ASSERT_TRUE(areCloseFloats(cv_convert_float(converter, 30), 1000.0)); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 10), 10.0)); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 30), 1000.0)); floats[0] = 10; floats[1] = 30; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 10)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 1000)); doubles[0] = 10; doubles[1] = 30; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 10)); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 1000)); floats[0] = 10; floats[1] = 30; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_TRUE(areCloseFloats(floats[1], 10)); doubles[0] = 10; doubles[1] = 30; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 10)); floats[0] = 10; floats[1] = 30; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 1000)); doubles[0] = 10; doubles[1] = 30; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 1000)); cv_free(converter); converter = ut_get_converter(second, hertz); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseFloats(cv_convert_float(converter, 1.0), 1.0)); CU_ASSERT_TRUE(areCloseFloats(cv_convert_float(converter, 5.0), 1/5.0)); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 1.0), 1.0)); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 5.0), 1/5.0)); floats[0] = 1; floats[1] = 5; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 1.0)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 1.0/5)); doubles[0] = 1; doubles[1] = 5; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 1)); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 1.0/5)); cv_free(converter); converter = ut_get_converter(second, megahertz); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseFloats(cv_convert_float(converter, 1), 1e-6)); CU_ASSERT_TRUE(areCloseFloats(cv_convert_float(converter, 1e-6), 1.0)); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 1), 1e-6)); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 1e-6), 1.0)); floats[0] = 1; floats[1] = 1e-6; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 1e-6)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 1)); doubles[0] = 1; doubles[1] = 1e-6; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 1e-6)); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 1)); cv_free(converter); converter = ut_get_converter(secondsSinceTheEpoch, minutesSinceTheMillenium); CU_ASSERT_PTR_NOT_NULL(converter); cv_free(converter); CU_ASSERT_PTR_NULL(ut_get_converter(NULL, meter)); CU_ASSERT_PTR_NULL(ut_get_converter(meter, NULL)); } static void test_utOffsetByTime(void) { char buf[80]; int nchar; cv_converter* converter; ut_unit* day; ut_unit* daysSinceTheEpoch; double doubles[2]; float floats[2]; secondsSinceTheEpoch = ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0)); CU_ASSERT_PTR_NOT_NULL(secondsSinceTheEpoch); nchar = ut_format(secondsSinceTheEpoch, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "s @ 19700101T000000.0000000 UTC"); minutesSinceTheMillenium = ut_offset_by_time(minute, ut_encode_time(2001, 1, 1, 0, 0, 0)); CU_ASSERT_PTR_NOT_NULL(minutesSinceTheMillenium); nchar = ut_format(secondsSinceTheEpoch, buf, sizeof(buf)-1, asciiNameDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "second since 1970-01-01 00:00:00.0000000 UTC"); converter = ut_get_converter(secondsSinceTheEpoch, secondsSinceTheEpoch); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 1000), 1000)); floats[0] = 0; floats[1] = 1000; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 0)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 1000)); doubles[0] = 0; doubles[1] = 1000; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 0)); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 1000)); floats[0] = 0; floats[1] = 1000; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_TRUE(areCloseFloats(floats[1], 0)); doubles[0] = 0; doubles[1] = 1000; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 0)); floats[0] = 0; floats[1] = 1000; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 1000)); doubles[0] = 0; doubles[1] = 1000; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 1000)); cv_free(converter); day = ut_scale(86400, second); CU_ASSERT_PTR_NOT_NULL_FATAL(day); daysSinceTheEpoch = ut_offset_by_time(day, ut_encode_time(1970, 1, 1, 0, 0, 0)); ut_free(day); CU_ASSERT_PTR_NOT_NULL_FATAL(daysSinceTheEpoch); nchar = ut_format(daysSinceTheEpoch, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "(86400 s) @ 19700101T000000.0000000 UTC"); converter = ut_get_converter(secondsSinceTheEpoch, daysSinceTheEpoch); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 86400), 1)); floats[0] = 0; floats[1] = 86400; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 0)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 1)); doubles[0] = 0; doubles[1] = 86400; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 0)); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 1)); floats[0] = 0; floats[1] = 86400; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_TRUE(areCloseFloats(floats[1], 0)); doubles[0] = 0; doubles[1] = 86400; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 0)); floats[0] = 0; floats[1] = 86400; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 1)); doubles[0] = 0; doubles[1] = 86400; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 1)); cv_free(converter); converter = ut_get_converter(daysSinceTheEpoch, secondsSinceTheEpoch); CU_ASSERT_PTR_NOT_NULL(converter); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 1), 86400)); floats[0] = 0; floats[1] = 1; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 2, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 0)); CU_ASSERT_TRUE(areCloseFloats(floats[1], 86400)); doubles[0] = 0; doubles[1] = 1; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 2, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 0)); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 86400)); floats[0] = 0; floats[1] = 1; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats, 1, floats+1), floats+1); CU_ASSERT_TRUE(areCloseFloats(floats[1], 0)); doubles[0] = 0; doubles[1] = 1; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles, 1, doubles+1), doubles+1); CU_ASSERT_TRUE(areCloseDoubles(doubles[1], 0)); floats[0] = 0; floats[1] = 1; CU_ASSERT_EQUAL(cv_convert_floats(converter, floats+1, 1, floats), floats); CU_ASSERT_TRUE(areCloseFloats(floats[0], 86400)); doubles[0] = 0; doubles[1] = 1; CU_ASSERT_EQUAL(cv_convert_doubles(converter, doubles+1, 1, doubles), doubles); CU_ASSERT_TRUE(areCloseDoubles(doubles[0], 86400)); cv_free(converter); ut_free(daysSinceTheEpoch); CU_ASSERT_PTR_NULL(ut_offset_by_time(NULL, ut_encode_time(0, 0, 0, 0, 0, 0))); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); } static void test_ut_decode_time(void) { double timeval = ut_encode_time(2001, 1, 1, 0, 0, 0); int year1, month1, day1, hour1, minute1; int year2, month2, day2, hour2, minute2; double second1, resolution1; double second2, resolution2; ut_unit* unit; ut_decode_time(timeval, &year1, &month1, &day1, &hour1, &minute1, &second1, &resolution1); unit = ut_parse(unitSystem, "second since 2010-01-11T09:08:10Z", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); ut_decode_time(timeval, &year2, &month2, &day2, &hour2, &minute2, &second2, &resolution2); CU_ASSERT_EQUAL(year1, year2); CU_ASSERT_EQUAL(month1, month2); CU_ASSERT_EQUAL(day1, day2); CU_ASSERT_EQUAL(hour1, hour2); CU_ASSERT_EQUAL(minute1, minute2); CU_ASSERT_EQUAL(second1, second2); CU_ASSERT_EQUAL(resolution1, resolution2); } static void test_utSetEncoding(void) { char buf[80]; int nchar; nchar = ut_format(watt, buf, sizeof(buf)-1, asciiSymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "kg.m2.s-3"); nchar = ut_format(watt, buf, sizeof(buf)-1, latin1SymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "m\xb2\xb7kg/s\xb3"); nchar = ut_format(watt, buf, sizeof(buf)-1, utf8SymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "kg\xc2\xb7m\xc2\xb2\xc2\xb7s\xe2\x81\xbb\xc2\xb3"); nchar = ut_format(wattSquared, buf, sizeof(buf)-1, utf8SymbolDef); CU_ASSERT_TRUE_FATAL(nchar > 0); CU_ASSERT_TRUE_FATAL(nchar < sizeof(buf)); buf[nchar] = 0; CU_ASSERT_STRING_EQUAL(buf, "kg\xc2\xb2\xc2\xb7m\xe2\x81\xb4\xc2\xb7s\xe2\x81\xbb\xe2\x81\xb6"); /* kg2.m4.s-6 */ } static void test_utCompare(void) { CU_ASSERT_NOT_EQUAL(ut_compare(kilogram, meter), 0); CU_ASSERT_NOT_EQUAL(ut_compare(meter, radian), 0); CU_ASSERT_NOT_EQUAL(ut_compare(radian, kelvin), 0); CU_ASSERT_NOT_EQUAL(ut_compare(kelvin, second), 0); CU_ASSERT_NOT_EQUAL(ut_compare(second, minute), 0); CU_ASSERT_NOT_EQUAL(ut_compare(minute, kilometer), 0); CU_ASSERT_NOT_EQUAL(ut_compare(kilometer, rankine), 0); CU_ASSERT_NOT_EQUAL(ut_compare(rankine, celsius), 0); CU_ASSERT_NOT_EQUAL(ut_compare(celsius, fahrenheit), 0); CU_ASSERT_NOT_EQUAL(ut_compare(fahrenheit, watt), 0); CU_ASSERT_NOT_EQUAL(ut_compare(watt, cubicMicron), 0); CU_ASSERT_NOT_EQUAL(ut_compare(BZ, cubicMicron), 0); CU_ASSERT_NOT_EQUAL(ut_compare(cubicMicron, dBZ), 0); CU_ASSERT_NOT_EQUAL(ut_compare(dBZ, secondsSinceTheEpoch), 0); CU_ASSERT_NOT_EQUAL(ut_compare(secondsSinceTheEpoch, hertz), 0); CU_ASSERT_NOT_EQUAL(ut_compare(hertz, megahertz), 0); CU_ASSERT_NOT_EQUAL(ut_compare(megahertz, kilogram), 0); CU_ASSERT_NOT_EQUAL(ut_compare(dBZ, meter), 0); CU_ASSERT_EQUAL(ut_compare(NULL, meter), -1); CU_ASSERT_EQUAL(ut_compare(NULL, NULL), 0); CU_ASSERT_EQUAL(ut_compare(meter, NULL), 1); } static void test_parsing(void) { ut_unit* unit; char* spec; spec = "34 quatloos"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NULL(unit); CU_ASSERT_EQUAL(ut_get_status(), UT_UNKNOWN); spec = "$&/^"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NULL(unit); CU_ASSERT_EQUAL(ut_get_status(), UT_UNKNOWN); unit = ut_parse(unitSystem, NULL, UT_ASCII); CU_ASSERT_PTR_NULL(unit); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); unit = ut_parse(NULL, "kg", UT_ASCII); CU_ASSERT_PTR_NULL(unit); CU_ASSERT_EQUAL(ut_get_status(), UT_BAD_ARG); spec = "m"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, meter), 0); ut_free(unit); spec = "kg.m"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); spec = "kg m"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); spec = "1/s"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, hertz), 0); ut_free(unit); spec = "kg.m2.s-3"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, watt), 0); ut_free(unit); spec = "kg.m2/s3"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, watt), 0); ut_free(unit); spec = "s-3.m2.kg"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, watt), 0); ut_free(unit); spec = "(kg.m2/s3)"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, watt), 0); ut_free(unit); spec = "(kg.m2/s3)^1"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, watt), 0); ut_free(unit); spec = "kg.(m/s)^2.s-1"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, watt), 0); ut_free(unit); spec = "1000 m"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, kilometer), 0); ut_free(unit); spec = "(1000)(m)"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, kilometer), 0); ut_free(unit); spec = "(K/1.8) @ 459.67"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_EQUAL(ut_are_convertible(unit, fahrenheit), 1); ut_free(unit); spec = "METER"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, meter), 0); ut_free(unit); spec = "s @ 19700101T000000"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "s@19700101T000000 UTC"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "s@19700101T000000Z"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "s@19700101T000000 Z"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "s @ 1970-01-01 00:00:00"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "s @ 1970-01-01T00:00:00"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "s@1970-01-01T00:00:00Z"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "s @ 1970-01-01T00:00:00Z"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "second@1970-01-01T00:00:00Z"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "second @ 1970-01-01T00:00:00Z"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "second since 1970-01-01T00:00:00Z"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, secondsSinceTheEpoch), 0); ut_free(unit); spec = "kg\xb7m\xb2/s\xb3"; /* "kg" mid-dot "m" squared "/" "s" cubed */ unit = ut_parse(unitSystem, spec, UT_LATIN1); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, watt), 0); ut_free(unit); spec = "(kg)(m)^2/(s)^3"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, watt), 0); ut_free(unit); spec = "kg\xc2\xb7m\xc2\xb2/s\xc2\xb3"; unit = ut_parse(unitSystem, spec, UT_UTF8); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, watt), 0); ut_free(unit); spec = "0.1 lg(re (1e-6 m)^3)"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, dBZ), 0); ut_free(unit); { char buf[] = " (K/1.8) @ 459.67 "; (void)ut_trim(buf, UT_ASCII); unit = ut_parse(unitSystem, buf, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_are_convertible(unit, fahrenheit), 1); ut_free(unit); } spec = "1"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(ut_get_dimensionless_unit_one(unitSystem), unit), 0); ut_free(unit); spec = "3.141592653589793238462643383279"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); spec = ""; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(ut_get_dimensionless_unit_one(unitSystem), unit), 0); ut_free(unit); spec = "km"; unit = ut_parse(unitSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(kilometer, unit), 0); ut_free(unit); spec = "\xb5m"; /* mu "m" */ unit = ut_parse(unitSystem, spec, UT_LATIN1); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, micron), 0); ut_free(unit); spec = "\xb5megaHz"; /* mu "megaHz" */ unit = ut_parse(unitSystem, spec, UT_LATIN1); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, hertz), 0); ut_free(unit); spec = "MeGa\xb5Hertz"; /* "MeGa" mu "Hertz" */ unit = ut_parse(unitSystem, spec, UT_LATIN1); CU_ASSERT_PTR_NOT_NULL(unit); CU_ASSERT_EQUAL(ut_compare(unit, hertz), 0); ut_free(unit); spec = "meter @ 100 @ 10"; unit = ut_parse(unitSystem, spec, UT_LATIN1); CU_ASSERT_PTR_NULL(unit); CU_ASSERT_EQUAL(ut_get_status(), UT_SYNTAX); } static void test_visitor(void) { CU_ASSERT_EQUAL(ut_accept_visitor(NULL, NULL, NULL), UT_BAD_ARG); } static void test_xml(void) { ut_system* xmlSystem; glob_t files; int status; ut_unit* unit1; ut_unit* unit2; cv_converter* converter; char* spec; ut_unit* unit; ut_set_error_message_handler(ut_write_to_stderr); xmlSystem = ut_read_xml(xmlPath); CU_ASSERT_PTR_NOT_NULL_FATAL(xmlSystem); spec = "seconds@1970-01-01T00:00:00Z"; unit = ut_parse(xmlSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); spec = "seconds @ 1970-01-01T00:00:00Z"; unit = ut_parse(xmlSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); spec = "seconds since 1970-01-01T00:00:00Z"; unit = ut_parse(xmlSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); spec = "seconds since 1970-01-01T00:00:00Z"; unit = ut_parse(xmlSystem, spec, UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit); ut_free(unit); unit1 = ut_get_unit_by_symbol(unitSystem, "\xb0K"); /* Latin-1 degree sym */ CU_ASSERT_PTR_NOT_NULL(unit1); CU_ASSERT_EQUAL(ut_compare(unit1, kelvin), 0); ut_free(unit1); unit1 = ut_parse(xmlSystem, "\xb0K", UT_LATIN1); /* degree sign */ CU_ASSERT_PTR_NOT_NULL(unit1); unit2 = ut_parse(xmlSystem, "K", UT_LATIN1); CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit1); unit1 = ut_parse(xmlSystem, "\xc2\xb5K", UT_UTF8); /* "mu" character */ CU_ASSERT_PTR_NOT_NULL(unit1); converter = ut_get_converter(unit1, unit2); CU_ASSERT_PTR_NOT_NULL_FATAL(converter); CU_ASSERT_TRUE(areCloseDoubles(cv_convert_double(converter, 1e6), 1.0)); cv_free(converter); ut_free(unit1); ut_free(unit2); unit1 = ut_parse(xmlSystem, "arc_degree", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit1); unit2 = ut_parse(xmlSystem, "arc""\xA0""degree", UT_LATIN1); /* NBSP */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); unit2 = ut_parse(xmlSystem, "\xB0", UT_LATIN1); /* degree sign */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); unit2 = ut_parse(xmlSystem, "\xC2\xB0", UT_UTF8); /* degree sign */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); ut_free(unit1); unit1 = ut_parse(xmlSystem, "arc_minute", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit1); unit2 = ut_parse(xmlSystem, "arc""\xA0""minute", UT_LATIN1); /* NBSP */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); unit2 = ut_parse(xmlSystem, "'", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); unit2 = ut_parse(xmlSystem, "\xE2\x80\xB2", UT_UTF8); /* PRIME */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); ut_free(unit1); unit1 = ut_parse(xmlSystem, "arc_second", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit1); unit2 = ut_parse(xmlSystem, "arc""\xA0""second", UT_LATIN1); /* NBSP */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); unit2 = ut_parse(xmlSystem, "\"", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); unit2 = ut_parse(xmlSystem, "\xE2\x80\xB3", UT_UTF8); /* DOUBLE PRIME */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); ut_free(unit1); unit1 = ut_parse(xmlSystem, "ohm", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit1); unit2 = ut_parse(xmlSystem, "\xCE\xA9", UT_UTF8); /* UPPER CASE OMEGA */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); unit2 = ut_parse(xmlSystem, "\xE2\x84\xA6", UT_UTF8); /* OHM SIGN */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); ut_free(unit1); unit1 = ut_parse(xmlSystem, "degree_celsius", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit1); unit2 = ut_parse(xmlSystem, "degree""\xA0""celsius", UT_LATIN1);/* NBSP */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); unit2 = ut_parse(xmlSystem, "\xB0""C", UT_LATIN1); /* degree sign */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); unit2 = ut_parse(xmlSystem, "\xE2\x84\x83", UT_UTF8); /* DEGREE CELSIUS */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); ut_free(unit1); unit1 = ut_parse(xmlSystem, "angstrom", UT_ASCII); CU_ASSERT_PTR_NOT_NULL(unit1); unit2 = ut_parse(xmlSystem, "\xe5ngstr\xf6m", UT_LATIN1);/* small A with ring */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); #if 0 unit2 = ut_parse(xmlSystem, "\xc5ngstr\xf6m", UT_LATIN1);/* capital A with ring */ CU_ASSERT_PTR_NOT_NULL(unit2); CU_ASSERT_EQUAL(ut_compare(unit1, unit2), 0); ut_free(unit2); #endif ut_free(unit1); ut_free_system(xmlSystem); ut_set_error_message_handler(ut_ignore); xmlSystem = ut_read_xml(NULL); if (xmlSystem == NULL) { CU_ASSERT_EQUAL(ut_get_status(), getenv("UDUNITS2_XML_PATH") == NULL ? UT_OPEN_DEFAULT : UT_OPEN_ENV); } else { ut_free_system(xmlSystem); } xmlSystem = ut_read_xml("xmlFailure/noExist.xml"); CU_ASSERT_PTR_NULL(xmlSystem); CU_ASSERT_EQUAL(ut_get_status(), UT_OPEN_ARG); status = glob("xmlFailure/*.xml", 0, NULL, &files); if (status != 0 && status != GLOB_NOMATCH) { CU_ASSERT_TRUE(0); } else { size_t i; for (i = 0; i < files.gl_pathc; ++i) { xmlSystem = ut_read_xml(files.gl_pathv[i]); CU_ASSERT(xmlSystem == NULL); if (xmlSystem == NULL) { CU_ASSERT(ut_get_status() == UT_PARSE); if (ut_get_status() != UT_PARSE) (void)fprintf(stderr, "File didn't fail: \"%s\"\n", files.gl_pathv[i]); } else { (void)fprintf(stderr, "File didn't fail: \"%s\"\n", files.gl_pathv[i]); ut_free_system(xmlSystem); } } } globfree(&files); ut_set_error_message_handler(ut_write_to_stderr); status = glob("xmlSuccess/*.xml", 0, NULL, &files); if (status != 0 && status != GLOB_NOMATCH) { CU_ASSERT_TRUE(0); } else { size_t i; for (i = 0; i < files.gl_pathc; ++i) { xmlSystem = ut_read_xml(files.gl_pathv[i]); CU_ASSERT_PTR_NOT_NULL(xmlSystem); if (xmlSystem != NULL) { ut_free_system(xmlSystem); } else { (void)fprintf(stderr, "File failed: \"%s\"\n", files.gl_pathv[i]); } } } globfree(&files); /* * Test again to ensure any persistent state doesn't interfere. */ ut_set_error_message_handler(ut_ignore); xmlSystem = ut_read_xml(xmlPath); CU_ASSERT_PTR_NOT_NULL(xmlSystem); ut_free_system(xmlSystem); } int main( const int argc, const char* const* argv) { int exitCode = EXIT_FAILURE; xmlPath = argv[1] ? argv[1] : getenv("UDUNITS2_XML_PATH"); if (CU_initialize_registry() == CUE_SUCCESS) { CU_Suite* testSuite = CU_add_suite(__FILE__, setup, teardown); if (testSuite != NULL) { CU_ADD_TEST(testSuite, test_unitSystem); CU_ADD_TEST(testSuite, test_utNewBaseUnit); CU_ADD_TEST(testSuite, test_utNewDimensionlessUnit); CU_ADD_TEST(testSuite, test_utGetUnitByName); CU_ADD_TEST(testSuite, test_utGetUnitBySymbol); CU_ADD_TEST(testSuite, test_utAddNamePrefix); CU_ADD_TEST(testSuite, test_utAddSymbolPrefix); CU_ADD_TEST(testSuite, test_utMapNameToUnit); CU_ADD_TEST(testSuite, test_utMapSymbolToUnit); CU_ADD_TEST(testSuite, test_utScale); CU_ADD_TEST(testSuite, test_utOffset); CU_ADD_TEST(testSuite, test_utOffsetByTime); CU_ADD_TEST(testSuite, test_ut_decode_time); CU_ADD_TEST(testSuite, test_utMultiply); CU_ADD_TEST(testSuite, test_utInvert); CU_ADD_TEST(testSuite, test_utDivide); CU_ADD_TEST(testSuite, test_utRaise); CU_ADD_TEST(testSuite, test_utRoot); CU_ADD_TEST(testSuite, test_utLog); CU_ADD_TEST(testSuite, test_utMapUnitToName); CU_ADD_TEST(testSuite, test_utGetName); CU_ADD_TEST(testSuite, test_utGetSymbol); CU_ADD_TEST(testSuite, test_utToString); CU_ADD_TEST(testSuite, test_utGetDimensionlessUnitOne); CU_ADD_TEST(testSuite, test_utGetSystem); CU_ADD_TEST(testSuite, test_utSameSystem); CU_ADD_TEST(testSuite, test_utIsDimensionless); CU_ADD_TEST(testSuite, test_utClone); CU_ADD_TEST(testSuite, test_utAreConvertible); CU_ADD_TEST(testSuite, test_utGetConverter); CU_ADD_TEST(testSuite, test_utSetEncoding); CU_ADD_TEST(testSuite, test_utCompare); CU_ADD_TEST(testSuite, test_parsing); CU_ADD_TEST(testSuite, test_visitor); CU_ADD_TEST(testSuite, test_xml); /* */ ut_set_error_message_handler(ut_ignore); if (CU_basic_run_tests() == CUE_SUCCESS) { if (CU_get_number_of_tests_failed() == 0) exitCode = EXIT_SUCCESS; } } CU_cleanup_registry(); } return exitCode; } udunits-2.2.0/lib/test_decode_time.c0000644000175000017500000000366512260406756020574 0ustar amckinstryamckinstry#include #include "udunits2.h" #include #define BUFLEN 1024 int main( int argc, char *argv[] ) { int year, month, day, hour, minute; double second, resolution; double tval; ut_system *unitSystem; ut_unit *utu1; /* Initialize unit system */ unitSystem = ut_read_xml(NULL); if( unitSystem == NULL ) { fprintf( stderr, "error initializing unit system\n" ); exit(-1); } /* Decode a time value of 0, print its date */ tval = 0.0; ut_decode_time( tval, &year, &month, &day, &hour, &minute, &second, &resolution ); /*printf( "decoding time location A: tval=%lf %d/%d/%d %d:%d:%06.3lf\n", tval, year, month, day, hour, minute, second );*/ printf( "decoding time location A: tval=%f %d/%d/%d %d:%d:%06.3f\n", tval, year, month, day, hour, minute, second ); /* Repeat just to make sure */ ut_decode_time( tval, &year, &month, &day, &hour, &minute, &second, &resolution ); /*printf( "decoding time location B: tval=%lf %d/%d/%d %d:%d:%06.3lf\n", tval, year, month, day, hour, minute, second );*/ printf( "decoding time location B: tval=%f %d/%d/%d %d:%d:%06.3f\n", tval, year, month, day, hour, minute, second ); /* Parse a timestamp string */ utu1 = ut_parse( unitSystem, "days since 2010-01-08 11:44", UT_ASCII ); if( utu1 == NULL ) { fprintf( stderr, "Error parsing unit string with current date\n" ); exit(-1); } /* Repeat decoding a time value of 0, print its date */ tval = 0.0; ut_decode_time( tval, &year, &month, &day, &hour, &minute, &second, &resolution ); /*printf( "decoding time location B: tval=%lf %d/%d/%d %d:%d %lf\n", tval, year, month, day, hour, minute, second );*/ printf( "decoding time location C: tval=%f %d/%d/%d %d:%d:%06.3f\n", tval, year, month, day, hour, minute, second ); return(0); } udunits-2.2.0/lib/idToUnitMap.h0000644000175000017500000000116112260406756017463 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ #ifndef UT_ID_TO_UNIT_MAP_H_INCLUDED #define UT_ID_TO_UNIT_MAP_H_INCLUDED #include "udunits2.h" #ifdef __cplusplus extern "C" { #endif /* * Frees resources associated with a unit-system. * * Arguments: * system Pointer to the unit-system to have its associated * resources freed. */ void itumFreeSystem( ut_system* system); #ifdef __cplusplus } #endif #endif udunits-2.2.0/lib/udunits2-accepted.xml0000644000175000017500000001552412260406756021172 0ustar amckinstryamckinstry 60 s minute min 60 min hour h hr 24 h day d 3.141592653589793238462643383279 pi π (pi/180) rad arc_degree ° angular_degree degree arcdeg °/60 arc_minute ' angular_minute arcminute arcmin '/60 arc_second " angular_second arcsecond arcsec dm^3 liter L litre l 1000 kg metric_ton t tonne 1.60217733e-19 J electronvolt eV electron_volt 1.6605402e-27 kg unified_atomic_mass_unit u atomic_mass_unit atomicmassunit amu 1.495979e11 m astronomical_unit ua 1852 m nautical_mile nautical_mile/hour international_knot knot_international knot 1e-10 m angstrom ångström Å dam^2 are a 100 are hectare 100 fm^2 barn b 1000 hPa bar cm/s^2 gal 3.7e10 Bq curie Ci 2.58e-4 C/kg roentgen R cSv rem udunits-2.2.0/lib/testUnits-1.c0000644000175000017500000002750112260406756017427 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include #include #include "udunits.h" static utUnit kilogram; static utUnit watt; static int setup( void) { return utInit("/foo/bar"); } static int teardown( void) { utTerm(); return 0; } static void test_utIsInit(void) { CU_ASSERT_TRUE(utIsInit()); } static void test_utScan(void) { utUnit unit; utIni(&kilogram); CU_ASSERT_EQUAL(utScan("kg", &kilogram), 0); utIni(&watt); CU_ASSERT_EQUAL(utScan("WATT", &watt), 0); utIni(&unit); CU_ASSERT_EQUAL(utScan("seconds since 1994-12-15 12:30:00 10", &unit), 0); CU_ASSERT_EQUAL(utScan("Celsius @ 100", &unit), 0); CU_ASSERT_EQUAL(utScan("34 quatloos", &unit), UT_EUNKNOWN); CU_ASSERT_EQUAL(utScan("$&/^", &unit), UT_EUNKNOWN); CU_ASSERT_EQUAL(utScan(NULL, &unit), UT_EINVALID); CU_ASSERT_EQUAL(utScan("kg", NULL), UT_EINVALID); } static void test_utCalendar(void) { utUnit unit; int year, month, day, hour, minute; float second; utIni(&unit); CU_ASSERT_EQUAL(utScan("seconds since 1994-12-15 2:29:60.0000 UTC", &unit), 0); CU_ASSERT_EQUAL( utCalendar(1, &unit, &year, &month, &day, &hour, &minute, &second), 0); CU_ASSERT_EQUAL(year, 1994); CU_ASSERT_EQUAL(month, 12); CU_ASSERT_EQUAL(day, 15); CU_ASSERT_EQUAL(hour, 2); CU_ASSERT_EQUAL(minute, 30); CU_ASSERT_EQUAL(second, 1); CU_ASSERT_EQUAL(utScan("seconds since 1925-01-01 00:00:00", &unit), 0); CU_ASSERT_EQUAL( utCalendar(1, &unit, &year, &month, &day, &hour, &minute, &second), 0); CU_ASSERT_EQUAL(year, 1925); CU_ASSERT_EQUAL(month, 1); CU_ASSERT_EQUAL(day, 1); CU_ASSERT_EQUAL(hour, 0); CU_ASSERT_EQUAL(minute, 0); CU_ASSERT_EQUAL(second, 1); } static void test_utInvCalendar(void) { utUnit unit; double value; utIni(&unit); CU_ASSERT_EQUAL(utScan("seconds since 1994-12-15 2:29:60.0000 UTC", &unit), 0); CU_ASSERT_EQUAL(utInvCalendar(1994, 12, 15, 2, 30, 1.0, &unit, &value), 0); CU_ASSERT_EQUAL(value, 1); CU_ASSERT_EQUAL(utScan("seconds since 1925-01-01 00:00:00", &unit), 0); CU_ASSERT_EQUAL(utInvCalendar(1925, 1, 1, 0, 0, 1.0, &unit, &value), 0); CU_ASSERT_EQUAL(value, 1); } static void test_utIsTime(void) { utUnit unit; utIni(&unit); CU_ASSERT_EQUAL(utScan("seconds", &unit), 0); CU_ASSERT_TRUE(utIsTime(&unit)); CU_ASSERT_EQUAL(utScan("seconds since 1925-01-01 00:00:00", &unit), 0); CU_ASSERT_TRUE(utIsTime(&unit)); CU_ASSERT_EQUAL(utScan("kg", &unit), 0); CU_ASSERT_FALSE(utIsTime(&unit)); CU_ASSERT_EQUAL(utScan("watt", &unit), 0); CU_ASSERT_FALSE(utIsTime(&unit)); CU_ASSERT_EQUAL(utScan("celsius", &unit), 0); CU_ASSERT_FALSE(utIsTime(&unit)); } static void test_utHasOrigin(void) { utUnit unit; utIni(&unit); CU_ASSERT_EQUAL(utScan("seconds", &unit), 0); CU_ASSERT_FALSE(utHasOrigin(&unit)); CU_ASSERT_EQUAL(utScan("seconds since 1925-01-01 00:00:00", &unit), 0); CU_ASSERT_TRUE(utHasOrigin(&unit)); CU_ASSERT_EQUAL(utScan("kg", &unit), 0); CU_ASSERT_FALSE(utHasOrigin(&unit)); CU_ASSERT_EQUAL(utScan("watt", &unit), 0); CU_ASSERT_FALSE(utHasOrigin(&unit)); CU_ASSERT_EQUAL(utScan("celsius", &unit), 0); CU_ASSERT_TRUE(utHasOrigin(&unit)); } static void test_utClear(void) { utUnit one; utUnit unit; double slope, intercept; utIni(&one); utIni(&unit); CU_ASSERT_EQUAL(utScan("1", &one), 0); CU_ASSERT_EQUAL(utScan("seconds", &unit), 0); CU_ASSERT_EQUAL(utConvert(&one, &unit, &slope, &intercept), UT_ECONVERT); CU_ASSERT_PTR_NOT_NULL(utClear(&unit)); CU_ASSERT_EQUAL(utConvert(&one, &unit, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_PTR_NULL(utClear(NULL)); } static void test_utCopy(void) { utUnit unit1; utUnit unit2; double slope, intercept; utIni(&unit1); utIni(&unit2); CU_ASSERT_EQUAL(utScan("seconds", &unit1), 0); CU_ASSERT_PTR_NOT_NULL(utCopy(&unit1, &unit2)); CU_ASSERT_EQUAL(utConvert(&unit1, &unit2, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_PTR_NULL(utCopy(NULL, &unit2)); CU_ASSERT_PTR_NULL(utCopy(&unit1, NULL)); } static void test_utMultiply(void) { utUnit m, s, result, expect; double slope, intercept; utIni(&m); utIni(&s); utIni(&result); utIni(&expect); CU_ASSERT_EQUAL(utScan("m", &m), 0); CU_ASSERT_EQUAL(utScan("s", &s), 0); CU_ASSERT_PTR_NOT_NULL(utMultiply(&m, &s, &result)); CU_ASSERT_EQUAL(utScan("m.s", &expect), 0); CU_ASSERT_EQUAL(utConvert(&result, &expect, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_PTR_NULL(utMultiply(NULL, &s, &result)); CU_ASSERT_PTR_NULL(utMultiply(&m, NULL, &result)); } static void test_utDivide(void) { utUnit m, s, result, expect; double slope, intercept; utIni(&m); utIni(&s); utIni(&result); utIni(&expect); CU_ASSERT_EQUAL(utScan("m", &m), 0); CU_ASSERT_EQUAL(utScan("s", &s), 0); CU_ASSERT_PTR_NOT_NULL(utDivide(&m, &s, &result)); CU_ASSERT_EQUAL(utScan("m/s", &expect), 0); CU_ASSERT_EQUAL(utConvert(&result, &expect, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_PTR_NULL(utDivide(NULL, &s, &result)); CU_ASSERT_PTR_NULL(utDivide(&m, NULL, &result)); } static void test_utInvert(void) { utUnit unit, result, expect; double slope, intercept; utIni(&unit); utIni(&result); utIni(&expect); CU_ASSERT_EQUAL(utScan("m", &unit), 0); CU_ASSERT_PTR_NOT_NULL(utInvert(&unit, &result)); CU_ASSERT_EQUAL(utScan("1/m", &expect), 0); CU_ASSERT_EQUAL(utConvert(&result, &expect, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_PTR_NULL(utInvert(NULL, &result)); } static void test_utRaise(void) { utUnit unit, result, expect; double slope, intercept; utIni(&unit); utIni(&result); utIni(&expect); CU_ASSERT_EQUAL(utScan("watt", &unit), 0); CU_ASSERT_PTR_NOT_NULL(utRaise(&unit, 2, &result)); CU_ASSERT_EQUAL(utScan("watt^2", &expect), 0); CU_ASSERT_EQUAL(utConvert(&result, &expect, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_PTR_NULL(utRaise(NULL, 2, &result)); } static void test_utShift(void) { utUnit unit, result, expect; double slope, intercept; utIni(&unit); utIni(&result); utIni(&expect); CU_ASSERT_EQUAL(utScan("kelvin", &unit), 0); CU_ASSERT_PTR_NOT_NULL(utShift(&unit, 273.15, &result)); CU_ASSERT_EQUAL(utScan("celsius", &expect), 0); CU_ASSERT_EQUAL(utConvert(&result, &expect, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_PTR_NULL(utShift(NULL, 2, &result)); } static void test_utScale(void) { utUnit unit, result, expect; double slope, intercept; utIni(&unit); utIni(&result); utIni(&expect); CU_ASSERT_EQUAL(utScan("meter", &unit), 0); CU_ASSERT_PTR_NOT_NULL(utScale(&unit, 1000, &result)); CU_ASSERT_EQUAL(utScan("kilometer", &expect), 0); CU_ASSERT_EQUAL(utConvert(&result, &expect, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_PTR_NULL(utScale(NULL, 2, &result)); } static void test_utPrint(void) { utUnit unit1, unit2; char* string; double slope, intercept; utIni(&unit1); utIni(&unit2); CU_ASSERT_EQUAL(utScan("seconds since 1994-12-15 12:30:00 10", &unit1), 0); CU_ASSERT_EQUAL(utPrint(&unit1, &string), 0); CU_ASSERT_EQUAL(utScan(string, &unit2), 0); CU_ASSERT_EQUAL(utConvert(&unit1, &unit2, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_EQUAL(utScan("seconds since 1994-12-15 2:29:60.0000 UTC", &unit1), 0); CU_ASSERT_EQUAL(utPrint(&unit1, &string), 0); CU_ASSERT_EQUAL(utScan(string, &unit2), 0); CU_ASSERT_EQUAL(utConvert(&unit1, &unit2, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_EQUAL(utScan("seconds since 1925-01-01 00:00:00", &unit1), 0); CU_ASSERT_EQUAL(utPrint(&unit1, &string), 0); CU_ASSERT_EQUAL(utScan(string, &unit2), 0); CU_ASSERT_EQUAL(utConvert(&unit1, &unit2, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_EQUAL(utScan("hours since 1-1-1 00:00:00", &unit1), 0); CU_ASSERT_EQUAL(utPrint(&unit1, &string), 0); CU_ASSERT_EQUAL(utScan(string, &unit2), 0); CU_ASSERT_EQUAL(utConvert(&unit1, &unit2, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_EQUAL(utScan("3600 s since 1-1-1 00:00:00", &unit1), 0); CU_ASSERT_EQUAL(utPrint(&unit1, &string), 0); CU_ASSERT_EQUAL(utScan(string, &unit2), 0); CU_ASSERT_EQUAL(utConvert(&unit1, &unit2, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); } static void test_utAdd(void) { utUnit kilogram; utUnit watt; utUnit unit; utUnit actual; double slope, intercept; utIni(&kilogram); utIni(&watt); utIni(&unit); utIni(&actual); CU_ASSERT_EQUAL_FATAL(utScan("kg", &kilogram), 0); CU_ASSERT_EQUAL_FATAL(utScan("watt", &watt), 0); CU_ASSERT_PTR_NOT_NULL_FATAL(utMultiply(&kilogram, &watt, &unit)); CU_ASSERT_EQUAL(utAdd("bof", 1, &unit), 0); CU_ASSERT_EQUAL_FATAL(utScan("bof", &actual), 0); CU_ASSERT_EQUAL(utConvert(&unit, &actual, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); CU_ASSERT_EQUAL_FATAL(utScan("bofs", &actual), 0); CU_ASSERT_EQUAL(utConvert(&unit, &actual, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); } static void test_utFind(void) { utUnit unit1, unit2; double slope, intercept; utIni(&unit1); utIni(&unit2); CU_ASSERT_EQUAL(utFind("watt", &unit1), 0); CU_ASSERT_EQUAL_FATAL(utScan("watt", &unit2), 0); CU_ASSERT_EQUAL(utConvert(&unit1, &unit2, &slope, &intercept), 0); CU_ASSERT_EQUAL(slope, 1); CU_ASSERT_EQUAL(intercept, 0); } int main( const int argc, const char* const* argv) { int exitCode = EXIT_FAILURE; if (CU_initialize_registry() == CUE_SUCCESS) { CU_Suite* testSuite = CU_add_suite(__FILE__, setup, teardown); if (testSuite != NULL) { CU_ADD_TEST(testSuite, test_utIsInit); CU_ADD_TEST(testSuite, test_utScan); CU_ADD_TEST(testSuite, test_utCalendar); CU_ADD_TEST(testSuite, test_utInvCalendar); CU_ADD_TEST(testSuite, test_utIsTime); CU_ADD_TEST(testSuite, test_utHasOrigin); CU_ADD_TEST(testSuite, test_utClear); CU_ADD_TEST(testSuite, test_utCopy); CU_ADD_TEST(testSuite, test_utMultiply); CU_ADD_TEST(testSuite, test_utDivide); CU_ADD_TEST(testSuite, test_utInvert); CU_ADD_TEST(testSuite, test_utRaise); CU_ADD_TEST(testSuite, test_utShift); CU_ADD_TEST(testSuite, test_utScale); CU_ADD_TEST(testSuite, test_utPrint); CU_ADD_TEST(testSuite, test_utAdd); CU_ADD_TEST(testSuite, test_utFind); ut_set_error_message_handler(ut_ignore); if (CU_basic_run_tests() == CUE_SUCCESS) { if (CU_get_number_of_tests_failed() == 0) exitCode = EXIT_SUCCESS; } } CU_cleanup_registry(); } return exitCode; } udunits-2.2.0/lib/udunits2.h0000644000175000017500000011266412260406756017056 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ #ifndef UT_UNITS2_H_INCLUDED #define UT_UNITS2_H_INCLUDED #include #include #include "converter.h" typedef struct ut_system ut_system; typedef union ut_unit ut_unit; enum utStatus { UT_SUCCESS = 0, /* Success */ UT_BAD_ARG, /* An argument violates the function's contract */ UT_EXISTS, /* Unit, prefix, or identifier already exists */ UT_NO_UNIT, /* No such unit exists */ UT_OS, /* Operating-system error. See "errno". */ UT_NOT_SAME_SYSTEM, /* The units belong to different unit-systems */ UT_MEANINGLESS, /* The operation on the unit(s) is meaningless */ UT_NO_SECOND, /* The unit-system doesn't have a unit named "second" */ UT_VISIT_ERROR, /* An error occurred while visiting a unit */ UT_CANT_FORMAT, /* A unit can't be formatted in the desired manner */ UT_SYNTAX, /* string unit representation contains syntax error */ UT_UNKNOWN, /* string unit representation contains unknown word */ UT_OPEN_ARG, /* Can't open argument-specified unit database */ UT_OPEN_ENV, /* Can't open environment-specified unit database */ UT_OPEN_DEFAULT, /* Can't open installed, default, unit database */ UT_PARSE /* Error parsing unit specification */ }; typedef enum utStatus ut_status; enum utEncoding { UT_ASCII = 0, UT_ISO_8859_1 = 1, UT_LATIN1 = UT_ISO_8859_1, UT_UTF8 = 2 }; typedef enum utEncoding ut_encoding; #define UT_NAMES 4 #define UT_DEFINITION 8 /* * Data-structure for a visitor to a unit: */ typedef struct ut_visitor { /* * Visits a basic-unit. A basic-unit is a base unit like "meter" or a non- * dimensional but named unit like "radian". * * Arguments: * unit Pointer to the basic-unit. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_basic)(const ut_unit* unit, void* arg); /* * Visits a product-unit. A product-unit is a product of zero or more * basic-units, each raised to a non-zero power. * * Arguments: * unit Pointer to the product-unit. * count The number of basic-units in the product. May be zero. * basicUnits Pointer to an array of basic-units in the product. * powers Pointer to an array of powers to which the respective * basic-units are raised. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_product)(const ut_unit* unit, int count, const ut_unit* const* basicUnits, const int* powers, void* arg); /* * Visits a Galilean-unit. A Galilean-unit has an underlying unit and a * non-unity scale factor or a non-zero offset. * * Arguments: * unit Pointer to the Galilean-unit. * scale The scale factor (e.g., 1000 for a kilometer when the * underlying unit is a meter). * underlyingUnit Pointer to the underlying unit. * offset Pointer to the underlying unit. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_galilean)(const ut_unit* unit, double scale, const ut_unit* underlyingUnit, double offset, void* arg); /* * Visits a timestamp-unit. A timestamp-unit has an underlying unit of time * and an encoded time-origin. * * Arguments: * unit Pointer to the timestamp-unit. * timeUnit Pointer to the underlying unit of time. * origin Encoded origin of the timestamp-unit. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_timestamp)(const ut_unit* unit, const ut_unit* timeUnit, double origin, void* arg); /* * Visits a logarithmic-unit. A logarithmic-unit has a logarithmic base and * a unit that specifies the reference level. * * Arguments: * unit Pointer to the logarithmic-unit. * base The logarithmic base (e.g., 2, M_E, 10). * reference Pointer to the unit that specifies the reference level. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_logarithmic)(const ut_unit* unit, double base, const ut_unit* reference, void* arg); } ut_visitor; typedef int (*ut_error_message_handler)(const char* fmt, va_list args); #ifdef __cplusplus extern "C" { #endif /****************************************************************************** * Unit System: ******************************************************************************/ /** * Returns the pathname of the XML database. * * @param path The pathname of the XML file or NULL. * @param status Status. One of UT_OPEN_ARG, UT_OPEN_ENV, or UT_OPEN_DEFAULT. * @return If "path" is not NULL, then it is returned; otherwise, the * pathname specified by the environment variable * UDUNITS2_XML_PATH is returned if set; otherwise, the * compile-time pathname of the installed, default, unit * database is returned. */ const char* ut_get_path_xml( const char* path, ut_status* status); /* * Returns the unit-system corresponding to an XML file. This is the usual way * that a client will obtain a unit-system. * * Arguments: * path The pathname of the XML file or NULL. If NULL, then the * pathname specified by the environment variable UDUNITS2_XML_PATH * is used if set; otherwise, the compile-time pathname of the * installed, default, unit database is used. * Returns: * NULL Failure. "ut_get_status()" will be * UT_OPEN_ARG "path" is non-NULL but file couldn't be * opened. See "errno" for reason. * UT_OPEN_ENV "path" is NULL and environment variable * UDUNITS2_XML_PATH is set but file * couldn't be opened. See "errno" for * reason. * UT_OPEN_DEFAULT "path" is NULL, environment variable * UDUNITS2_XML_PATH is unset, and the * installed, default, unit database * couldn't be opened. See "errno" for * reason. * UT_PARSE Couldn't parse unit database. * UT_OS Operating-system error. See "errno". * else Pointer to the unit-system defined by "path". */ ut_system* ut_read_xml( const char* path); /* * Returns a new unit-system. On success, the unit-system will only contain * the dimensionless unit one. See "ut_get_dimensionless_unit_one()". * * Returns: * NULL Failure. "ut_get_status()" will be: * UT_OS Operating-system error. See "errno". * else Pointer to a new unit system. */ ut_system* ut_new_system(void); /* * Frees a unit-system. All unit-to-identifier and identifier-to-unit mappings * will be removed. * * Arguments: * system Pointer to the unit-system to be freed. Use of "system" * upon return results in undefined behavior. */ void ut_free_system( ut_system* system); /* * Returns the unit-system to which a unit belongs. * * Arguments: * unit Pointer to the unit in question. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * else Pointer to the unit-system to which "unit" belongs. */ ut_system* ut_get_system( const ut_unit* const unit); /* * Returns the dimensionless-unit one of a unit-system. * * Arguments: * system Pointer to the unit-system for which the dimensionless-unit one * will be returned. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "system" is NULL. * else Pointer to the dimensionless-unit one associated with "system". * While not necessary, the pointer may be passed to ut_free() * when the unit is no longer needed by the client. */ ut_unit* ut_get_dimensionless_unit_one( const ut_system* const system); /* * Returns the unit with a given name from a unit-system. Name comparisons * are case-insensitive. * * Arguments: * system Pointer to the unit-system. * name Pointer to the name of the unit to be returned. * Returns: * NULL Failure. "ut_get_status()" will be * UT_SUCCESS "name" doesn't map to a unit of * "system". * UT_BAD_ARG "system" or "name" is NULL. * else Pointer to the unit of the unit-system with the given name. * The pointer should be passed to ut_free() when the unit is * no longer needed. */ ut_unit* ut_get_unit_by_name( const ut_system* const system, const char* const name); /* * Returns the unit with a given symbol from a unit-system. Symbol * comparisons are case-sensitive. * * Arguments: * system Pointer to the unit-system. * symbol Pointer to the symbol associated with the unit to be * returned. * Returns: * NULL Failure. "ut_get_status()" will be * UT_SUCCESS "symbol" doesn't map to a unit of * "system". * UT_BAD_ARG "system" or "symbol" is NULL. * else Pointer to the unit in the unit-system with the given symbol. * The pointer should be passed to ut_free() when the unit is no * longer needed. */ ut_unit* ut_get_unit_by_symbol( const ut_system* const system, const char* const symbol); /* * Sets the "second" unit of a unit-system. This function must be called before * the first call to "ut_offset_by_time()". ut_read_xml() calls this function if the * resulting unit-system contains a unit named "second". * * Arguments: * second Pointer to the "second" unit. * Returns: * UT_BAD_ARG "second" is NULL. * UT_EXISTS The second unit of the unit-system to which "second" * belongs is set to a different unit. * UT_SUCCESS Success. */ ut_status ut_set_second( const ut_unit* const second); /****************************************************************************** * Defining Unit Prefixes: ******************************************************************************/ /* * Adds a name-prefix to a unit-system. A name-prefix is something like "mega" * or "milli". Comparisons between name-prefixes are case-insensitive. * * Arguments: * system Pointer to the unit-system. * name Pointer to the name-prefix (e.g., "mega"). May be freed * upon return. * value The value of the prefix (e.g., 1e6). * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" or "name" is NULL, or "value" is 0. * UT_EXISTS "name" already maps to a different value. * UT_OS Operating-system failure. See "errno". */ ut_status ut_add_name_prefix( ut_system* const system, const char* const name, const double value); /* * Adds a symbol-prefix to a unit-system. A symbol-prefix is something like * "M" or "y". Comparisons between symbol-prefixes are case-sensitive. * * Arguments: * system Pointer to the unit-system. * symbol Pointer to the symbol-prefix (e.g., "M"). May be freed * upon return. * value The value of the prefix (e.g., 1e6). * Returns: * UT_SUCCESS Success. * UT_BADSYSTEM "system" or "symbol" is NULL. * UT_BAD_ARG "value" is 0. * UT_EXISTS "symbol" already maps to a different value. * UT_OS Operating-system failure. See "errno". */ ut_status ut_add_symbol_prefix( ut_system* const system, const char* const symbol, const double value); /****************************************************************************** * Defining and Deleting Units: ******************************************************************************/ /* * Adds a base-unit to a unit-system. Clients that use ut_read_xml() should not * normally need to call this function. * * Arguments: * system Pointer to the unit-system to which to add the new base-unit. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "system" or "name" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the new base-unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client (the * unit will remain in the unit-system). */ ut_unit* ut_new_base_unit( ut_system* const system); /* * Adds a dimensionless-unit to a unit-system. In the SI system of units, the * derived-unit radian is a dimensionless-unit. Clients that use ut_read_xml() * should not normally need to call this function. * * Arguments: * system Pointer to the unit-system to which to add the new * dimensionless-unit. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "system" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the new dimensionless-unit. The pointer should be * passed to ut_free() when the unit is no longer needed by the * client (the unit will remain in the unit-system). */ ut_unit* ut_new_dimensionless_unit( ut_system* const system); /* * Returns a clone of a unit. * * Arguments: * unit Pointer to the unit to be cloned. * Returns: * NULL Failure. ut_get_status() will be * UT_OS Operating-system failure. See "errno". * UT_BAD_ARG "unit" is NULL. * else Pointer to the clone of "unit". The pointer should be * passed to ut_free() when the unit is no longer needed by the * client. */ ut_unit* ut_clone( const ut_unit* unit); /* * Frees resources associated with a unit. This function should be invoked on * all units that are no longer needed by the client. Use of the unit upon * return from this function will result in undefined behavior. * * Arguments: * unit Pointer to the unit to have its resources freed or NULL. */ void ut_free( ut_unit* const unit); /****************************************************************************** * Mapping between Units and Names: ******************************************************************************/ /* * Returns the name in a given encoding to which a unit maps. * * Arguments: * unit Pointer to the unit whose name should be returned. * encoding The desired encoding of the name. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS "unit" doesn't map to a name in * in the given encoding. * else Pointer to the name in the given encoding to which * "unit" maps. */ const char* ut_get_name( const ut_unit* const unit, const ut_encoding encoding); /* * Adds a mapping from a name to a unit. * * Arguments: * name Pointer to the name to be mapped to "unit". May be * freed upon return. * encoding The character encoding of "name". * unit Pointer to the unit to be mapped-to by "name". May be * freed upon return. * Returns: * UT_BAD_ARG "name" or "unit" is NULL. * UT_OS Operating-system error. See "errno". * UT_EXISTS "name" already maps to a different unit. * UT_SUCCESS Success. */ ut_status ut_map_name_to_unit( const char* const name, const ut_encoding encoding, const ut_unit* const unit); /* * Removes a mapping from a name to a unit. After this function, * ut_get_unit_by_name(system,name) will no longer return a unit. * * Arguments: * system The unit-system to which the unit belongs. * name The name of the unit. * encoding The character encoding of "name". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" or "name" is NULL. */ ut_status ut_unmap_name_to_unit( ut_system* system, const char* const name, const ut_encoding encoding); /* * Adds a mapping from a unit to a name. * * Arguments: * unit Pointer to the unit to be mapped to "name". May be * freed upon return. * name Pointer to the name to be mapped-to by "unit". May be * freed upon return. * encoding The encoding of "name". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "unit" or "name" is NULL, or "name" is not in the * specified encoding. * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a name. */ ut_status ut_map_unit_to_name( const ut_unit* const unit, const char* const name, ut_encoding encoding); /* * Removes a mapping from a unit to a name. * * Arguments: * unit Pointer to the unit. May be freed upon return. * encoding The encoding to be removed. No other encodings will be * removed. * Returns: * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS Success. */ ut_status ut_unmap_unit_to_name( const ut_unit* const unit, ut_encoding encoding); /****************************************************************************** * Mapping between Units and Symbols: ******************************************************************************/ /* * Returns the symbol in a given encoding to which a unit maps. * * Arguments: * unit Pointer to the unit whose symbol should be returned. * encoding The desired encoding of the symbol. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS "unit" doesn't map to a symbol * in the given encoding. * else Pointer to the symbol in the given encoding to which * "unit" maps. */ const char* ut_get_symbol( const ut_unit* const unit, const ut_encoding encoding); /* * Adds a mapping from a symbol to a unit. * * Arguments: * symbol Pointer to the symbol to be mapped to "unit". May be * freed upon return. * ut_encoding The character encoding of "symbol". * unit Pointer to the unit to be mapped-to by "symbol". May * be freed upon return. * Returns: * UT_BAD_ARG "symbol" or "unit" is NULL. * UT_OS Operating-system error. See "errno". * UT_EXISTS "symbol" already maps to a different unit. * UT_SUCCESS Success. */ ut_status ut_map_symbol_to_unit( const char* const symbol, const ut_encoding encoding, const ut_unit* const unit); /* * Removes a mapping from a symbol to a unit. After this function, * ut_get_unit_by_symbol(system,symbol) will no longer return a unit. * * Arguments: * system The unit-system to which the unit belongs. * symbol The symbol of the unit. * encoding The character encoding of "symbol". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" or "symbol" is NULL. */ ut_status ut_unmap_symbol_to_unit( ut_system* system, const char* const symbol, const ut_encoding encoding); /* * Adds a mapping from a unit to a symbol. * * Arguments: * unit Pointer to the unit to be mapped to "symbol". May be * freed upon return. * symbol Pointer to the symbol to be mapped-to by "unit". May * be freed upon return. * encoding The encoding of "symbol". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "unit" or "symbol" is NULL. * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a symbol. */ ut_status ut_map_unit_to_symbol( const ut_unit* unit, const char* const symbol, ut_encoding encoding); /* * Removes a mapping from a unit to a symbol. * * Arguments: * unit Pointer to the unit to be unmapped to a symbol. May be * freed upon return. * encoding The encoding to be removed. The mappings for "unit" in * other encodings will not be removed. * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "unit" is NULL. */ ut_status ut_unmap_unit_to_symbol( const ut_unit* const unit, ut_encoding encoding); /****************************************************************************** * Getting Information about a Unit: ******************************************************************************/ /* * Indicates if a given unit is dimensionless or not. Note that logarithmic * units are dimensionless by definition. * * Arguments: * unit Pointer to the unit in question. * Returns: * 0 "unit" is dimensionfull or an error occurred. "ut_get_status()" * will be * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS "unit" is dimensionfull. * else "unit" is dimensionless. */ int ut_is_dimensionless( const ut_unit* const unit); /* * Indicates if two units belong to the same unit-system. * * Arguments: * unit1 Pointer to a unit. * unit2 Pointer to another unit. * Returns: * 0 Failure or the units belong to different unit-systems. * "ut_get_status()" will be * UT_BAD_ARG "unit1" or "unit2" is NULL. * UT_SUCCESS The units belong to different * unit-systems. * else The units belong to the same unit-system. */ int ut_same_system( const ut_unit* const unit1, const ut_unit* const unit2); /* * Compares two units. Returns a value less than, equal to, or greater than * zero as the first unit is considered less than, equal to, or greater than * the second unit, respectively. Units from different unit-systems never * compare equal. * * Arguments: * unit1 Pointer to a unit or NULL. * unit2 Pointer to another unit or NULL. * Returns: * <0 The first unit is less than the second unit. * 0 The first and second units are equal or both units are NULL. * >0 The first unit is greater than the second unit. */ int ut_compare( const ut_unit* const unit1, const ut_unit* const unit2); /* * Indicates if numeric values in one unit are convertible to numeric values in * another unit via "ut_get_converter()". In making this determination, * dimensionless units are ignored. * * Arguments: * unit1 Pointer to a unit. * unit2 Pointer to another unit. * Returns: * 0 Failure. "ut_get_status()" will be * UT_BAD_ARG "unit1" or "unit2" is NULL. * UT_NOT_SAME_SYSTEM "unit1" and "unit2" belong to * different unit-sytems. * UT_SUCCESS Conversion between the units is * not possible (e.g., "unit1" is * "meter" and "unit2" is * "kilogram"). * else Numeric values can be converted between the units. */ int ut_are_convertible( const ut_unit* const unit1, const ut_unit* const unit2); /* * Returns a converter of numeric values in one unit to numeric values in * another unit. The returned converter should be passed to cv_free() when it is * no longer needed by the client. * * NOTE: Leap seconds are not taken into account when converting between * timestamp units. * * Arguments: * from Pointer to the unit from which to convert values. * to Pointer to the unit to which to convert values. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "from" or "to" is NULL. * UT_NOT_SAME_SYSTEM "from" and "to" belong to * different unit-systems. * UT_MEANINGLESS Conversion between the units is * not possible. See * "ut_are_convertible()". * else Pointer to the appropriate converter. The pointer * should be passed to cv_free() when no longer needed by * the client. */ cv_converter* ut_get_converter( ut_unit* const from, ut_unit* const to); /****************************************************************************** * Arithmetic Unit Manipulation: ******************************************************************************/ /* * Returns a unit equivalent to another unit scaled by a numeric factor, * e.g., * const ut_unit* meter = ... * const ut_unit* kilometer = ut_scale(1000, meter); * * Arguments: * factor The numeric scale factor. * unit Pointer to the unit to be scaled. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "factor" is 0 or "unit" is NULL. * UT_OS Operating-system error. See * "errno". * else Pointer to the resulting unit. The pointer should be * passed to ut_free() when the unit is no longer needed by * the client. */ ut_unit* ut_scale( const double factor, const ut_unit* const unit); /* * Returns a unit equivalent to another unit offset by a numeric amount, * e.g., * const ut_unit* kelvin = ... * const ut_unit* celsius = ut_offset(kelvin, 273.15); * * Arguments: * unit Pointer to the unit to be offset. * offset The numeric offset. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_OS Operating-system error. See * "errno". * else Pointer to the resulting unit. The pointer should be * passed to ut_free() when the unit is no longer needed by * the client. */ ut_unit* ut_offset( const ut_unit* const unit, const double offset); /* * Returns a unit equivalent to another unit relative to a particular time. * e.g., * const ut_unit* second = ... * const ut_unit* secondsSinceTheEpoch = * ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0.0)); * * Arguments: * unit Pointer to the time-unit to be made relative to a time-origin. * origin The origin as returned by ut_encode_time(). * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_OS Operating-system error. See "errno". * UT_MEANINGLESS Creation of a timestamp unit based on * "unit" is not meaningful. * UT_NO_SECOND The associated unit-system doesn't * contain a "second" unit. See * ut_set_second(). * else Pointer to the resulting unit. The pointer should be passed * to ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_offset_by_time( const ut_unit* const unit, const double origin); /* * Returns the result of multiplying one unit by another unit. * * Arguments: * unit1 Pointer to a unit. * unit2 Pointer to another unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit1" or "unit2" is NULL. * UT_NOT_SAME_SYSTEM "unit1" and "unit2" belong to * different unit-systems. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed * to ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_multiply( const ut_unit* const unit1, const ut_unit* const unit2); /* * Returns the inverse (i.e., reciprocal) of a unit. This convenience function * is equal to "ut_raise(unit, -1)". * * Arguments: * unit Pointer to the unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_invert( const ut_unit* const unit); /* * Returns the result of dividing one unit by another unit. This convenience * function is equivalent to the following sequence: * { * ut_unit* inverse = ut_invert(denom); * ut_multiply(numer, inverse); * ut_free(inverse); * } * * Arguments: * numer Pointer to the numerator (top, dividend) unit. * denom Pointer to the denominator (bottom, divisor) unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "numer" or "denom" is NULL. * UT_NOT_SAME_SYSTEM "unit1" and "unit2" belong to * different unit-systems. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_divide( const ut_unit* const numer, const ut_unit* const denom); /* * Returns the result of raising a unit to a power. * * Arguments: * unit Pointer to the unit. * power The power by which to raise "unit". Must be greater than or * equal to -255 and less than or equal to 255. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit" is NULL or "power" is invalid. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_raise( const ut_unit* const unit, const int power); /* * Returns the result of taking the root of a unit. * * Arguments: * unit Pointer to the unit. * root The root to take of "unit". Must be greater than or * equal to 1 and less than or equal to 255. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit" is NULL, or "root" is invalid. * In particular, all powers of base units * in "unit" must be integral multiples of * "root". * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ ut_unit* ut_root( const ut_unit* const unit, const int root); /* * Returns the logarithmic unit corresponding to a logarithmic base and a * reference level. For example, the following creates a decibel unit with a * one milliwatt reference level: * * const ut_unit* watt = ...; * const ut_unit* milliWatt = ut_scale(0.001, watt); * * if (milliWatt != NULL) { * const ut_unit* bel_1_mW = ut_log(10.0, milliWatt); * * if (bel_1_mW != NULL) { * const ut_unit* decibel_1_mW = ut_scale(0.1, bel_1_mW); * * if (decibel_1_mW != NULL) { * ... * ut_free(decibel_1_mW); * } // "decibel_1_mW" allocated * * ut_free(bel_1_mW); * } // "bel_1_mW" allocated * * ut_free(milliWatt); * } // "milliWatt" allocated * * Arguments: * base The logarithmic base (e.g., 2, M_E, 10). Must be * greater than one. "M_E" is defined in . * reference Pointer to the reference value as a unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "base" is invalid or "reference" * is NULL. * UT_OS Operating-system error. See * "errno". * else Pointer to the resulting unit. The pointer should be * passed to ut_free() when the unit is no longer needed by * the client. */ ut_unit* ut_log( const double base, const ut_unit* const reference); /****************************************************************************** * Parsing and Formatting Units: ******************************************************************************/ /* * Returns the binary representation of a unit corresponding to a string * representation. * * Arguments: * system Pointer to the unit-system in which the parsing will * occur. * string The string to be parsed (e.g., "millimeters"). There * should be no leading or trailing whitespace in the * string. See ut_trim(). * encoding The encoding of "string". * Returns: * NULL Failure. "ut_get_status()" will be one of * UT_BAD_ARG "system" or "string" is NULL. * UT_SYNTAX "string" contained a syntax * error. * UT_UNKNOWN "string" contained an unknown * identifier. * UT_OS Operating-system failure. See * "errno". * else Pointer to the unit corresponding to "string". */ ut_unit* ut_parse( const ut_system* const system, const char* const string, const ut_encoding encoding); /* * Removes leading and trailing whitespace from a string. * * Arguments: * string NUL-terminated string. Will be modified if it contains * whitespace.. * encoding The character-encoding of "string". * Returns: * "string", with all leading and trailing whitespace removed. */ char* ut_trim( char* const string, const ut_encoding encoding); /* * Formats a unit. * * Arguments: * unit Pointer to the unit to be formatted. * buf Pointer to the buffer into which to format "unit". * size Size of the buffer in bytes. * opts Formatting options: bitwise-OR of zero or more of the * following: * UT_NAMES Use unit names instead of * symbols * UT_DEFINITION The formatted string should be * the definition of "unit" in * terms of basic-units instead of * stopping any expansion at the * highest level possible. * UT_ASCII The string should be formatted * using the ASCII character set * (default). * UT_LATIN1 The string should be formatted * using the ISO Latin-1 (alias * ISO-8859-1) character set. * UT_UTF8 The string should be formatted * using the UTF-8 character set. * UT_LATIN1 and UT_UTF8 are mutually exclusive: they may * not both be specified. * Returns: * -1 Failure: "ut_get_status()" will be * UT_BAD_ARG "unit" or "buf" is NULL, or both * UT_LATIN1 and UT_UTF8 specified. * UT_CANT_FORMAT "unit" can't be formatted in * the desired manner. * else Success. Number of characters printed in "buf". If * the number is equal to the size of the buffer, then the * buffer is too small to have a terminating NUL character. */ int ut_format( const ut_unit* const unit, char* buf, size_t size, unsigned opts); /* * Accepts a visitor to a unit. * * Arguments: * unit Pointer to the unit to accept the visitor. * visitor Pointer to the visitor of "unit". * arg An arbitrary pointer that will be passed to "visitor". * Returns: * UT_BAD_ARG "unit" or "visitor" is NULL. * UT_VISIT_ERROR A error occurred in "visitor" while visiting "unit". * UT_SUCCESS Success. */ ut_status ut_accept_visitor( const ut_unit* const unit, const ut_visitor* const visitor, void* const arg); /****************************************************************************** * Time Handling: ******************************************************************************/ /* * Encodes a date as a double-precision value. * * Arguments: * year The year. * month The month. * day The day (1 = the first of the month). * Returns: * The date encoded as a scalar value. */ double ut_encode_date( int year, int month, int day); /* * Encodes a time as a double-precision value. * * Arguments: * hours The number of hours (0 = midnight). * minutes The number of minutes. * seconds The number of seconds. * Returns: * The clock-time encoded as a scalar value. */ double ut_encode_clock( int hours, int minutes, double seconds); /* * Encodes a time as a double-precision value. The convenience function is * equivalent to "ut_encode_date(year,month,day) + * ut_encode_clock(hour,minute,second)" * * Arguments: * year The year. * month The month. * day The day. * hour The hour. * minute The minute. * second The second. * Returns: * The time encoded as a scalar value. */ double ut_encode_time( const int year, const int month, const int day, const int hour, const int minute, const double second); /* * Decodes a time from a double-precision value. * * Arguments: * value The value to be decoded. * year Pointer to the variable to be set to the year. * month Pointer to the variable to be set to the month. * day Pointer to the variable to be set to the day. * hour Pointer to the variable to be set to the hour. * minute Pointer to the variable to be set to the minute. * second Pointer to the variable to be set to the second. * resolution Pointer to the variable to be set to the resolution * of the decoded time in seconds. */ void ut_decode_time( double value, int *year, int *month, int *day, int *hour, int *minute, double *second, double *resolution); /****************************************************************************** * Error Handling: ******************************************************************************/ /* * Returns the status of the last operation by the units module. This function * will not change the status. */ ut_status ut_get_status(void); /* * Sets the status of the units module. This function would not normally be * called by the user unless they were doing their own parsing or formatting. * * Arguments: * status The status of the units module. */ void ut_set_status( ut_status status); /* * Handles an error-message. * * Arguments: * fmt The format for the error-message. * ... The arguments for "fmt". * Returns: * <0 An output error was encountered. * else The number of bytes of "fmt" and "arg" written excluding any * terminating NUL. */ int ut_handle_error_message( const char* const fmt, ...); /* * Returns the previously-installed error-message handler and optionally * installs a new handler. The initial handler is "ut_write_to_stderr()". * * Arguments: * handler NULL or pointer to the error-message handler. If NULL, * then the handler is not changed. The * currently-installed handler can be obtained this way. * Returns: * Pointer to the previously-installed error-message handler. */ ut_error_message_handler ut_set_error_message_handler( ut_error_message_handler handler); /* * Writes an error-message to the standard-error stream when received and * appends a newline. This is the initial error-message handler. * * Arguments: * fmt The format for the error-message. * args The arguments of "fmt". * Returns: * <0 A output error was encountered. See "errno". * else The number of bytes of "fmt" and "arg" written excluding any * terminating NUL. */ int ut_write_to_stderr( const char* const fmt, va_list args); /* * Does nothing with an error-message. * * Arguments: * fmt The format for the error-message. * args The arguments of "fmt". * Returns: * 0 Always. */ int ut_ignore( const char* const fmt, va_list args); #ifdef __cplusplus } #endif #endif udunits-2.2.0/lib/udunits.h0000644000175000017500000001167712260406756016776 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Public header-file for the Unidata units(3) library. */ #ifndef UT_UNITS_H_INCLUDED #define UT_UNITS_H_INCLUDED #include "udunits2.h" #define UT_NAMELEN 32 /* maximum length of a unit string * (including all prefixes and EOS) */ /* * Macro for declaring functions regardless of the availability of * function prototypes. NB: will need double parens in actual use (e.g. * "int func PROTO((int a, char *cp))"). */ #ifndef PROTO # if defined(__STDC__) || defined(__GNUC__) \ || defined(__cplusplus) || defined(c_plusplus) # define PROTO(a) a # else # define PROTO(a) () # endif #endif #define UT_EOF 1 /* end-of-file encountered */ #define UT_ENOFILE -1 /* no units-file */ #define UT_ESYNTAX -2 /* syntax error */ #define UT_EUNKNOWN -3 /* unknown specification */ #define UT_EIO -4 /* I/O error */ #define UT_EINVALID -5 /* invalid unit-structure */ #define UT_ENOINIT -6 /* package not initialized */ #define UT_ECONVERT -7 /* two units are not convertable */ #define UT_EALLOC -8 /* memory allocation failure */ #define UT_ENOROOM -9 /* insufficient room supplied */ #define UT_ENOTTIME -10 /* not a unit of time */ #define UT_DUP -11 /* duplicate unit */ #define UT_MAXNUM_BASE_QUANTITIES 10 typedef double UtOrigin; /* origin datatype */ typedef double UtFactor; /* conversion-factor datatype */ /* * Unit-structure. Don't rely on or mess with the members! */ typedef struct utUnit { ut_unit* unit2; } utUnit; #ifdef __cplusplus extern "C" { #endif /* * Initialize the units(3) package. */ extern int utInit PROTO(( const char *path )); /* * Indicate if the units(3) package has been initialized. */ extern int utIsInit PROTO((void)); /* * Initialize a unit-structure. */ extern void utIni PROTO(( utUnit* const unit )); /* * Decode a formatted unit specification into a unit-structure. */ extern int utScan PROTO(( const char *spec, utUnit *up )); /* * Convert a temporal value into a UTC Gregorian date and time. */ extern int utCalendar PROTO(( double value, const utUnit *unit, int *year, int *month, int *day, int *hour, int *minute, float *second )); /* * Convert a date into a temporal value. The date is assumed to * use the Gregorian calendar if on or after noon, October 15, 1582; * otherwise, the date is assumed to use the Julian calendar. */ extern int utInvCalendar PROTO(( int year, int month, int day, int hour, int minute, double second, const utUnit *unit, double *value )); /* * Indicate if a unit structure refers to a unit of time. */ extern int utIsTime PROTO(( const utUnit *up )); /* * Indicate if a unit structure has an origin. */ extern int utHasOrigin PROTO(( const utUnit *up )); /* * Clear a unit structure. */ extern utUnit* utClear PROTO(( utUnit *unit )); /* * Copy a unit-strcture. */ extern utUnit* utCopy PROTO(( const utUnit *source, utUnit *dest )); /* * Multiply one unit-structure by another. */ extern utUnit* utMultiply PROTO(( const utUnit *term1, const utUnit *term2, utUnit *result )); /* * Divide one unit-structure by another. */ extern utUnit* utDivide PROTO(( const utUnit *numer, const utUnit *denom, utUnit *result )); /* * Form the reciprocal of a unit-structure. */ extern utUnit* utInvert PROTO(( const utUnit *source, utUnit *dest )); /* * Raise a unit-structure to a power. */ extern utUnit* utRaise PROTO(( const utUnit *source, int power, utUnit *result )); /* * Shift the origin of a unit-structure by an arithmetic amount. */ extern utUnit* utShift PROTO(( const utUnit *source, double amount, utUnit *result )); /* * Scale a unit-structure. */ extern utUnit* utScale PROTO(( const utUnit *source, double factor, utUnit *result )); /* * Compute the conversion factor between two unit-structures. */ extern int utConvert PROTO(( const utUnit *from, const utUnit *to, double *slope, double *intercept )); /* * Encode a unit-structure into a formatted unit-specification. */ extern int utPrint PROTO(( const utUnit *unit, char **buf )); /* * Add a unit-structure to the units-table. */ extern int utAdd PROTO(( char *name, int HasPlural, const utUnit *unit )); /* * Return the unit-structure corresponding to a unit-specification. */ extern int utFind PROTO(( char *spec, utUnit *up )); /* * Free the resources of a unit-structure. */ extern void utFree PROTO(( utUnit* const unit )); /* * Terminate use of this package. */ extern void utTerm PROTO((void)); #ifdef __cplusplus } #endif #endif /* UT_UNITS_H_INCLUDED not defined */ udunits-2.2.0/lib/unitToIdMap.c0000644000175000017500000004617512260406756017474 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Unit-to-identifier map. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include "udunits2.h" #include "unitAndId.h" #include "unitToIdMap.h" /* this module's API */ #include "systemMap.h" typedef struct { void* ascii; void* latin1; void* utf8; } UnitToIdMap; static SystemMap* systemToUnitToName = NULL; static SystemMap* systemToUnitToSymbol = NULL; /****************************************************************************** * Miscellaneous Functions: ******************************************************************************/ /* * Unconditionally converts an ISO Latin-1 string into a UTF-8 string. * * Arguments: * latin1String Pointer to the ISO Latin-1 string. * Returns: * NULL Failure. See errno. * else Pointer to the equivalent UTF-8 string. Should be freed * when no longer needed. */ static char* latin1ToUtf8( const char* const latin1String) { int nchar; const char* inp; char* outp; char* utf8String; for (nchar = 0, inp = latin1String; *inp; ++inp, ++nchar) if ((*inp & 0x80U) != 0) nchar++; utf8String = malloc(nchar+1); if (utf8String != NULL) { for (inp = latin1String, outp = utf8String; *inp; ++inp, ++outp) { if ((*inp & 0x80U) == 0) { *outp = *inp; } else { *outp++ = (char)(0xC0U | ((unsigned)*inp >> 6)); *outp = (char)(0x80U | (*inp & 0x3FU)); } } *outp = 0; } return utf8String; } /* * Adjust a given encoding according to a string. Because ASCII is a subset of * ISO Latin-1 and because a UTF-8 encoded string must follow certain rules, * it's possible for strings to be mis-encoded and for an encoding specification * to be too restrictive or over-generous. If the encoding specification is * ASCII and the given string contains a character with the high-order bit * set, then the encoding will be changed to ISO Latin-1. If the encoding * specification is ISO Latin-1 but the string doesn't contain a character with * the high-order bit set, then the encoding will be changed to ASCII. If the * encoding specification is UTF-8 but the string doesn't follow the UTF-8 * encoding rules, then the function will error-return. * * Arguments: * encoding Pointer to the presumptive encoding. Might be modified * on return to reflect the actual, most restrictive, * encoding of "string". * string The string to be checked. * Returns: * 0 Success. "*encoding" might be modified. * -1 Failure. "string" doesn't conform to "encoding". */ static int adjustEncoding( ut_encoding* const encoding, const char* string) { int status = 0; /* success */ if (*encoding == UT_ASCII) { for (; *string && ((*string & 0x80U) == 0); string++) ; if (*string != 0) *encoding = UT_LATIN1; } else if (*encoding == UT_LATIN1) { for (; *string && ((*string & 0x80U) == 0); string++) ; if (*string == 0) *encoding = UT_ASCII; } else if (*encoding == UT_UTF8) { for (; *string; string++) { if (*string & 0x80U) { if ((*string & 0xE0U) == 0xC0U) { if ((*++string & 0xC0U) != 0x80U) break; } else if ((*string & 0xF0U) == 0xE0U) { if ((*++string & 0xC0U) != 0x80U) break; if ((*++string & 0xC0U) != 0x80U) break; } else if ((*string & 0xF8U) == 0xF0U) { if ((*++string & 0xC0U) != 0x80U) break; if ((*++string & 0xC0U) != 0x80U) break; if ((*++string & 0xC0U) != 0x80U) break; } } } if (*string) status = -1; } return status; } /****************************************************************************** * Internal Map Functions: ******************************************************************************/ static int compareUnits( const void* const entry1, const void* const entry2) { return ut_compare(((const UnitAndId*)entry1)->unit, ((const UnitAndId*)entry2)->unit); } /* * Selects a unit-and-identifier tree corresponding to a given encoding. * * Arguments: * map The unit-to-id map. * encoding The encoding. * Returns: * Pointer to the root of the unit-and-identifier tree in "map" that * corresponds to "encoding". */ static void** selectTree( UnitToIdMap* const unitToIdMap, const ut_encoding encoding) { return encoding == UT_ASCII ? &unitToIdMap->ascii : encoding == UT_LATIN1 ? &unitToIdMap->latin1 : &unitToIdMap->utf8; } /* * Returns a new instance of a unit-to-identifier map. * * Returns: * NULL Failure. See "errno". * else Pointer to a new unit-to-identifier map. */ static UnitToIdMap* utimNew(void) { UnitToIdMap* const map = malloc(sizeof(UnitToIdMap)); if (map != NULL) { map->ascii = NULL; map->latin1 = NULL; map->utf8 = NULL; } return map; } /* * Frees a unit-to-identifier map. All entries in all encodings are freed. * * Arguments: * map Pointer to the map to be freed. */ static void utimFree( UnitToIdMap* map) { if (map != NULL) { ut_encoding encodings[] = {UT_ASCII, UT_LATIN1, UT_UTF8}; int i; for (i = 0; i < sizeof(encodings)/sizeof(encodings[0]); ++i) { void** rootp = selectTree(map, encodings[i]); while (*rootp != NULL) { UnitAndId* uai = **(UnitAndId***)rootp; (void)tdelete(uai, rootp, compareUnits); uaiFree(uai); } } free(map); } } /* * Adds an entry to a unit-to-identifier map. * * Arguments: * map Pointer to unit-to-identifier map. * unit The unit. May be freed upon return. * id The identifier. May be freed upon return. * encoding The ostensible encoding of "id". * Returns: * UT_BAD_ARG "id" is inconsistent with "encoding". * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a different identifier. * UT_SUCCESS Success. */ static ut_status utimAdd( UnitToIdMap* const map, const ut_unit* unit, const char* const id, ut_encoding encoding) { ut_status status; assert(map != NULL); assert(unit != NULL); assert(id != NULL); if (adjustEncoding(&encoding, id)) { status = UT_BAD_ARG; ut_set_status(status); ut_handle_error_message("Identifier not in given encoding"); } else { UnitAndId* targetEntry = uaiNew(unit, id); if (targetEntry != NULL) { void** rootp = selectTree(map, encoding); UnitAndId** treeEntry = tsearch(targetEntry, rootp, compareUnits); if (treeEntry == NULL) { status = UT_OS; ut_set_status(status); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't add search-tree entry"); uaiFree(targetEntry); } else { if (strcmp((*treeEntry)->id, id) != 0) { status = UT_EXISTS; ut_set_status(status); ut_handle_error_message("Unit already maps to \"%s\"", (*treeEntry)->id); } else { status = UT_SUCCESS; } if (targetEntry != *treeEntry) uaiFree(targetEntry); } } /* "targetEntry" allocated */ } /* valid arguments */ return status; } /* * Removes an entry from a unit-to-identifier map. * * Arguments: * map Pointer to the unit-to-identifier map. * unit The unit. May be freed upon return. * encoding The encoding to be removed. * Returns: * UT_SUCCESS Success. */ static ut_status utimRemove( UnitToIdMap* const map, const ut_unit* unit, ut_encoding encoding) { ut_status status; UnitAndId targetEntry; UnitAndId** treeEntry; assert(map != NULL); assert(unit != NULL); targetEntry.unit = (ut_unit*)unit; treeEntry = tfind(&targetEntry, selectTree(map, encoding), compareUnits); if (treeEntry == NULL || *treeEntry == NULL) { status = UT_SUCCESS; } else { UnitAndId* uai = *treeEntry; (void)tdelete(uai, selectTree(map, encoding), compareUnits); uaiFree(uai); } return status; } /* * Returns the unit-and-identifier whose ASCII identifier corresponding to a * unit. * * Arguments: * map The unit-to-identifier map. * unit The unit to be used as the key in the search. * Returns: * NULL The map doesn't contain an entry corresponding to "unit" whose * identifier is in ASCII. * else Pointer to the entry corresponding to "unit" whose identifier is * in ASCII. */ static UnitAndId* utimFindAsciiByUnit( UnitToIdMap* const map, const ut_unit* const unit) { UnitAndId targetEntry; UnitAndId** treeEntry; targetEntry.unit = (ut_unit*)unit; treeEntry = tfind(&targetEntry, &map->ascii, compareUnits); return treeEntry == NULL ? NULL : *treeEntry; } /* * Finds a unit-search-entry with a Latin-1 identifier correcponding to a unit. * * Arguments: * map The unit-to-identifier map. * unit The unit to be used as the key in the search. * Returns: * NULL The map doesn't contain an entry corresponding to "unit" whose * identifier is in Latin-1. * else Pointer to the entry corresponding to "unit" whose identifier is * in Latin-1 (and might, actually, be in ASCII). */ static UnitAndId* utimFindLatin1ByUnit( UnitToIdMap* const map, const ut_unit* const unit) { UnitAndId targetEntry; UnitAndId** treeEntry; targetEntry.unit = (ut_unit*)unit; treeEntry = tfind(&targetEntry, &map->latin1, compareUnits); if (treeEntry == NULL) treeEntry = tfind(&targetEntry, &map->ascii, compareUnits); return treeEntry == NULL ? NULL : *treeEntry; } /* * Finds an entry with a UTF-8 identifier corresponding to a unit. * * Arguments: * map The unit-to-identifier map. * unit The unit to be used as the key in the search. * Returns: * NULL The map doesn't contain an entry corresponding to "unit" whose * identifier is in UTF-8. * else Pointer to the entry corresponding to "unit" whose identifier is * in UTF-8 (and might, actually, be in ASCII). */ static UnitAndId* utimFindUtf8ByUnit( UnitToIdMap* const map, const ut_unit* const unit) { UnitAndId targetEntry; UnitAndId** treeEntry = NULL; /* failure */ targetEntry.unit = (ut_unit*)unit; treeEntry = tfind(&targetEntry, &map->utf8, compareUnits); if (treeEntry == NULL) { treeEntry = tfind(&targetEntry, &map->latin1, compareUnits); if (treeEntry == NULL) { treeEntry = tfind(&targetEntry, &map->ascii, compareUnits); } else { /* * Create the UTF-8 version of the Latin-1 identifier and add it to * the UTF-8 unit-to-id map so that it will be found next time. */ char* const id = latin1ToUtf8((*treeEntry)->id); if (id == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "Couldn't convert identifier from ISO-8859-1 to UTF-8"); treeEntry = NULL; } else { UnitAndId* newEntry = uaiNew(unit, id); if (newEntry != NULL) { treeEntry = tsearch(newEntry, &map->utf8, compareUnits); if (treeEntry == NULL) { uaiFree(newEntry); ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "Couldn't add unit-and-identifier to search-tree"); } } free(id); } /* UTF-8 identifier created */ } /* found Latin-1 identifier */ } /* no UTF-8 identifier */ return treeEntry == NULL ? NULL : *treeEntry; } /* * Adds an entry to the unit-to-identifier map associated with a unit-system. * * Arguments: * sytemMap Address of the pointer to the * system-to-unit-to-identifier map. * unit The unit. May be freed upon return. * id The identifier. May be freed upon return. * encoding The ostensible encoding of "id". * Returns: * UT_BAD_ARG "unit" or "id" is NULL, or "id" is inconsistent with * "encoding". * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a different identifier. * UT_SUCCESS Success. */ static ut_status mapUnitToId( SystemMap** const systemMap, const ut_unit* const unit, const char* const id, ut_encoding encoding) { ut_status status; assert(systemMap != NULL); if (unit == NULL || id == NULL) { status = UT_BAD_ARG; } else { if (*systemMap == NULL) { *systemMap = smNew(); if (*systemMap == NULL) status = UT_OS; } if (*systemMap != NULL) { UnitToIdMap** const unitToIdMap = (UnitToIdMap**)smSearch(*systemMap, ut_get_system(unit)); if (unitToIdMap == NULL) { status = UT_OS; } else { if (*unitToIdMap == NULL) { *unitToIdMap = utimNew(); if (*unitToIdMap == NULL) status = UT_OS; } if (*unitToIdMap != NULL) status = utimAdd(*unitToIdMap, unit, id, encoding); } } } return status; } /* * Removes an entry from the unit-to-identifier map associated with a * unit-system. * * Arguments: * sytemMap Pointer to the system-to-unit-to-identifier map. * unit The unit. May be freed upon return. * encoding The ostensible encoding of "id". * Returns: * UT_BAD_ARG "systemMap" is NULL. * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS Success. */ static ut_status unmapUnitToId( SystemMap* const systemMap, const ut_unit* const unit, ut_encoding encoding) { ut_status status; if (systemMap == NULL || unit == NULL) { status = UT_BAD_ARG; } else { UnitToIdMap** const unitToIdMap = (UnitToIdMap**)smFind(systemMap, ut_get_system(unit)); status = (unitToIdMap == NULL || *unitToIdMap == NULL) ? UT_SUCCESS : utimRemove(*unitToIdMap, unit, encoding); } return status; } /* * Returns the identifier in a given encoding to which a unit associated with * a unit-system maps. * * Arguments: * systemMap Pointer to the system-to-unit-to-id map. * unit Pointer to the unit whose identifier should be returned. * encoding The desired encoding of the identifier. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" was NULL. * else Pointer to the identifier in the given encoding * associated with "unit". */ static const char* getId( SystemMap* const systemMap, const ut_unit* const unit, const ut_encoding encoding) { const char* id = NULL; /* failure */ if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("NULL unit argument"); } else { UnitToIdMap** const unitToId = (UnitToIdMap**)smFind(systemMap, ut_get_system(unit)); if (unitToId != NULL) { UnitAndId* mapEntry = encoding == UT_LATIN1 ? utimFindLatin1ByUnit(*unitToId, unit) : encoding == UT_UTF8 ? utimFindUtf8ByUnit(*unitToId, unit) : utimFindAsciiByUnit(*unitToId, unit); if (mapEntry != NULL) id = mapEntry->id; } } return id; } /****************************************************************************** * Public API: ******************************************************************************/ /* * Adds a mapping from a unit to a name. * * Arguments: * unit Pointer to the unit to be mapped to "name". May be * freed upon return. * name Pointer to the name to be mapped-to by "unit". May be * freed upon return. * encoding The encoding of "name". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "unit" or "name" is NULL, or "name" is not in the * specified encoding. * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a name. */ ut_status ut_map_unit_to_name( const ut_unit* const unit, const char* const name, ut_encoding encoding) { ut_set_status(mapUnitToId(&systemToUnitToName, unit, name, encoding)); return ut_get_status(); } /* * Removes a mapping from a unit to a name. * * Arguments: * unit Pointer to the unit. May be freed upon return. * encoding The encoding to be removed. No other encodings will be * removed. * Returns: * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS Success. */ ut_status ut_unmap_unit_to_name( const ut_unit* const unit, ut_encoding encoding) { ut_set_status(unmapUnitToId(systemToUnitToName, unit, encoding)); return ut_get_status(); } /* * Adds a mapping from a unit to a symbol. * * Arguments: * unit Pointer to the unit to be mapped to "symbol". May be * freed upon return. * symbol Pointer to the symbol to be mapped-to by "unit". May * be freed upon return. * encoding The encoding of "symbol". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "unit" or "symbol" is NULL. * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a symbol. */ ut_status ut_map_unit_to_symbol( const ut_unit* unit, const char* const symbol, ut_encoding encoding) { ut_set_status(mapUnitToId(&systemToUnitToSymbol, unit, symbol, encoding)); return ut_get_status(); } /* * Removes a mapping from a unit to a symbol. * * Arguments: * unit Pointer to the unit to be unmapped to a symbol. May be * freed upon return. * encoding The encoding to be removed. The mappings for "unit" in * other encodings will not be removed. * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "unit" is NULL. */ ut_status ut_unmap_unit_to_symbol( const ut_unit* const unit, ut_encoding encoding) { ut_set_status(unmapUnitToId(systemToUnitToSymbol, unit, encoding)); return ut_get_status(); } /* * Returns the name in a given encoding to which a unit maps. * * Arguments: * unit Pointer to the unit whose name should be returned. * encoding The desired encoding of the name. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS "unit" doesn't map to a name in * in the given encoding. * else Pointer to the name in the given encoding to which * "unit" maps. */ const char* ut_get_name( const ut_unit* const unit, const ut_encoding encoding) { ut_set_status(UT_SUCCESS); return getId(systemToUnitToName, unit, encoding); } /* * Returns the symbol in a given encoding to which a unit maps. * * Arguments: * unit Pointer to the unit whose symbol should be returned. * encoding The desired encoding of the symbol. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS "unit" doesn't map to a symbol * in the given encoding. * else Pointer to the symbol in the given encoding to which * "unit" maps. */ const char* ut_get_symbol( const ut_unit* const unit, const ut_encoding encoding) { ut_set_status(UT_SUCCESS); return getId(systemToUnitToSymbol, unit, encoding); } /* * Frees resources associated with a unit-system. * * Arguments: * system Pointer to the unit-system to have its associated * resources freed. */ void utimFreeSystem( ut_system* system) { if (system != NULL) { SystemMap* systemMaps[2]; int i; systemMaps[0] = systemToUnitToName; systemMaps[1] = systemToUnitToSymbol; for (i = 0; i < 2; i++) { if (systemMaps[i] != NULL) { UnitToIdMap** const unitToId = (UnitToIdMap**)smFind(systemMaps[i], system); if (unitToId != NULL) utimFree(*unitToId); smRemove(systemMaps[i], system); } } } } udunits-2.2.0/lib/parser.y0000644000175000017500000003046212260406756016611 0ustar amckinstryamckinstry%{ /* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * bison(1)-based parser for decoding formatted unit specifications. * * This module is thread-compatible but not thread-safe. Multi-threaded * access must be externally synchronized. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include "udunits2.h" static ut_unit* _finalUnit; /* fully-parsed specification */ static ut_system* _unitSystem; /* The unit-system to use */ static char* _errorMessage; /* last error-message */ static ut_encoding _encoding; /* encoding of string to be parsed */ static int _restartScanner;/* restart scanner? */ /* * Removes leading and trailing whitespace from a string. * * Arguments: * string NUL-terminated string. Will be modified if it * contains whitespace. * encoding The character-encoding of "string". * Returns: * "string" */ char* ut_trim( char* const string, const ut_encoding encoding) { static const char* asciiSpace = " \t\n\r\f\v"; static const char* latin1Space = " \t\n\r\f\v\xa0"; /* add NBSP */ const char* whiteSpace; char* start; char* stop; size_t len; whiteSpace = encoding == UT_LATIN1 ? latin1Space : asciiSpace; start = string + strspn(string, whiteSpace); for (stop = start + strlen(start); stop > start; --stop) if (strchr(whiteSpace, stop[-1]) == NULL) break; len = stop - start; (void)memmove(string, start, len); string[len] = 0; ut_set_status(UT_SUCCESS); return start; } /* * YACC error routine: */ void uterror( char *s) { static char* nomem = "uterror(): out of memory"; if (_errorMessage != NULL && _errorMessage != nomem) free(_errorMessage); _errorMessage = strdup(s); if (_errorMessage == NULL) _errorMessage = nomem; } %} %union { char* id; /* identifier */ ut_unit* unit; /* "unit" structure */ double rval; /* floating-point numerical value */ long ival; /* integer numerical value */ } %token ERR %token SHIFT %token MULTIPLY %token DIVIDE %token INT %token EXPONENT %token REAL %token ID %token DATE %token CLOCK %token TIMESTAMP %token LOGREF %type unit_spec %type shift_exp %type product_exp %type power_exp %type basic_exp %type timestamp %type number %% unit_spec: /* nothing */ { _finalUnit = ut_get_dimensionless_unit_one(_unitSystem); YYACCEPT; } | shift_exp { _finalUnit = $1; YYACCEPT; } | error { YYABORT; } ; shift_exp: product_exp { $$ = $1; } | product_exp SHIFT REAL { $$ = ut_offset($1, $3); ut_free($1); if ($$ == NULL) YYERROR; } | product_exp SHIFT INT { $$ = ut_offset($1, $3); ut_free($1); if ($$ == NULL) YYERROR; } | product_exp SHIFT timestamp { $$ = ut_offset_by_time($1, $3); ut_free($1); if ($$ == NULL) YYERROR; } | product_exp SHIFT error { ut_status prev = ut_get_status(); ut_free($1); ut_set_status(prev); YYERROR; } ; product_exp: power_exp { $$ = $1; } | product_exp power_exp { $$ = ut_multiply($1, $2); ut_free($1); ut_free($2); if ($$ == NULL) YYERROR; } | product_exp error { ut_status prev = ut_get_status(); ut_free($1); ut_set_status(prev); YYERROR; } | product_exp MULTIPLY power_exp { $$ = ut_multiply($1, $3); ut_free($1); ut_free($3); if ($$ == NULL) YYERROR; } | product_exp MULTIPLY error { ut_status prev = ut_get_status(); ut_free($1); ut_set_status(prev); YYERROR; } | product_exp DIVIDE power_exp { $$ = ut_divide($1, $3); ut_free($1); ut_free($3); if ($$ == NULL) YYERROR; } | product_exp DIVIDE error { ut_status prev = ut_get_status(); ut_free($1); ut_set_status(prev); YYERROR; } ; power_exp: basic_exp { $$ = $1; } | basic_exp INT { $$ = ut_raise($1, $2); ut_free($1); if ($$ == NULL) YYERROR; } | basic_exp EXPONENT { $$ = ut_raise($1, $2); ut_free($1); if ($$ == NULL) YYERROR; } | basic_exp error { ut_status prev = ut_get_status(); ut_free($1); ut_set_status(prev); YYERROR; } ; basic_exp: ID { double prefix = 1; ut_unit* unit = NULL; char* cp = $1; int symbolPrefixSeen = 0; while (*cp) { size_t nchar; double value; unit = ut_get_unit_by_name(_unitSystem, cp); if (unit != NULL) break; unit = ut_get_unit_by_symbol(_unitSystem, cp); if (unit != NULL) break; if (utGetPrefixByName(_unitSystem, cp, &value, &nchar) == UT_SUCCESS) { prefix *= value; cp += nchar; } else { if (!symbolPrefixSeen && utGetPrefixBySymbol(_unitSystem, cp, &value, &nchar) == UT_SUCCESS) { symbolPrefixSeen = 1; prefix *= value; cp += nchar; } else { break; } } } free($1); if (unit == NULL) { ut_set_status(UT_UNKNOWN); YYERROR; } $$ = ut_scale(prefix, unit); ut_free(unit); if ($$ == NULL) YYERROR; } | '(' shift_exp ')' { $$ = $2; } | '(' shift_exp error { ut_status status = ut_get_status(); ut_free($2); ut_set_status(status); YYERROR; } | LOGREF product_exp ')' { $$ = ut_log($1, $2); ut_free($2); if ($$ == NULL) YYERROR; } | LOGREF product_exp error { ut_status status = ut_get_status(); ut_free($2); ut_set_status(status); YYERROR; } | number { $$ = ut_scale($1, ut_get_dimensionless_unit_one(_unitSystem)); } ; number: INT { $$ = $1; } | REAL { $$ = $1; } ; timestamp: DATE { $$ = $1; } | DATE CLOCK { $$ = $1 + $2; } | DATE CLOCK CLOCK { $$ = $1 + ($2 - $3); } | DATE CLOCK INT { int mag = $3 >= 0 ? $3 : -$3; if (mag <= 24) { $$ = $1 + ($2 - ut_encode_clock($3, 0, 0)); } else if (mag >= 100 && mag <= 2400) { $$ = $1 + ($2 - ut_encode_clock($3/100, $3%100, 0)); } else { ut_set_status(UT_SYNTAX); YYERROR; } } | DATE CLOCK ID { int error = 0; if (strcasecmp($3, "UTC") != 0 && strcasecmp($3, "GMT") != 0 && strcasecmp($3, "Z") != 0) { ut_set_status(UT_UNKNOWN); error = 1; } free($3); if (!error) { $$ = $1 + $2; } else { YYERROR; } } | TIMESTAMP { $$ = $1; } | TIMESTAMP CLOCK { $$ = $1 - $2; } | TIMESTAMP INT { int mag = $2 >= 0 ? $2 : -$2; if (mag <= 24) { $$ = $1 - ut_encode_clock($2, 0, 0); } else if (mag >= 100 && mag <= 2400) { $$ = $1 - ut_encode_clock($2/100, $2%100, 0); } else { ut_set_status(UT_SYNTAX); YYERROR; } } | TIMESTAMP ID { int error = 0; if (strcasecmp($2, "UTC") != 0 && strcasecmp($2, "GMT") != 0 && strcasecmp($2, "Z") != 0) { ut_set_status(UT_UNKNOWN); error = 1; } free($2); if (!error) { $$ = $1; } else { YYERROR; } } ; %% #define yymaxdepth utmaxdepth #define yylval utlval #define yychar utchar #define yypact utpact #define yyr1 utr1 #define yyr2 utr2 #define yydef utdef #define yychk utchk #define yypgo utpgo #define yyact utact #define yyexca utexca #define yyerrflag uterrflag #define yynerrs utnerrs #define yyps utps #define yypv utpv #define yys uts #define yy_yys utyys #define yystate utstate #define yytmp uttmp #define yyv utv #define yy_yyv utyyv #define yyval utval #define yylloc utlloc #define yyreds utreds #define yytoks uttoks #define yylhs utyylhs #define yylen utyylen #define yydefred utyydefred #define yydgoto utyydgoto #define yysindex utyysindex #define yyrindex utyyrindex #define yygindex utyygindex #define yytable utyytable #define yycheck utyycheck #define yyname utyyname #define yyrule utyyrule #include "scanner.c" /* * Converts a string in the Latin-1 character set (ISO 8859-1) to the UTF-8 * character set. * * Arguments: * latin1String Pointer to the string to be converted. May be freed * upon return. * Returns: * NULL Failure. ut_handle_error_message() was called. * else Pointer to UTF-8 representation of "string". Must not * be freed. Subsequent calls may overwrite. */ static const char* latin1ToUtf8( const char* const latin1String) { static char* utf8String = NULL; static size_t bufSize = 0; size_t size; const unsigned char* in; unsigned char* out; assert(latin1String != NULL); size = 2 * strlen(latin1String) + 1; if (size > bufSize) { char* buf = realloc(utf8String, size); if (buf != NULL) { utf8String = buf; bufSize = size; } else { ut_handle_error_message("Couldn't allocate %ld-byte buffer: %s", (unsigned long)size, strerror(errno)); return NULL; } } for (in = (const unsigned char*)latin1String, out = (unsigned char*)utf8String; *in; ++in) { # define IS_ASCII(c) (((c) & 0x80) == 0) if (IS_ASCII(*in)) { *out++ = *in; } else { *out++ = 0xC0 | ((0xC0 & *in) >> 6); *out++ = 0x80 | (0x3F & *in); } } *out = 0; return utf8String; } /* * Returns the binary representation of a unit corresponding to a string * representation. * * Arguments: * system Pointer to the unit-system in which the parsing will * occur. * string The string to be parsed (e.g., "millimeters"). There * should be no leading or trailing whitespace in the * string. See ut_trim(). * encoding The encoding of "string". * Returns: * NULL Failure. "ut_get_status()" will be one of * UT_BAD_ARG "system" or "string" is NULL. * UT_SYNTAX "string" contained a syntax * error. * UT_UNKNOWN "string" contained an unknown * identifier. * UT_OS Operating-system failure. See * "errno". * else Pointer to the unit corresponding to "string". */ ut_unit* ut_parse( const ut_system* const system, const char* const string, ut_encoding encoding) { ut_unit* unit = NULL; /* failure */ if (system == NULL || string == NULL) { ut_set_status(UT_BAD_ARG); } else { const char* utf8String; if (encoding != UT_LATIN1) { utf8String = string; } else { utf8String = latin1ToUtf8(string); encoding = UT_UTF8; if (utf8String == NULL) ut_set_status(UT_OS); } if (utf8String != NULL) { YY_BUFFER_STATE buf = ut_scan_string(utf8String); _unitSystem = (ut_system*)system; _encoding = encoding; _restartScanner = 1; #if YYDEBUG utdebug = 0; ut_flex_debug = 0; #endif _finalUnit = NULL; if (utparse() == 0) { int status; int n = yy_c_buf_p - buf->yy_ch_buf; if (n >= strlen(utf8String)) { unit = _finalUnit; /* success */ status = UT_SUCCESS; } else { /* * Parsing terminated before the end of the string. */ ut_free(_finalUnit); status = UT_SYNTAX; } ut_set_status(status); } ut_delete_buffer(buf); } /* utf8String != NULL */ } /* valid arguments */ return unit; } udunits-2.2.0/lib/unitAndId.c0000644000175000017500000000400012260406756017133 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Searchable unit-and-identifier tree. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include "unitAndId.h" #include "udunits2.h" /* * Arguments: * unit The unit. May be freed upon return. * id The identifier (name or symbol). May be freed upon return. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" or "id" is NULL. * UT_OS Operating-system failure. See "errno". * else Pointer to the new unit-and-identifier. */ UnitAndId* uaiNew( const ut_unit* const unit, const char* const id) { UnitAndId* entry = NULL; /* failure */ if (id == NULL || unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("uaiNew(): NULL argument"); } else { entry = malloc(sizeof(UnitAndId)); if (entry == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't allocate %lu-byte data-structure", sizeof(UnitAndId)); } else { entry->id = strdup(id); if (entry->id == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't duplicate identifier"); } else { entry->unit = ut_clone(unit); if (entry->unit == NULL) { assert(ut_get_status() != UT_SUCCESS); free(entry->id); } } if (ut_get_status() != UT_SUCCESS) { free(entry); entry = NULL; } } } return entry; } /* * Frees memory of a unit-and-identifier. * * Arguments: * entry Pointer to the unit-and-identifier or NULL. */ void uaiFree( UnitAndId* const entry) { if (entry != NULL) { free(entry->id); ut_free(entry->unit); free(entry); } } udunits-2.2.0/lib/converter.h0000644000175000017500000001315012260406756017276 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Public header-file for the Unidata units(3) library. */ #ifndef CV_CONVERTER_H_INCLUDED #define CV_CONVERTER_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif typedef union cv_converter cv_converter; /* * Returns the trivial converter (i.e., y = x). * When finished with the converter, the client should pass the converter to * cv_free(). * RETURNS: * The trivial converter. */ cv_converter* cv_get_trivial(void); /* * Returns the reciprocal converter (i.e., y = 1/x). * When finished with the converter, the client should pass the converter to * cv_free(). * RETURNS: * The reciprocal converter. */ cv_converter* cv_get_inverse(void); /* * Returns a scaling converter (i.e., y = ax). * When finished with the converter, the client should pass the converter to * cv_free(). * RETURNS: * The scaling converter. */ cv_converter* cv_get_scale( const double slope); /* * Returns a converter that adds a number to values (i.e., y = x + b). * When finished with the converter, the client should pass the converter to * cv_free(). * ARGUMENTS: * intercept The number to be added. * RETURNS: * NULL Necessary memory couldn't be allocated. * else A converter that adds the given number to values. */ cv_converter* cv_get_offset( const double intercept); /* * Returns a Galilean converter (i.e., y = ax + b). * When finished with the converter, the client should pass the converter to * cv_free(). * ARGUMENTS: * slope The number by which to multiply values. * intercept The number to be added. * RETURNS: * NULL Necessary memory couldn't be allocated. * else A Galilean converter corresponding to the inputs. */ cv_converter* cv_get_galilean( const double slope, const double intercept); /* * Returns a logarithmic converter (i.e., y = log(x) in some base). * When finished with the converter, the client should pass the converter to * cv_free(). * ARGUMENTS: * base The logarithmic base (e.g., 2, M_E, 10). Must be * greater than one. * RETURNS: * NULL "base" is not greater than one or necessary * memory couldn't be allocated. * else A logarithmic converter corresponding to the inputs. */ cv_converter* cv_get_log( const double base); /* * Returns an exponential converter (i.e., y = pow(b, x) in some base "b"). * When finished with the converter, the client should pass the converter to * cv_free(). * * Arguments: * base The desired base. Must be positive. * Returns: * NULL "base" is invalid or necessary memory couldn't be * allocated. * else An exponential converter corresponding to the inputs. */ cv_converter* cv_get_pow( const double base); /* * Returns a converter corresponding to the sequential application of two * other converters. * ARGUMENTS: * first The converter to be applied first. * second The converter to be applied second. * RETURNS: * NULL Either "first" or "second" is NULL or necessary memory couldn't * be allocated. * else A converter corresponding to the sequential application of the * given converters. If one of the input converters is the trivial * converter, then the returned converter will be the other input * converter. */ cv_converter* cv_combine( cv_converter* const first, cv_converter* const second); /* * Frees resources associated with a converter. * ARGUMENTS: * conv The converter to have its resources freed or NULL. */ void cv_free( cv_converter* const conv); /* * Converts a float. * ARGUMENTS: * converter The converter. * value The value to be converted. * RETURNS: * The converted value. */ float cv_convert_float( const cv_converter* converter, const float value); /* * Converts a double. * ARGUMENTS: * converter The converter. * value The value to be converted. * RETURNS: * The converted value. */ double cv_convert_double( const cv_converter* converter, const double value); /* * Converts an array of floats. * ARGUMENTS: * converter The converter. * in The values to be converted. * count The number of values to be converted. * out The output array for the converted values. May * be the same array as "in" or overlap it. * RETURNS: * NULL "out" is NULL. * else A pointer to the output array. */ float* cv_convert_floats( const cv_converter* converter, const float* const in, const size_t count, float* out); /* * Converts an array of doubles. * ARGUMENTS: * converter The converter. * in The values to be converted. * count The number of values to be converted. * out The output array for the converted values. May * be the same array as "in" or overlap it. * RETURNS: * NULL "out" is NULL. * else A pointer to the output array. */ double* cv_convert_doubles( const cv_converter* converter, const double* const in, const size_t count, double* out); /* * Returns a string representation of a converter. * ARGUMENTS: * conv The converter. * buf The buffer into which to write the expression. * max The size of the buffer. * variable The string to be used as the input value for the * converter. * RETURNS * <0 An error was encountered. * else The number of bytes formatted excluding the terminating null. */ int cv_get_expression( const cv_converter* const conv, char* const buf, size_t max, const char* const variable); #ifdef __cplusplus } #endif #endif udunits-2.2.0/lib/unitAndId.h0000644000175000017500000000166112260406756017152 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ #ifndef UT_UNIT_SEARCH_NODE_H_INCLUDED #define UT_UNIT_SEARCH_NODE_H_INCLUDED #include "udunits2.h" typedef struct { char* id; ut_unit* unit; } UnitAndId; #ifdef __cplusplus extern "C" { #endif /* * Arguments: * id The identifier (name or symbol). May be freed upon return. * unit The unit. Must not be freed upon successful return until the * returned unit-search-node is no longer needed. * Returns: * NULL "id" is NULL. * NULL "node" is NULL. * NULL Out of memory. * else Pointer to the new unit search node. */ UnitAndId* uaiNew( const ut_unit* const unit, const char* const id); void uaiFree( UnitAndId* const node); #ifdef __cplusplus } #endif #endif udunits-2.2.0/lib/udunits2-common.xml0000644000175000017500000015037512260406756020716 0ustar amckinstryamckinstry s sec A amp K °K degree_kelvin degrees_kelvin degree_K degrees_K degreeK degreesK deg_K degs_K degK degsK cd candle mole einstein Hz baud Bd bps degree_Celsius celsius degree_C degrees_C degreeC degreesC deg_C degs_C degC degsC knot kt kts 6.02214179e23/mol avogadro_constant 0.01 percent % 1e-6 ppm ppmv 1e-9 ppb ppbv 1e-12 ppt pptv 1e-15 ppq ppqv 0.9 arc_degree grade 2 pi rad circle cycle turn revolution rotation arc_degree degree_north degrees_north degree_N degrees_N degreeN degreesN degree_east degrees_east degree_E degrees_E degreeE degreesE degree_true degrees_true degree_T degrees_T degreeT degreesT -1 degree_east degree_west degrees_west degree_W degrees_W degreeW degreesW 2.916667e-2 kg assay_ton 2.834952e-2 kg avoirdupois_ounce 4.5359237e-1 kg avoirdupois_pound pound lb 2e-4 kg carat 6.479891e-5 kg grain gr 5.080235e1 kg long_hundredweight 1.555174e-3 kg pennyweight 4.535924e1 kg short_hundredweight 14.59390 kg slug 3.110348e-2 kg troy_ounce apothecary_ounce 3.732417e-1 kg troy_pound apothecary_pound 20 grain scruple 60 grain apdram 480 grain apounce 5760 grain appound 94 pound bag 2000 pound short_ton ton 2240 pound long_ton 1e-15 m fermi 9.46073e15 m light_year 1e-6 m micron 2.54e-5 m mil 3.085678e16 m parsec 3.514598e-4 m printers_point 2.011684e1 m chain 12 printers_point printers_pica pica nautical_mile nmile (1200/3937) m US_survey_foot US_survey_feet 3 US_survey_feet US_survey_yard 5280 US_survey_feet US_survey_mile US_statute_mile 16.5 US_survey_feet rod pole perch 660 US_survey_feet furlong 6 US_survey_feet fathom 2.54 cm international_inch inch in 12 international_inches international_foot international_feet foot feet ft 3 international_feet international_yard yard yd 5280 international_feet international_mile mile mi inch/72 big_point inch/3 barleycorn 191.835 foot arpentlin rotation/second rotation_per_second rotations_per_second rps cps rotation/minute rpm 1.111111e-7 kg/m denier 1e-6 kg/m tex 5.72135e-11 kg/(Pa.s.m^2) perm_0C perms_0C 5.74525e-11 kg/(Pa.s.m^2) perm_23C perms_23C 5.067075e-10 m^2 circular_mil 9.869233e-13 m^2 darcy 160 rod^2 acre 1.233489e3 m^3 acre_foot acre_feet 2.359737e-3 m^3 board_foot board_feet 3.523907e-2 m^3 bushel bu bushel/4 peck pk 4.546090e-3 m^3 Canadian_liquid_gallon 4.404884e-3 m^3 US_dry_gallon cm^3 cc 1 m^3 stere 2.831685 m^3 register_ton US_dry_gallon/4 US_dry_quart dry_quart US_dry_gallon/8 US_dry_pint dry_pint 3.785412e-3 m^3 US_liquid_gallon liquid_gallon gallon 42 US_liquid_gallon barrel bbl barrel/4 firkin US_liquid_gallon/4 US_liquid_quart liquid_quart quart US_liquid_gallon/8 US_liquid_pint liquid_pint pint pt US_liquid_gallon/16 US_liquid_cup liquid_cup cup US_liquid_gallon/32 US_liquid_gill liquid_gill gill US_liquid_gallon/128 US_fluid_ounce US_liquid_ounce fluid_ounce liquid_ounce oz floz US_fluid_ounce/2 tablespoon Tbl Tbsp tbsp Tblsp tblsp US_fluid_ounce/8 fldr US_fluid_ounce/16 dram dr tablespoon/3 teaspoon tsp 4.546090e-3 m^3 UK_liquid_gallon UK_liquid_gallon/4 UK_liquid_quart UK_liquid_gallon/8 UK_liquid_pint UK_liquid_gallon/16 UK_liquid_cup UK_liquid_gallon/32 UK_liquid_gill UK_liquid_gallon/160 UK_fluid_ounce UK_liquid_ounce lg(re (1e-6 m)^3) BZ 1e-8 s shake 8.616409e4 s sidereal_day 3.590170e3 s sidereal_hour 5.983617e1 s sidereal_minute 0.9972696 s sidereal_second 3.155815e7 s sidereal_year 3.15569259747e7 s tropical_year year yr 29.530589 day lunar_month 365 day common_year 366 day leap_year 365.25 day Julian_year 365.2425 day Gregorian_year 27.321661 day sidereal_month 27.321582 day tropical_month 14 day fortnight 7 day week 0.01 s jiffy 1e9 year eon year/12 month 1e6 m^3/s sverdrup 9.806650 m/s^2 standard_free_fall standard_free_fall gravity gravity 1000 kg/m^3 conventional_water water H2O h2o gravity 999.972 kg/m^3 water_4C waters_4C water_39F waters_39F gravity 999.001 kg/m^3 water_60F waters_60F gravity 13595.10 kg/m^3 mercury_0C mercuries_0C mercury_32F mercuries_32F conventional_mercury conventional_mercuries Hg gravity 13556.8 kg/m^3 mercury_60F mercuries_60F standard_free_fall force 1e-5 N dyne 9.806650e-3 N pond 9.806650 N force_kilogram kilogram_force kilograms_force kgf 2.780139e-1 N force_ounce ounce_force ounces_force ozf 4.4482216152605 N force_pound pound_force pounds_force lbf 1.382550e-1 N poundal gram force gram_force grams_force force_gram gf 2000 force_pound force_ton ton_force tons_force 1000 lbf kip 1.01325e5 Pa standard_atmosphere atmosphere atm 1 kg gravity/cm2 technical_atmosphere at cm H2O cm_H2O cmH2O inch water_39F inch_H2O_39F inches_H2O_39F inch water_60F inch_H2O_60F inches_H2O_60F foot water foot_water feet_water foot_H2O feet_H2O footH2O feetH2O ftH2O fth2o cm Hg cm_Hg cmHg mm mercury_0C millimeter_Hg_0C millimeters_Hg_0C inch mercury_32F inch_Hg_32F inches_Hg_32F inch mercury_60F inch_Hg_60F inches_Hg_60F mm Hg millimeter_Hg millimeters_Hg torr mm_Hg mm_hg mmHg mmhg inch Hg inch_Hg inches_Hg in_Hg inHg 1 pound gravity/in^2 psi kip/in^2 ksi 0.1 N/m^2 barie barye lg(re 20e-6 Pa) B_SPL 1e-1 Pa.s poise 1e-4 m^2/s stokes St 10/(Pa.s) rhe 1e-7 J erg 1.05505585262e3 J IT_Btu IT_Btus Btu Btus 1.05506e8 J EC_therm 4.184000 J thermochemical_calorie 4.1868 J IT_calorie calorie cal 4.184 MJ/kg TNT 4.184e9 J ton_TNT tons_TNT 1.054804e8 J US_therm therm thm watt.hour watthour 1e9 eV bev V.A voltampere VA 9.80950e3 W boiler_horsepower 7.456999e2 W shaft_horsepower horsepower hp 7.35499e2 W metric_horsepower 7.460000e2 W electric_horsepower 7.46043e2 W water_horsepower 7.4570e2 W UK_horsepower 12000 Btu/hr refrigeration_ton ton_of_refrigeration tons_of_refrigeration lg(re 1 W) BW lg(re 1 mW) Bm 1.55e-1 K.m^2/W clo 10 A abampere 7.957747e-1 A gilbert 3.335640e-10 A statampere 10 A biot 1e9 F abfarad 1e-9 H abhenry 1e9 S abmho 1e-9 ohm abohm 1e-8 V abvolt 1.602176487e-19 C e 9.64957e4 C chemical_faraday 9.65219e4 C physical_faraday 9.648531e4 C C12_faraday faraday 1e-9 T gamma 1e-4 T gauss 1e-8 Wb maxwell 7.957747e1 A/m oersted Oe 3.335640e-10 C statcoulomb 1.112650e-12 F statfarad 8.987554e11 H stathenry 1.112650e-12 S statmho 8.987554e11 ohm statohm 2.997925e2 V statvolt 1.256637e-7 Wb unit_pole lg(re 1 V) BV lg(re 0.775 V) Bv lg(re 1e-6 V) BµV K/1.8 °R degree_rankine degrees_rankine degreeR degreesR degree_R degrees_R degR degsR deg_R degs_R °R @ 459.67 °F fahrenheit degree_fahrenheit degrees_fahrenheit degreeF degreesF degree_F degrees_F degF degsF deg_F degs_F 1.076391e-1 lx footcandle 3.426259 cd/m^2 footlambert (1e4/pi) cd/m^2 lambert 1e4 cd/m^2 stilb sb 1e4 lm/m^2 phot ph 1 cd/m^2 nit nt 4.184000e4 J/m^2 langley cd/(pi m^2) blondel apostilb 100/m kayser gravity geopotential dynamic gp 2056 hours work_year work_year/12 work_month 1e-6 m^2 s^-1 K kg^-1 potential_vorticity_unit PVU 1 count 1 bit 446.2 micromoles/meter^2 dobson DU mol/6.02214129e23 molecule molec udunits-2.2.0/lib/formatter.c0000644000175000017500000011350412260406756017271 0ustar amckinstryamckinstry/* * Copyright 2013 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file COPYRIGHT * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * This module is thread-compatible but not thread-safe. */ /*LINTLIBRARY*/ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include #include #include "udunits2.h" #include "unitToIdMap.h" typedef const char* (*IdGetter)(const ut_unit*, ut_encoding); typedef int (*ProductPrinter)(const ut_unit* const*, const int*, int, char*, size_t, IdGetter); /* * Formatting parameters: */ typedef struct { IdGetter getId; ProductPrinter printProduct; char* buf; size_t size; int getDefinition; ut_encoding encoding; int addParens; int nchar; } FormatPar; #undef ABS #define ABS(x) ((x) < 0 ? -(x) : (x)) #define RETURNS_NAME(getId) ((getId) == getName) #define SUBTRACT_SIZET(a, b) ((a) > (b) ? (a) - (b) : 0) static int asciiPrintProduct( const ut_unit* const* const basicUnits, const int* const powers, const int count, char* const buf, const size_t max, IdGetter getId); static int latin1PrintProduct( const ut_unit* const* const basicUnits, const int* const powers, const int count, char* const buf, const size_t max, IdGetter getId); static int utf8PrintProduct( const ut_unit* const* const basicUnits, const int* const powers, const int count, char* const buf, const size_t max, IdGetter getId); static ut_visitor formatter; /* * Returns a name for a unit. * * Arguments: * unit Pointer to the unit to have it's name returned. * encoding The encoding of the name to be returned. * Returns: * NULL A name is not available in the desired encoding. * else Pointer to the name. */ static const char* getName( const ut_unit* const unit, const ut_encoding encoding) { const char* name; name = ut_get_name(unit, encoding); if (name == NULL) name = ut_get_name(unit, UT_ASCII); return name; } /* * Returns a symbol for a unit. * * Arguments: * unit Pointer to the unit to have it's symbol returned. * encoding The encoding of the symbol to be returned. * Returns: * NULL A symbol is not available in the desired encoding. * else Pointer to the symbol. */ static const char* getSymbol( const ut_unit* const unit, const ut_encoding encoding) { const char* symbol; symbol = ut_get_symbol(unit, encoding); if (symbol == NULL) symbol = ut_get_symbol(unit, UT_ASCII); return symbol; } /* * Formats a unit. * * Arguments: * unit Pointer to the unit to be formatted. * buf Pointer to the buffer into which to print the formatted * unit. * size Size of the buffer. * useNames Use unit names rather than unit symbols. * getDefinition Returns the definition of "unit" in terms of basic * units. * encoding The type of encoding to use. * addParens Whether or not to add bracketing parentheses if * whitespace is printed. * Returns: * -1 Failure: "utFormStatus()" will be * UT_BAD_ARG "unit" is NULL or "buf" is NULL. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static int format( const ut_unit* const unit, char* buf, size_t size, const int useNames, const int getDefinition, ut_encoding encoding, const int addParens) { int nchar = -1; /* failure */ if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("format(): NULL unit argument"); } else if (buf == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("format(): NULL buffer argument"); } else { FormatPar formatPar; formatPar.buf = buf; formatPar.size = size; formatPar.getId = useNames ? getName : getSymbol; formatPar.getDefinition = getDefinition; formatPar.encoding = encoding; formatPar.printProduct = encoding == UT_ASCII ? asciiPrintProduct : encoding == UT_LATIN1 ? latin1PrintProduct : utf8PrintProduct; formatPar.addParens = addParens; formatPar.nchar = 0; if (ut_accept_visitor(unit, &formatter, &formatPar) == UT_SUCCESS) nchar = formatPar.nchar; } return nchar; } /******************************************************************************* * Basic-Unit Formatting: ******************************************************************************/ /* * Prints a basic-unit. * * Arguments: * unit The basic-unit to be printed. * buf The buffer into which to print "unit". * size The size of "buf". * Returns: * -1 Failure. The identifier for "unit" could not be * obtained. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static int printBasic( const ut_unit* const unit, char* const buf, const size_t size, IdGetter getId, ut_encoding encoding) { const char* const id = getId(unit, encoding); return id == NULL ? -1 : snprintf(buf, size, "%s", id); } /* * Formats a basic-unit. * * Arguments: * unit The basic-unit to be formatted. * arg The formatting parameters. * Returns: * -1 Failure. The identifier for "unit" could not be * obtained. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static ut_status formatBasic( const ut_unit* const unit, void* arg) { FormatPar* formatPar = (FormatPar*)arg; int nchar = printBasic(unit, formatPar->buf, formatPar->size, formatPar->getId, formatPar->encoding); formatPar->nchar = nchar < 0 ? nchar : formatPar->nchar + nchar; return nchar < 0 ? UT_VISIT_ERROR : UT_SUCCESS; } /******************************************************************************* * Product-Unit Formatting: ******************************************************************************/ /* * Prints a product-unit using the ASCII character-set. * * Arguments: * basicUnits Pointer to pointers to the basic-units that constitute * the product-unit. * powers Pointer to the powers associated with each basic-unit. * count The number of basic-units. * buf Pointer to the buffer into which to print the basic- * units. * size The size of "buf" in bytes. * getId Returns the identifier for a unit. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static int asciiPrintProduct( const ut_unit* const* const basicUnits, const int* const powers, const int count, char* const buf, size_t size, IdGetter getId) { int nchar = snprintf(buf, size, "%s", ""); if (nchar >= 0) { int i; size = SUBTRACT_SIZET(size, nchar); for (i = 0; i < count && nchar >= 0; i++) { int n; /* * Append separator if appropriate. */ if (nchar > 0) { n = RETURNS_NAME(getId) ? snprintf(buf+nchar, size, "%s", "-") : snprintf(buf+nchar, size, "%s", "."); if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); } /* * Append unit identifier. */ n = printBasic(basicUnits[i], buf+nchar, size, getId, UT_ASCII); if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); /* * Append exponent if appropriate. */ if (powers[i] != 1) { n = RETURNS_NAME(getId) ? snprintf(buf+nchar, size, "^%d", powers[i]) : snprintf(buf+nchar, size, "%d", powers[i]); if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); } } /* loop over basic-units */ } /* "buf" initialized */ return nchar; } /* * Prints a product of basic-units using the UTF-8 character-set. * * Arguments: * basicUnits Pointer to pointers to the basic-units whose product * is to be printed. * powers Pointer to the powers associated with each basic-unit. * count The number of basic-units. * buf Pointer to the buffer into which to print the basic- * units. * size The size of "buf" in bytes. * getId Returns the identifier for a unit. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static int utf8PrintProduct( const ut_unit* const* const basicUnits, const int* const powers, const int count, char* const buf, size_t size, IdGetter getId) { int nchar = snprintf(buf, size, "%s", ""); if (nchar >= 0) { int iBasic; size = SUBTRACT_SIZET(size, nchar); for (iBasic = 0; iBasic < count; iBasic++) { int power = powers[iBasic]; if (power != 0) { /* * The current basic-unit must be printed. */ int n; if (nchar > 0) { /* * Append mid-dot separator. */ n = snprintf(buf+nchar, size, "%s", "\xc2\xb7"); if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); } /* * Append unit identifier. */ n = printBasic(basicUnits[iBasic], buf+nchar, size, getId, UT_UTF8); if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); if (power != 1) { /* * Append exponent. */ static const char* exponentStrings[10] = { "\xe2\x81\xb0", /* 0 */ "\xc2\xb9", /* 1 */ "\xc2\xb2", /* 2 */ "\xc2\xb3", /* 3 */ "\xe2\x81\xb4", /* 4 */ "\xe2\x81\xb5", /* 5 */ "\xe2\x81\xb6", /* 6 */ "\xe2\x81\xb7", /* 7 */ "\xe2\x81\xb8", /* 8 */ "\xe2\x81\xb9", /* 9 */ }; if (power < 0) { /* * Append superscript minus sign. */ n = snprintf(buf+nchar, size, "%s", "\xe2\x81\xbb"); if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); power = -power; } /* * Append UTF-8 encoding of exponent magnitude. */ { static int* digit = NULL; digit = realloc(digit, (size_t)((sizeof(powers[0])* CHAR_BIT*(M_LOG10E/M_LOG2E)) + 1)); if (digit == NULL) { nchar = -1; } else { int idig = 0; for (; power > 0; power /= 10) digit[idig++] = power % 10; while (idig-- > 0) { n = snprintf(buf+nchar, size, "%s", exponentStrings[digit[idig]]); if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); } if (nchar < 0) break; } } /* exponent digits block */ } /* must print exponent */ } /* must print basic-unit */ } /* loop over basic-units */ } /* "buf" initialized */ return nchar; } static const int* globalPowers = NULL; static int compareExponents( const void* i, const void* j) { return globalPowers[*(const int*)j] - globalPowers[*(const int*)i]; } /* * Returns the order of basic-unit powers in decreasing order. * * Arguments: * powers Pointer to the powers of the basic-units. * count The number of powers. * positiveCount Pointer to pointer to the number of positive powers. * Set on and only on success. * negativeCount Pointer to pointer to the number of negative powers. * Set on and only on success. * Returns: * NULL Failure. See errno. * else Success. Pointer to indexes of "powers" in decreasing * order. */ static void getBasicOrder( const int* const powers, const int count, int* const order, int* const positiveCount, int* const negativeCount) { int nNeg = 0; int nPos = 0; int n = 0; int i; for (i = 0; i < count; i++) { if (powers[i] < 0) { ++nNeg; order[n++] = i; } else if (powers[i] > 0) { ++nPos; order[n++] = i; } } *negativeCount = nNeg; *positiveCount = nPos; globalPowers = powers; qsort(order, n, sizeof(int), compareExponents); } /* * Prints the product of a set of basic-units using the ISO-8859-1 (Latin-1) * character-set. * * Arguments: * buf Pointer to the buffer into which to print the basic- * units. * size The size of "buf" in bytes. * basicUnits Pointer to pointers to the basic-units. * powers Pointer to the powers associated with each basic-unit. * order Pointer to indexes of "powers". "order[i]" is the * index of "basicUnits" and "powers" for the "i"th * position. * count The number of basic-units. * getId Returns the identifier for a unit. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static int latin1PrintBasics( char* const buf, size_t size, const ut_unit* const* basicUnits, const int* const powers, const int* const order, const int count, IdGetter getId) { int needSeparator = 0; int nchar = 0; int i; for (i = 0; i < count; i++) { int n; int j = order[i]; int power = ABS(powers[j]); if (power != 0) { if (needSeparator) { n = snprintf(buf+nchar, size, "%s", "\xb7"); /* raised dot */ if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); } /* * Append unit identifier. */ n = printBasic(basicUnits[j], buf+nchar, size, getId, UT_LATIN1); if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); needSeparator = 1; /* * Append exponent if appropriate. */ if (power != 1) { n = snprintf(buf+nchar, size, "%s", power == 2 ? "\xb2" : "\xb3"); /* superscript 2, superscript 3 */ if (n < 0) { nchar = n; break; } nchar += n; size = SUBTRACT_SIZET(size, n); } } /* exponent not zero */ } /* loop over positive exponents */ return nchar; } /* * Prints a product-unit using the ISO-8859-1 (Latin-1) character-set. * * Arguments: * basicUnits Pointer to pointers to the basic-units that constitute * the product-unit. * powers Pointer to the powers associated with each basic-unit. * count The number of basic-units. * buf Pointer to the buffer into which to print the basic- * units. * size The size of "buf" in bytes. * getId Returns the identifier for a unit. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static int latin1PrintProduct( const ut_unit* const* const basicUnits, const int* const powers, const int count, char* const buf, size_t size, IdGetter getId) { int nchar; int i; for (i = 0; i < count; i++) if (powers[i] < -3 || powers[i] > 3) break; if (i < count) { /* * At least one exponent can't be represented in ISO 8859-1. Use * the ASCII encoding instead. */ nchar = asciiPrintProduct(basicUnits, powers, count, buf, size, getId); } else { int positiveCount; int negativeCount; int* order = malloc(count*sizeof(int)); if (order == NULL) { nchar = -1; } else { getBasicOrder(powers, count, order, &positiveCount, &negativeCount); nchar = snprintf(buf, size, "%s", ""); if (nchar >= 0 && (positiveCount + negativeCount > 0)) { int n; size = SUBTRACT_SIZET(size, nchar); if (positiveCount == 0) { n = snprintf(buf+nchar, size, "%s", "1"); if (0 > n) { nchar = n; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } } else { n = latin1PrintBasics(buf+nchar, size, basicUnits, powers, order, positiveCount, getId); if (0 > n) { nchar = n; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } } if (nchar >= 0 && negativeCount > 0) { n = snprintf(buf+nchar, size, "%s", negativeCount == 1 ? "/" : "/("); if (0 > n) { nchar = n; } else { nchar += n; size = SUBTRACT_SIZET(size, n); n = latin1PrintBasics(buf+nchar, size, basicUnits, powers, order+positiveCount, negativeCount, getId); if (0 > n) { nchar = n; } else { nchar += n; size = SUBTRACT_SIZET(size, n); if (negativeCount > 1) { n = snprintf(buf+nchar, size, "%s", ")"); if (0 > n) { nchar = n; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } } } } /* solidus appended */ } /* positive exponents printed */ } /* "buf" initialized */ (void)free(order); } /* "order" allocated */ } /* using Latin-1 encoding */ return nchar; } /* * Prints a product-unit. * * Arguments: * unit Pointer to the product-unit to be formatted. * count The number of basic-units that constitute the * product-unit. * basicUnits Pointer to pointers to the basic-units that constitute * the product-unit. * powers Pointer to the powers associated with each basic-unit * of "basicUnits". * arg The formatting parameters. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static ut_status formatProduct( const ut_unit* const unit, const int count, const ut_unit* const* const basicUnits, const int* const powers, void* arg) { FormatPar* formatPar = (FormatPar*)arg; int nchar; if (ut_compare(unit, ut_get_dimensionless_unit_one(ut_get_system(unit))) == 0) { /* * The dimensionless unit one is special. */ (void)strncpy(formatPar->buf, "1", formatPar->size); nchar = formatPar->size > 0 ? 1 : 0; } else { if (formatPar->getDefinition) { nchar = formatPar->printProduct(basicUnits, powers, count, formatPar->buf, formatPar->size, formatPar->getId); } else { const char* id = formatPar->getId(unit, formatPar->encoding); nchar = id == NULL ? formatPar->printProduct(basicUnits, powers, count, formatPar->buf, formatPar->size, formatPar->getId) : snprintf(formatPar->buf, formatPar->size, "%s", id); } } formatPar->nchar = nchar < 0 ? nchar : formatPar->nchar + nchar; return nchar < 0 ? UT_VISIT_ERROR : UT_SUCCESS; } /******************************************************************************* * Galilean-Unit Formatting: ******************************************************************************/ /* * Prints a Galilean-unit. * * Arguments: * scale The number of "unit"s in the Galilean-unit. * unit Pointer to the unit underlying the Galilean-unit. * offset The offset of the Galilean-unit in units of "unit". * buf Pointer to the buffer into which to print the Galilean- * unit. * size The size of "buf" in bytes. * getId Returns the identifier for a unit. * getDefinition Returns the definition of "unit" in terms of basic * units. * encoding The type of encoding to use. * addParens Whether or not to add bracketing parentheses if * whitespace is printed. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static int printGalilean( double scale, const ut_unit* const unit, double offset, char* const buf, size_t size, IdGetter getId, const int getDefinition, const ut_encoding encoding, const int addParens) { int n; int nchar = 0; int needParens = 0; if (scale != 1) { needParens = addParens; n = snprintf(buf, size, needParens ? "(%.*g " : "%.*g ", DBL_DIG, scale); if (0 > n) { nchar = n; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } } if (0 <= nchar) { n = format(unit, buf+nchar, size, RETURNS_NAME(getId), getDefinition, encoding, 1); if (n < 0) { nchar = n; } else { nchar += n; size = SUBTRACT_SIZET(size, n); if (offset != 0) { needParens = addParens; n = RETURNS_NAME(getId) ? snprintf(buf+nchar, size, " from %.*g", DBL_DIG, offset) : snprintf(buf+nchar, size, " @ %.*g", DBL_DIG, offset); if (0 > n) { nchar = n; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } } /* non-zero offset */ if (nchar >= 0) { if (needParens) { n = snprintf(buf+nchar, size, "%s", ")"); if (0 > n) { nchar = n; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } } } /* printed offset if appropriate */ } /* underlying unit printed */ } /* scale printed if appropriate */ return nchar; } /* * Formats a Galilean-unit. * * Arguments: * unit Pointer to the Galilean-unit to be formatted. * scale The number of "underlyingUnit"s in "unit". * underlyingUnit Pointer to the unit that underlies "unit". * offset The offset of "unit" in units of "underlyingUnit". * arg Pointer to the formatting parameters. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static ut_status formatGalilean( const ut_unit* const unit, const double scale, const ut_unit* const underlyingUnit, double offset, void* arg) { FormatPar* formatPar = (FormatPar*)arg; int nchar; if (formatPar->getDefinition) { nchar = printGalilean(scale, underlyingUnit, offset, formatPar->buf, formatPar->size, formatPar->getId, formatPar->getDefinition, formatPar->encoding, formatPar->addParens); } else { const char* id = formatPar->getId(unit, formatPar->encoding); nchar = id == NULL ? printGalilean(scale, underlyingUnit, offset, formatPar->buf, formatPar->size, formatPar->getId, formatPar->getDefinition, formatPar->encoding, formatPar->addParens) : snprintf(formatPar->buf, formatPar->size, "%s", id); } formatPar->nchar = nchar < 0 ? nchar : formatPar->nchar + nchar; return nchar < 0 ? UT_VISIT_ERROR : UT_SUCCESS; } /******************************************************************************* * Timestamp-Unit Formatting: ******************************************************************************/ /* * Prints a timestamp-unit. * * Arguments: * underlyingUnit Pointer to the unit underlying the timestamp-unit. * year The UTC year of the origin. * month The UTC month of the origin (1 through 12). * day The UTC day of the origin (1 through 32). * hour The UTC hour of the origin (0 through 23). * minute The UTC minute of the origin (0 through 59). * second The UTC second of the origin (0 through 60). * resolution The resolution of the origin in seconds. * buf Pointer to the buffer into which to print the * timestamp-unit. * size The size of "buf" in bytes. * getId Returns the identifier for a unit. * getDefinition Returns the definition of "unit" in terms of basic * units. * encoding The type of encoding to use. * addParens Whether or not to add bracketing parentheses if * whitespace is printed. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static int printTimestamp( const ut_unit* const underlyingUnit, const int year, const int month, const int day, const int hour, const int minute, const double second, const double resolution, char* const buf, size_t size, IdGetter getId, const int getDefinition, const ut_encoding encoding, const int addParens) { int n; int nchar = 0; if (addParens) { n = snprintf(buf, size, "%s", "("); if (0 > n) { nchar = -1; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } } if (nchar >= 0) { int useNames = RETURNS_NAME(getId); n = format(underlyingUnit, buf+nchar, size, useNames, getDefinition, encoding, 1); nchar = n < 0 ? n : nchar + n; if (nchar >= 0) { int useSeparators = useNames || year < 1000 || year > 9999; n = snprintf(buf+nchar, size, useSeparators ? " %s %d-%02d-%02d %02d:%02d" : " %s %d%02d%02dT%02d%02d", useNames ? "since" : "@", year, month, day, hour, minute); if (0 > n) { nchar = -1; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } if (nchar >= 0) { int decimalCount = -(int)floor(log10(resolution)); if (decimalCount > -2) { n = snprintf(buf+nchar, size, useSeparators ? ":%0*.*f" : "%0*.*f", decimalCount+3, decimalCount, second); if (0 > n) { nchar = -1; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } } /* sufficient precision for seconds */ if (nchar >= 0) { n = snprintf(buf+nchar, size, "%s", addParens ? " UTC)" : " UTC"); if (0 > n) { nchar = -1; } else { nchar += n; size = SUBTRACT_SIZET(size, n); } } /* printed seconds if appropriate */ } /* printed year through minute */ } /* underlying unit printed */ } /* leading "(" printed if appropriate */ return nchar; } /* * Formats a timestamp-unit. * * Arguments: * unit Pointer to the timestamp-unit to be formatted. * underlyingUnit Pointer to the unit that underlies "unit". * origin The encoded origin of the timestamp-unit. * arg Pointer to the formatting parameters. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static ut_status formatTimestamp( const ut_unit* const unit, const ut_unit* const underlyingUnit, const double origin, void* arg) { FormatPar* formatPar = (FormatPar*)arg; int nchar; int year; int month; int day; int hour; int minute; double second; double resolution; ut_decode_time(origin, &year, &month, &day, &hour, &minute, &second, &resolution); if (formatPar->getDefinition) { nchar = printTimestamp(underlyingUnit, year, month, day, hour, minute, second, resolution, formatPar->buf, formatPar->size, formatPar->getId, formatPar->getDefinition, formatPar->encoding, formatPar->addParens); } else { const char* id = formatPar->getId(unit, formatPar->encoding); nchar = id == NULL ? printTimestamp(underlyingUnit, year, month, day, hour, minute, second, resolution, formatPar->buf, formatPar->size, formatPar->getId, formatPar->getDefinition, formatPar->encoding, formatPar->addParens) : snprintf(formatPar->buf, formatPar->size, "%s", id); } formatPar->nchar = nchar < 0 ? nchar : formatPar->nchar + nchar; return nchar < 0 ? UT_VISIT_ERROR : UT_SUCCESS; } /******************************************************************************* * Logarithmic-Unit Formatting: ******************************************************************************/ /* * Prints a logarithmic-unit. * * Arguments: * base The base of the logarithm (e.g., 2, M_E, 10). * reference Pointer to the reference-level of the logarithmic-unit. * buf Pointer to the buffer into which to print the * logarithmic-unit. * size The size of "buf" in bytes. * getId Returns the identifier for a unit. * getDefinition Returns the definition of "unit" in terms of basic * units. * encoding The type of encoding to use. * addParens Whether or not to add bracketing parentheses if * whitespace is printed. * Returns: * -1 Failure. See errno. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ static int printLogarithmic( const double base, const ut_unit* const reference, char* buf, size_t size, IdGetter getId, const int getDefinition, const ut_encoding encoding, const int addParens) { char refSpec[512]; int nchar = format(reference, refSpec, sizeof(refSpec)-1, RETURNS_NAME(getId), getDefinition, encoding, 0); if (nchar >= 0) { const char* amount; refSpec[nchar] = 0; amount = isalpha(refSpec[0]) ? "1 " : ""; if (base == 2) { nchar = snprintf(buf, size, "lb(re %s%s)", amount, refSpec); } else if (base == M_E) { nchar = snprintf(buf, size, "ln(re %s%s)", amount, refSpec); } else if (base == 10) { nchar = snprintf(buf, size, "lg(re %s%s)", amount, refSpec); } else { nchar = snprintf(buf, size, addParens ? "(%.*g ln(re %s%s))" : "%.*g ln(re %s%s)", DBL_DIG, 1/log(base), amount, refSpec); } } /* printed reference unit */ return nchar; } /* * Formats a logarithmic-unit. * * Arguments: * unit Pointer to the logarithmic-unit to be formatted. * base The base of the logarithm (e.g., 2, M_E, 10). * reference Pointer to the reference-level of "unit". * arg Pointer to the formatting parameters. * Returns: * UT_VISIT_ERROR Failure. * UT_SUCCESS Success. */ static ut_status formatLogarithmic( const ut_unit* const unit, const double base, const ut_unit* const reference, void* arg) { FormatPar* formatPar = (FormatPar*)arg; int nchar; if (formatPar->getDefinition) { nchar = printLogarithmic(base, reference, formatPar->buf, formatPar->size, formatPar->getId, formatPar->getDefinition, formatPar->encoding, formatPar->addParens); } else { const char* id = formatPar->getId(unit, formatPar->encoding); nchar = id == NULL ? printLogarithmic(base, reference, formatPar->buf, formatPar->size, formatPar->getId, formatPar->getDefinition, formatPar->encoding, formatPar->addParens) : snprintf(formatPar->buf, formatPar->size, "%s", id); } formatPar->nchar = nchar < 0 ? nchar : formatPar->nchar + nchar; return nchar < 0 ? UT_VISIT_ERROR : UT_SUCCESS; } /******************************************************************************* * This module as a unit-visitor: ******************************************************************************/ static ut_visitor formatter = { formatBasic, formatProduct, formatGalilean, formatTimestamp, formatLogarithmic }; /****************************************************************************** * Public API: ******************************************************************************/ /* * Formats a unit. * * Arguments: * unit Pointer to the unit to be formatted. * buf Pointer to the buffer into which to format "unit". * size Size of the buffer in bytes. * opts Formatting options: bitwise-OR of zero or more of the * following: * UT_NAMES Use unit names instead of * symbols * UT_DEFINITION The formatted string should be * the definition of "unit" in * terms of basic-units instead of * stopping any expansion at the * highest level possible. * UT_ASCII The string should be formatted * using the ASCII character set * (default). * UT_LATIN1 The string should be formatted * using the ISO Latin-1 (alias * ISO-8859-1) character set. * UT_UTF8 The string should be formatted * using the UTF-8 character set. * UT_LATIN1 and UT_UTF8 are mutually exclusive: they may * not both be specified. * Returns: * -1 Failure: "ut_get_status()" will be * UT_BAD_ARG "unit" or "buf" is NULL, or both * UT_LATIN1 and UT_UTF8 specified. * UT_CANT_FORMAT "unit" can't be formatted in * the desired manner. * else Success. Number of bytes that would be printed if * "size" were sufficiently large excluding the * terminating NUL. */ int ut_format( const ut_unit* const unit, char* buf, size_t size, unsigned opts) { int nchar = -1; /* failure */ const int useNames = opts & UT_NAMES; const int getDefinition = opts & UT_DEFINITION; const ut_encoding encoding = (ut_encoding)(opts & (unsigned)(UT_ASCII | UT_LATIN1 | UT_UTF8)); if (unit == NULL || buf == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("NULL argument"); } else if ((encoding & UT_LATIN1) && (encoding & UT_UTF8)) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("Both UT_LATIN1 and UT_UTF8 specified"); } else { nchar = format(unit, buf, size, useNames, getDefinition, encoding, 0); if (nchar < 0) { ut_set_status(UT_CANT_FORMAT); ut_handle_error_message("Couldn't format unit"); } else { ut_set_status(UT_SUCCESS); } } return nchar; } udunits-2.2.0/check-commit0000755000175000017500000000151212260406756016640 0ustar amckinstryamckinstryexec >$HOME/check-commit.log 2>&1 echo pwd=`pwd` echo '$0'=\"$0\" echo '$-'=\"$-\" echo '$$'=\"$$\" ps -O pgid -p $$ for arg in "$@"; do echo arg=\"$arg\" done set -x -m topSrcDir=`dirname $0` if cd $topSrcDir; then ( # # Allow only one process to proceed. # while ! ln -s /dev/null check-commit.ln 2>/dev/null do sleep 10 done trap 'rm -f check-commit.ln' EXIT trap 'exit 1' HUP INT QUIT TERM if test -f check-commit.pid; then pid=`cat check-commit.pid` kill -- -$pid while kill -n 0 $pid do sleep 1 done fi echo $! >check-commit.pid trap 'rm -f check-commit.pid' EXIT # # Allow another process to proceed. # rm check-commit.ln sleep 300 make remote-checks 2>&1 | ssh zero mailx \ -s '"UDUNITS-2: \"make remote-checks\" output"' \ $USER@unidata.ucar.edu ) & fi udunits-2.2.0/ltmain.sh0000755000175000017500000075636512260406756016221 0ustar amckinstryamckinstry# Generated from ltmain.m4sh. # libtool (GNU libtool) 2.2.10 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # 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. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.2.10 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . PROGRAM=libtool PACKAGE=libtool VERSION=2.2.10 TIMESTAMP="" package_revision=1.3175 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${EGREP="/bin/grep -E"} : ${FGREP="/bin/grep -F"} : ${GREP="/bin/grep"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SED="/bin/sed"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # Generated shell functions inserted here. # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=: for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname${mode+: }$mode: $*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_version # Echo version message to standard output and exit. func_version () { $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $SED -n '/^# Usage:/,/# Report bugs to/ { s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ p }' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { func_error "missing argument for $1." exit_cmd=exit } exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. # $mode is unset nonopt= execute_dlfiles= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 opt_dry_run=false opt_duplicate_deps=false opt_silent=false opt_debug=: # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # Parse options once, thoroughly. This comes as soon as possible in # the script to make things like `libtool --version' happen quickly. { # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Parse non-mode specific arguments: while test "$#" -gt 0; do opt="$1" shift case $opt in --config) func_config ;; --debug) preserve_args="$preserve_args $opt" func_echo "enabling shell trace mode" opt_debug='set -x' $opt_debug ;; -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break execute_dlfiles="$execute_dlfiles $1" shift ;; --dry-run | -n) opt_dry_run=: ;; --features) func_features ;; --finish) mode="finish" ;; --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break case $1 in # Valid mode arguments: clean) ;; compile) ;; execute) ;; finish) ;; install) ;; link) ;; relink) ;; uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac mode="$1" shift ;; --preserve-dup-deps) opt_duplicate_deps=: ;; --quiet|--silent) preserve_args="$preserve_args $opt" opt_silent=: opt_verbose=false ;; --no-quiet|--no-silent) preserve_args="$preserve_args $opt" opt_silent=false ;; --verbose| -v) preserve_args="$preserve_args $opt" opt_silent=false opt_verbose=: ;; --no-verbose) preserve_args="$preserve_args $opt" opt_verbose=false ;; --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break preserve_args="$preserve_args $opt $1" func_enable_tag "$1" # tagname is set here shift ;; # Separate optargs to long options: -dlopen=*|--mode=*|--tag=*) func_opt_split "$opt" set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} shift ;; -\?|-h) func_usage ;; --help) opt_help=: ;; --help-all) opt_help=': help-all' ;; --version) func_version ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) nonopt="$opt" break ;; esac done case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_duplicate_deps ;; esac # Having warned about all mis-specified options, bail out if # anything was wrong. $exit_cmd $EXIT_FAILURE } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } ## ----------- ## ## Main. ## ## ----------- ## $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi test -z "$mode" && func_fatal_error "error: you must specify a MODE." # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$mode' for more information." } # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_ltwrapper_scriptname_result="" if func_ltwrapper_executable_p "$1"; then func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" fi } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T <?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi removelist="$removelist $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist removelist="$removelist $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir command="$command -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then command="$command -o $obj" fi # Suppress compiler output if we already did a PIC compilation. command="$command$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $execute_dlfiles; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_quote_for_eval "$file" args="$args $func_quote_for_eval_result" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" exit $EXIT_SUCCESS } test "$mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" install_prog="$install_prog$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then files="$files $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" install_prog="$install_prog $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi install_shared_prog="$install_shared_prog $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" install_shared_prog="$install_shared_prog -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" dir="$dir$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_verbose "extracting global C symbols from \`$progfile'" $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" } done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; " case $host in *cygwin* | *mingw* | *cegcc* ) echo >> "$output_objdir/$my_dlsyms" "\ /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */" lt_dlsym_const= ;; *osf5*) echo >> "$output_objdir/$my_dlsyms" "\ /* This system does not cope well with relocations in const data */" lt_dlsym_const= ;; *) lt_dlsym_const=const ;; esac echo >> "$output_objdir/$my_dlsyms" "\ extern $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) symtab_cflags="$symtab_cflags $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then win32_nmres=`eval $NM -f posix -A $1 | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # 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 relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_to_host_path arg # # Convert paths to host format when used with build tools. # Intended for use with "native" mingw (where libtool itself # is running under the msys shell), or in the following cross- # build environments: # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # where wine is equipped with the `winepath' executable. # In the native mingw case, the (msys) shell automatically # converts paths for any non-msys applications it launches, # but that facility isn't available from inside the cwrapper. # Similar accommodations are necessary for $host mingw and # $build cygwin. Calling this function does no harm for other # $host/$build combinations not listed above. # # ARG is the path (on $build) that should be converted to # the proper representation for $host. The result is stored # in $func_to_host_path_result. func_to_host_path () { func_to_host_path_result="$1" if test -n "$1"; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' case $build in *mingw* ) # actually, msys # awkward: cmd appends spaces to result func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_path_result=`cygpath -w "$1" | $SED -e "$lt_sed_naive_backslashify"` ;; * ) # Unfortunately, winepath does not exit with a non-zero # error code, so we are forced to check the contents of # stdout. On the other hand, if the command is not # found, the shell will set an exit code of 127 and print # *an error message* to stdout. So we must check for both # error code of zero AND non-empty stdout, which explains # the odd construction: func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then func_to_host_path_result=`$ECHO "$func_to_host_path_tmp1" | $SED -e "$lt_sed_naive_backslashify"` else # Allow warning below. func_to_host_path_result= fi ;; esac if test -z "$func_to_host_path_result" ; then func_error "Could not determine host path corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_path_result="$1" fi ;; esac fi } # end: func_to_host_path # func_to_host_pathlist arg # # Convert pathlists to host format when used with build tools. # See func_to_host_path(), above. This function supports the # following $build/$host combinations (but does no harm for # combinations not listed here): # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # # Path separators are also converted from $build format to # $host format. If ARG begins or ends with a path separator # character, it is preserved (but converted to $host format) # on output. # # ARG is a pathlist (on $build) that should be converted to # the proper representation on $host. The result is stored # in $func_to_host_pathlist_result. func_to_host_pathlist () { func_to_host_pathlist_result="$1" if test -n "$1"; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_pathlist_tmp1=$func_stripname_result case $build in *mingw* ) # Actually, msys. # Awkward: cmd appends spaces to result. func_to_host_pathlist_result=` ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" | $SED -e "$lt_sed_naive_backslashify"` ;; * ) # unfortunately, winepath doesn't convert pathlists func_to_host_pathlist_result="" func_to_host_pathlist_oldIFS=$IFS IFS=: for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do IFS=$func_to_host_pathlist_oldIFS if test -n "$func_to_host_pathlist_f" ; then func_to_host_path "$func_to_host_pathlist_f" if test -n "$func_to_host_path_result" ; then if test -z "$func_to_host_pathlist_result" ; then func_to_host_pathlist_result="$func_to_host_path_result" else func_append func_to_host_pathlist_result ";$func_to_host_path_result" fi fi fi done IFS=$func_to_host_pathlist_oldIFS ;; esac if test -z "$func_to_host_pathlist_result"; then func_error "Could not determine the host path(s) corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This may break if $1 contains DOS-style drive # specifications. The fix is not to complicate the expression # below, but for the user to provide a working wine installation # with winepath so that path translation in the cross-to-mingw # case works properly. lt_replace_pathsep_nix_to_dos="s|:|;|g" func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ $SED -e "$lt_replace_pathsep_nix_to_dos"` fi # Now, add the leading and trailing path separators back case "$1" in :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" ;; esac case "$1" in *: ) func_append func_to_host_pathlist_result ";" ;; esac ;; esac fi } # end: func_to_host_pathlist # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -e 's/\([\\"]\)/\\\1/g' \ -e 's/^/ fputs ("/' -e 's/$/\\n", f);/' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) deplibs="$deplibs $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # moreargs="$moreargs $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) weak_libs="$weak_libs $arg" prev= continue ;; xcclinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname '-L' '' "$arg" dir=$func_stripname_result if test -z "$dir"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "*) ;; *) deplibs="$deplibs -L$dir" lib_search_path="$lib_search_path $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) dllsearchpath="$dllsearchpath:$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework deplibs="$deplibs System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi deplibs="$deplibs $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $func_quote_for_eval_result" compiler_flags="$compiler_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $wl$func_quote_for_eval_result" compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" linker_flags="$linker_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" compiler_flags="$compiler_flags $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. objs="$objs $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. deplibs="$deplibs $arg" old_deplibs="$old_deplibs $arg" continue ;; *.la) # A libtool-controlled library. if test "$prev" = dlfiles; then # This library was specified with -dlopen. dlfiles="$dlfiles $arg" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. dlprefiles="$dlprefiles $arg" prev= else deplibs="$deplibs $arg" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_duplicate_deps ; then case "$libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi libs="$libs $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; esac pre_post_deps="$pre_post_deps $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= case $lib in *.la) func_source "$lib" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) deplibs="$deplibs $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else compiler_flags="$compiler_flags $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" dir=$func_stripname_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) lib="$deplib" ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. newdlprefiles="$newdlprefiles $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else newdlfiles="$newdlfiles $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && dlfiles="$dlfiles $dlopen" test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. convenience="$convenience $ladir/$objdir/$old_library" old_convenience="$old_convenience $ladir/$objdir/$old_library" elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done continue fi # $pass = conv # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. dlprefiles="$dlprefiles $lib $dependency_libs" else newdlfiles="$newdlfiles $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$libdir" absdir="$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then newdlprefiles="$newdlprefiles $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then newdlprefiles="$newdlprefiles $dir/$dlname" else newdlprefiles="$newdlprefiles $dir/$linklib" fi fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then newlib_search_path="$newlib_search_path $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) temp_rpath="$temp_rpath$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded notinst_deplibs="$notinst_deplibs $lib" need_relink=no ;; *) if test "$installed" = no; then notinst_deplibs="$notinst_deplibs $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; *) temp_deplibs="$temp_deplibs $libdir";; esac done dependency_libs="$temp_deplibs" fi newlib_search_path="$newlib_search_path $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_dirname "$deplib" "" "." dir="$func_dirname_result" # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) tmp_libs="$tmp_libs $deplib" ;; esac ;; *) tmp_libs="$tmp_libs $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then tmp_libs="$tmp_libs $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" objs="$objs$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" libobjs="$libobjs $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" libobjs="$libobjs $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi removelist="$removelist $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) dlfiles="$dlfiles $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) dlprefiles="$dlprefiles $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework deplibs="$deplibs System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then deplibs="$deplibs -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) newdeplibs="$newdeplibs $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" dep_rpath="$dep_rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" if test -n "$hardcode_libdir_flag_spec_ld"; then eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" else eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do linknames="$linknames $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" delfiles="$delfiles $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" func_len " $cmd" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then func_show_eval "$cmd" 'exit $?' skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) tmp_deplibs="$tmp_deplibs $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $convenience libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" fi # Make a backup of the uninstalled library when relinking if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do $ECHO "$obj" >> $output done echo ')' >> $output delfiles="$delfiles $output" elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do $ECHO "$obj" >> $output done delfiles="$delfiles $output" output=$firstobj\"$file_list_spec$output\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi delfiles="$delfiles $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" generated="$generated $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) compile_command="$compile_command ${wl}-bind_at_load" finalize_command="$finalize_command ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done compile_deplibs="$new_libs" compile_command="$compile_command $compile_deplibs" finalize_command="$finalize_command $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) dllsearchpath="$dllsearchpath:$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then oldobjs="$oldobjs $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $addlibs oldobjs="$oldobjs $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles oldobjs="$oldobjs $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" oldobjs="$oldobjs $gentop/$newobj" ;; *) oldobjs="$oldobjs $obj" ;; esac done fi eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" newdependency_libs="$newdependency_libs $libdir/$name" ;; *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlfiles="$newdlfiles $libdir/$name" ;; *) newdlfiles="$newdlfiles $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlprefiles="$newdlprefiles $libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlfiles="$newdlfiles $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlprefiles="$newdlprefiles $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$mode" = link || test "$mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) RM="$RM $arg"; rmforce=yes ;; -*) RM="$RM $arg" ;; *) files="$files $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= origobjdir="$objdir" for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then objdir="$origobjdir" else objdir="$dir/$origobjdir" fi func_basename "$file" name="$func_basename_result" test "$mode" = uninstall && objdir="$dir" # Remember objdir for removal later, being careful to avoid duplicates if test "$mode" = clean; then case " $rmdirs " in *" $objdir "*) ;; *) rmdirs="$rmdirs $objdir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $objdir/$n" done test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" case "$mode" in clean) case " $library_names " in # " " in the beginning catches empty $dlname *" $dlname "*) ;; *) rmfiles="$rmfiles $objdir/$dlname" ;; esac test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then rmfiles="$rmfiles $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then rmfiles="$rmfiles $dir/$non_pic_object" fi fi ;; *) if test "$mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe rmfiles="$rmfiles $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result rmfiles="$rmfiles $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then rmfiles="$rmfiles $objdir/lt-$name" fi if test "X$noexename" != "X$name" ; then rmfiles="$rmfiles $objdir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done objdir="$origobjdir" # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$mode" = uninstall || test "$mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 udunits-2.2.0/config.h.in0000644000175000017500000000541412260406756016377 0ustar amckinstryamckinstry/* config.h.in. Generated from configure.ac by autoheader. */ /* The default absolute pathname of the installed units database */ #undef DEFAULT_UDUNITS2_XML_PATH /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_FLOAT_H /* Define to 1 if you have the `floor' function. */ #undef HAVE_FLOOR /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* 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 `modf' function. */ #undef HAVE_MODF /* Define to 1 if you have the `pow' function. */ #undef HAVE_POW /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* 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 you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* 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 header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O /* 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 /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `unsigned int' if does not define. */ #undef size_t udunits-2.2.0/BACKLOG0000644000175000017500000000040012260406756015327 0ustar amckinstryamckinstrySupport for unreferenced logarithmic units Fortran 2003 API Investigate name collisions in the scanner and parser [UDUNITS !IEB-391154]. Create default names for common units for ontologies. Add ability to get version identifier to API and udunits(2). udunits-2.2.0/missing0000755000175000017500000002623312260406756015755 0ustar amckinstryamckinstry#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2009-04-28.21; # UTC # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, # 2008, 2009 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program 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, or (at your option) # any later version. # 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. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and \`g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; tar*) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; tar*) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case $firstarg in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case $firstarg in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: udunits-2.2.0/build.gradle0000644000175000017500000001053212260406756016630 0ustar amckinstryamckinstryapply plugin: 'cpp' //apply plugin: 'cpp-lib' //apply plugin: 'cpp-exe' version = '2.1.25' group = 'edu.ucar.unidata' description = "Units of Physical Quantities" /* * Apparently, there is no Maven repository for the Expat development package; * consequently, the dependency on that package is explicitly managed. */ task checkExpat(type: Exec) { ignoreExitValue = true standardOutput = new ByteArrayOutputStream() commandLine 'yum', 'info', 'expat-devel' } task ensureExpat(type: Exec, dependsOn: 'checkExpat') { onlyIf { checkExpat.execResult.getExitValue() != 0 } commandLine 'yum', 'install', 'expat-devel' } /* * Build the HTML documentation from texinfo(5) files. */ task ensureLibHtml(type: Exec) { onlyIf { !new File("src/lib/udunits2lib.html").exists() } workingDir "src/lib" commandLine 'makeinfo', '--html', '--no-split', '-o', 'udunits2lib.html', 'udunits2lib.texi' } task ensureProgHtml(type: Exec) { onlyIf { !new File("src/prog/udunits2prog.html").exists() } workingDir "src/prog" commandLine 'makeinfo', '--html', '--no-split', '-o', 'udunits2prog.html', 'udunits2prog.texi' } task ensureHtml(type: Exec, dependsOn: ['ensureLibHtml', 'ensureProgHtml']) { onlyIf { !new File("src/udunits2.html").exists() } workingDir "src" commandLine 'makeinfo', '--html', '--no-split', '-o', 'udunits2.html', 'udunits2.texi' } /* * Build the parser of unit specifications from yacc(1) and lex(1) input. */ task parser(type: Exec) { onlyIf { !new File("src/lib/parser.c").exists() } workingDir "src/lib" commandLine 'bison', '-t', '-p', 'ut', '-o', 'parser.c', 'parser.y' } task scanner(type: Exec) { onlyIf { !new File("src/lib/scanner.c").exists() } workingDir "src/lib" commandLine 'flex', '-d', '-P', 'ut', '-o', 'scanner.c', 'scanner.l' } sources { lib { c { source { srcDirs = ["src/lib"] include "*.c" exclude "scanner.c", "test*.c" } exportedHeaders { srcDirs = ["src/lib"] include "udunits.h" include "udunits2.h" include "converter.h" } } } exe { c { source { srcDirs = ["src/prog"] include "*.c" } } } } libCExtractHeaders.dependsOn parser libCExtractHeaders.dependsOn scanner libraries { main { source sources.lib binaries.all { compilerArgs "-DDEFAULT_UDUNITS2_XML_PATH=\"${projectDir}" + '/share/udunits/udunits2.xml"' } } } /* * The following dependency requires use of "afterEvaluate" because the task * "mainSharedLibrary" doesn't exist until after this entire file is parsed * and then the "sources" section is evaluated. */ afterEvaluate { mainSharedLibrary.dependsOn ensureExpat } executables { main { source sources.exe binaries.all { lib libraries.main.shared compilerArgs "-I" + projectDir.toString() + "/src/lib" linkerArgs "-lexpat" } } } def libTask = "${name}SharedLibrary" task "installLib"(dependsOn: "mainSharedLibrary", type: Copy) { from "${buildDir}/binaries/$libTask" into "lib" } task installHeaders(type: Copy) { from "${rootDir}/src/lib" include "udunits.h" include "udunits2.h" include "converter.h" into "include" } task installDatabase(type: Copy) { from "${rootDir}/src/lib" include "*.xml" into "share/udunits" } task installLibHtml(type: Copy, dependsOn: 'ensureLibHtml') { from "${rootDir}/src/lib" include "*.html" into "share/doc/udunits" } task installProgHtml(type: Copy, dependsOn: 'ensureProgHtml') { from "${rootDir}/src/prog" include "*.html" into "share/doc/udunits" } task installHtml(type: Copy, dependsOn: ['ensureHtml', "installLibHtml", "installProgHtml"]) { from "${rootDir}/src" include "*.html" into "share/doc/udunits" } task "installProg"(dependsOn: "installMainExecutable", type: Copy) { from "${buildDir}/install/${name}Executable" into "bin" } task install(dependsOn: ["installLib", "installHeaders", "installDatabase", "installProg", "installHtml"]) { } apply plugin: 'maven' /* dependencies { archives } */ uploadArchives { repositories { mavenDeployer { repository(url: uri("${buildDir}/repo")) } } } task wrapper(type: Wrapper) { gradleVersion = "1.9-20130910220037+0000" //gradleVersion = "1.9-20130903235553+0000" //gradleVersion = "1.9-20130829220030+0000" //gradleVersion = "1.9-20130825220029+0000" }udunits-2.2.0/config.guess0000755000175000017500000013226412260406756016700 0ustar amckinstryamckinstry#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # Free Software Foundation, Inc. timestamp='2009-04-27' # This file 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. # # 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. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:[3456]*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T | authenticamd | genuineintel) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^LIBC/{ s: ::g p }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: