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.
Coding:
#include <udunits2.h>
const char*
|
ut_get_path_xml(const char* path, ut_status* status
);
|
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 ... -Llibdir -ludunits2 -lexpat ... -lm
Where libdir is the installation-directory for object code libraries (e.g.,
/usr/local/lib
).
The existence 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:
ut_parse()
.While the above might seem to be trivial activities, their general availability at the time might have helped prevent the Mars Climate Orbiter fiasco.
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 the NIST International System of Units (SI).)
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:
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):
ut_read_xml(NULL)
.ut_read_xml()
with the pathname of the customized database to obtain a customized unit-system.ut_new_base_unit()
and
ut_new_dimensionless_unit()
.ut_new_system()
, in which case you will definitely have to start with
ut_new_base_unit()
and
ut_new_dimensionless_unit()
.You should pass every unit-system pointer to ut_free_system()
when you
no longer need the corresponding unit-system.
const char*
ut_get_path_xml (const char* path,
ut_status* status)
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
NULL
and was returned.UT_OPEN_ENV
NULL
, the environment variable UDUNITS2_XML_PATH
is set, and
its value was returned.UT_OPEN_DEFAULT
NULL
, the environment variable UDUNITS2_XML_PATH
is unset,
and the pathname of the default unit-database was returned.ut_system*
ut_read_xml (const char* path)
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
NULL
but the file couldn’t be opened. See errno
for
the reason.UT_OPEN_ENV
NULL
and environment variable UDUNITS2_XML_PATH
is set but
the file couldn’t be opened. See errno
for the reason.UT_OPEN_DEFAULT
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
errno
.UT_PARSE
ut_system*
ut_new_system (void)
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
errno
.NOTE: This section covers low-level access to the individual units of a unit-system. General parsing of arbitrary unit specifications is covered 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()
.
ut_unit*
ut_get_unit_by_name
(const ut_system* system, const char* name)
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
UT_BAD_ARG
NULL
.ut_free()
when it is no longer needed.ut_unit*
ut_get_unit_by_symbol (const ut_system*
system, const char* symbol)
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
UT_BAD_ARG
NULL
.ut_free()
when it is no longer needed.ut_unit*
ut_get_dimensionless_unit_one (const ut_system* system)
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
.
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.
ut_unit*
ut_new_base_unit (ut_system* system)
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
NULL
.UT_OS
errno
.ut_read_xml()
, then you should not normally need to call
this function.ut_unit*
ut_new_dimensionless_unit (ut_system*
system)
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
NULL
.UT_OS
errno
.ut_read_xml()
, then you should not normally need to call
this function.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.
ut_status
ut_add_name_prefix
(ut_system* system, const char* name, double value)
UT_SUCCESS
UT_BAD_ARG
NULL
, or value is 0
.UT_EXISTS
UT_OS
errno
.ut_status
ut_add_symbol_prefix
(ut_system* system, const char* symbol, double value)
UT_SUCCESS
UT_BAD_ARG
NULL
, or value is 0
.UT_EXISTS
UT_OS
errno
.void
ut_free_system (ut_system*
system)
system
after this function returns results in undefined behavior.ut_status
ut_set_second
(const ut_unit* second)
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
UT_EXISTS
UT_BAD_ARG
NULL
.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.
int
ut_are_convertible (const ut_unit* unit1,
uconst t_unit* unit2)
0
is returned and ut_get_status() will return one of the following:
UT_BAD_ARG
NULL
.UT_NOT_SAME_SYSTEM
UT_SUCCESS
cv_converter*
ut_get_converter (ut_unit* const from,
ut_unit* const 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
NULL
.UT_NOT_SAME_SYSTEM
UT_MEANINGLESS
UT_OS
errno
.float
cv_convert_float (const cv_converter*
converter, const float value)
double
cv_convert_double (const cv_converter*
converter, const 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* in, size_t count, double*
out)
void
cv_free (cv_converter* conv)
;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. */ }
ut_unit*
ut_parse (const ut_system* system, const
char* string, ut_encoding encoding)
ut_trim()
). If an error occurs, then
this function returns NULL
and ut_get_status()
will
return one of the following:
UT_BAD_ARG
NULL
.UT_SYNTAX
UT_UNKNOWN
UT_OS
errno
for the reason.ut_free()
when it is no longer needed.size_t
ut_trim (char* string, ut_encoding
encoding)
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 the NIST International System of Units (SI). 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”).
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 (udunits2prog)udunits2
utility to experiment with
string unit specifications.
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>)? TIMESTAMP: <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]*)?
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 */ }
int
ut_format (const ut_unit* unit, char*
buf, size_t size, unsigned opts)
UT_NAMES
UT_DEFINITION
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.-1
and ut_get_status() will
return one of the following:
UT_BAD_ARG
NULL
, or opts contains the bit patterns of
both UT_LATIN1
and UT_UTF8
.UT_CANT_FORMAT
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).You can use unit operations to construct new units, get information about units, or compare units.
void
ut_free (ut_unit* unit)
ut_unit*
ut_scale (double factor, const ut_unit*
unit)
const ut_unit* meter = ... const ut_unit* kilometer = ut_scale(1000, meter);
ut_free()
when you no longer need the unit.ut_unit*
ut_offset (const ut_unit* unit, double
offset)
const ut_unit* kelvin = ... const ut_unit* celsius = ut_offset(kelvin, 273.15);
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
NULL
.UT_OS
errno
for the reason.ut_unit*
ut_offset_by_time (const ut_unit* const
unit, const double origin)
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));
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
NULL
.UT_OS
errno
for the reason.UT_MEANINGLESS
UT_NO_SECOND
ut_set_second()
.ut_unit*
ut_invert (const ut_unit*
unit)
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
NULL
.UT_OS
errno
for the reason.ut_unit*
ut_raise (const ut_unit* unit, int
power)
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
NULL
.UT_OS
errno
for the reason.ut_unit*
ut_root (const ut_unit* unit, int
root)
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
NULL
.UT_MEANINGLESS
UT_OS
errno
for the reason.ut_unit*
ut_log (double base, const ut_unit*
reference)
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 */ }
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
NULL
.UT_OS
errno
for the reason.UT_BAD_ARG
const char*
ut_get_name (const ut_unit* unit,
ut_encoding encoding)
NULL
, then
ut_get_status()
will return one of the following:
UT_BAD_ARG
NULL
.UT_SUCCESS
const char*
ut_get_symbol (const ut_unit* unit,
ut_encoding encoding)
NULL
, then
ut_get_status()
will return one of the following:
UT_BAD_ARG
NULL
.UT_SUCCESS
ut_system*
ut_get_system
(const ut_unit* unit)
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
.int
ut_is_dimensionless
(const ut_unit* unit)
0
is returned and
ut_get_status() will return one of the following:
UT_BAD_ARG
NULL
.UT_SUCCESS
ut_unit*
ut_clone
(const ut_unit* unit)
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
NULL
.UT_OS
errno
.ut_read_xml()
, then you should not normally need to call
this function.ut_status
ut_accept_visitor
(const ut_unit* unit, const ut_visitor* visitor, void*
arg)
UT_BAD_ARG
NULL
.UT_VISIT_ERROR
UT_SUCCESS
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);
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);
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);
UT_SUCCESS
on and
only on success.ut_status (*visit_timestamp)(const ut_unit* unit,
const ut_unit* timeUnit, double origin, void* arg);
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);
UT_SUCCESS
on and only on success.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.
ut_unit*
ut_multiply (const ut_unit* unit1,
const ut_unit* unit2)
NULL
and ut_get_status() will return one of the following:
UT_BAD_ARG
NULL
.UT_NOT_SAME_SYSTEM
UT_OS
ut_unit*
ut_divide (const ut_unit* numer,
const ut_unit* denom)
NULL
and ut_get_status() will return one of the following:
UT_BAD_ARG
NULL
.UT_NOT_SAME_SYSTEM
UT_OS
errno
for the reason.int
ut_compare (const ut_unit* unit1, const ut_unit*
unit2)
NULL
.int
ut_same_system (const ut_unit* unit1,
const ut_unit* unit2)
0
is returned and
ut_get_status() will return one of the following:
UT_BAD_ARG
NULL
.UT_SUCCESS
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 two kinds of identifiers: names and symbols.
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.
ut_status
ut_map_name_to_unit
(const char* name, const ut_encoding encoding, const ut_unit*
unit)
UT_SUCCESS
UT_BAD_ARG
NULL
.UT_OS
errno
.UT_EXISTS
ut_status
ut_unmap_name_to_unit
(ut_system* system, const char* name, const ut_encoding
encoding)
UT_SUCCESS
UT_BAD_ARG
NULL
.ut_status
ut_map_unit_to_name
(const ut_unit* unit, const char* name,
ut_encoding encoding)
UT_SUCCESS
UT_BAD_ARG
NULL
, or name is not in the character-set
encoding.UT_OS
errno
.UT_EXISTS
ut_status
ut_unmap_unit_to_name
(const ut_unit* unit, ut_encoding encoding)
UT_SUCCESS
UT_BAD_ARG
NULL
.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.
ut_status
ut_map_symbol_to_unit
(const char* symbol, const ut_encoding encoding, const ut_unit*
unit)
UT_SUCCESS
UT_BAD_ARG
NULL
.UT_OS
errno
.UT_EXISTS
ut_status
ut_unmap_symbol_to_unit
(ut_system* system, const char* symbol, const ut_encoding
encoding)
UT_SUCCESS
UT_BAD_ARG
NULL
.ut_status
ut_map_unit_to_symbol
(const ut_unit* unit, const char* symbol, ut_encoding
encoding)
UT_SUCCESS
UT_BAD_ARG
NULL
.UT_BAD_ARG
UT_OS
errno
.UT_EXISTS
ut_status
ut_unmap_unit_to_symbol
(const ut_unit* unit, ut_encoding encoding)
UT_SUCCESS
UT_BAD_ARG
NULL
.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.
double
ut_encode_time (int year, int
month, int day, int hour, int minute, double
second)
ut_encode_date(year,month,day) +
ut_encode_clock(hour,minute,second)
double
ut_encode_date (int year,
int month, int day)
double
ut_encode_clock (int hour,
int minute, double second)
abs(hour)
must be less than 24;
abs(minute)
must be less than 60; and fabs(second)
must be less than or equal to 62.
You probably won’t use this function.void
ut_decode_time (double time, int*
year, int* month, int* day, int* hour, int* minute,
double* second, double* resolution)
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:
UDUNITS-2 functions set their status by calling ut_set_status()
. You
can use the function ut_get_status()
to retrieve that status.
ut_status
ut_get_status
(void)
ut_set_status()
void
ut_set_status (ut_status
status)
UT_SUCCESS
UT_BAD_ARG
NULL
).UT_EXISTS
UT_NO_UNIT
UT_OS
errno
for the reason.UT_NOT_SAME_SYSTEM
UT_MEANINGLESS
UT_NO_SECOND
UT_VISIT_ERROR
UT_CANT_FORMAT
UT_SYNTAX
UT_UNKNOWN
UT_OPEN_ARG
UT_OPEN_ENV
UT_OPEN_DEFAULT
UT_PARSE
int
ut_handle_error_message (const char* fmt,
...)
printf()
. On success, this function returns the number of bytes in the error-message; otherwise,
this function returns -1
.ut_set_error_message_handler()
to
change how error-messages are handled.ut_error_message_handler
ut_set_error_message_handler (ut_error_message_handler
handler)
ut_write_to_stderr()
.int
ut_write_to_stderr (const char* fmt, va_list
args)
printf()
. On success, this function returns the number of
bytes in the error-message; otherwise, this function returns -1
.int
ut_ignore (const char* fmt, va_list
args)
ut_set_error_message_handler()
when you don’t
want the unit module to print any error-messages.typedef int (*ut_error_message_handler)(const char* fmt, va_list args);
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.
The data types ut_visitor
,
ut_status
, and
ut_error_message_handler
are documented elsewhere.
UT_ASCII
UT_ISO_8859_1
UT_LATIN1
UT_ISO_8859_1
.UT_UTF8