1 /*
2  * Copyright 2020 University Corporation for Atmospheric Research
3  *
4  * This file is part of the UDUNITS-2 package.  See the file COPYRIGHT
5  * in the top-level source-directory of the package for copying and
6  * redistribution conditions.
7  */
8 #ifndef UT_UNITS2_H_INCLUDED
9 #define UT_UNITS2_H_INCLUDED
10 
11 #include <stdarg.h>
12 #include <stddef.h>
13 
14 #ifdef _MSC_VER
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <io.h>
19 
20 #define _USE_MATH_DEFINES
21 
22 /* Define a bunch of variables to use the ISO C++ conformant name instead
23    of the POSIX name. This quiets a lot of the warnings thrown by MSVC. */
24 #define read _read
25 #define open _open
26 #define close _close
27 #define strdup _strdup
28 #define strcasecmp stricmp
29 #define stricmp _stricmp
30 #define isatty _isatty
31 
32 //We must accommodate the lack of snprintf in versions of MSVC less than 1900.
33 //udunits_snprintf is defined in udunits_snprintf.c, in lib/.
34 #define snprintf udunits_snprintf
35 
36 int udunits_snprintf(
37    char* str,
38      size_t size,
39      const char* format,
40      ...);
41 
42 int udunits_vsnprintf(
43 char* str,
44   size_t size,
45   const char* format,
46   va_list ap);
47 
48 #endif
49 
50 /* If we are working in Visual Studio and have a
51    shared library, we will need to do some slight-of-hand
52    in order to make it generate a proper export library.
53 */
54 
55 #if defined(DLL_UDUNITS2) /* define when library is a DLL */
56 #   if defined(DLL_EXPORT) /* defined when building the library */
57 #     define MSC_EXTRA __declspec(dllexport)
58 #   else
59 #     define MSC_EXTRA __declspec(dllimport)
60 #   endif
61 #else
62 # define MSC_EXTRA
63 #endif /* defined(DLL_UDUNITS2) */
64 
65 /*
66  * Results in
67  * udunits2.c.obj : error LNK2019: unresolved external symbol cv_free referenced in function handleRequest
68  * udunits2.c.obj : error LNK2019: unresolved external symbol cv_convert_double referenced in function handleRequest
69  * udunits2.c.obj : error LNK2019: unresolved external symbol cv_get_expression referenced in function handleRequest
70  */
71 #ifndef EXTERNL
72 #   define EXTERNL MSC_EXTRA extern
73 #endif
74 
75 /*
76  * Results in "NMAKE : fatal error U1073: don't know how to make 'lib\udunits2.lib'"
77 #undef EXTERNL
78 #define EXTERNL extern
79  */
80 
81 #include "converter.h"
82 
83 typedef struct ut_system	ut_system;
84 typedef union ut_unit		ut_unit;
85 
86 enum utStatus {
87     UT_SUCCESS = 0,	/* Success */
88     UT_BAD_ARG,	        /* An argument violates the function's contract */
89     UT_EXISTS,		/* Unit, prefix, or identifier already exists */
90     UT_NO_UNIT,		/* No such unit exists */
91     UT_OS,		/* Operating-system error.  See "errno". */
92     UT_NOT_SAME_SYSTEM,	/* The units belong to different unit-systems */
93     UT_MEANINGLESS,	/* The operation on the unit(s) is meaningless */
94     UT_NO_SECOND,	/* The unit-system doesn't have a unit named "second" */
95     UT_VISIT_ERROR,	/* An error occurred while visiting a unit */
96     UT_CANT_FORMAT,	/* A unit can't be formatted in the desired manner */
97     UT_SYNTAX,		/* string unit representation contains syntax error */
98     UT_UNKNOWN,		/* string unit representation contains unknown word */
99     UT_OPEN_ARG,	/* Can't open argument-specified unit database */
100     UT_OPEN_ENV,	/* Can't open environment-specified unit database */
101     UT_OPEN_DEFAULT,	/* Can't open installed, default, unit database */
102     UT_PARSE		/* Error parsing unit specification */
103 };
104 typedef enum utStatus          ut_status;
105 
106 enum utEncoding {
107     UT_ASCII = 0,
108     UT_ISO_8859_1 = 1,
109     UT_LATIN1 = UT_ISO_8859_1,
110     UT_UTF8 = 2
111 };
112 typedef enum utEncoding        ut_encoding;
113 
114 #define UT_NAMES	4
115 #define UT_DEFINITION	8
116 
117 
118 /*
119  * Data-structure for a visitor to a unit:
120  */
121 typedef struct ut_visitor {
122     /*
123      * Visits a basic-unit.  A basic-unit is a base unit like "meter" or a non-
124      * dimensional but named unit like "radian".
125      *
126      * Arguments:
127      *	unit		Pointer to the basic-unit.
128      *	arg		Client pointer passed to ut_accept_visitor().
129      * Returns:
130      *	UT_SUCCESS	Success.
131      *	else		Failure.
132      */
133     ut_status	(*visit_basic)(const ut_unit* unit, void* arg);
134 
135     /*
136      * Visits a product-unit.  A product-unit is a product of zero or more
137      * basic-units, each raised to a non-zero power.
138      *
139      * Arguments:
140      *	unit		Pointer to the product-unit.
141      *	count		The number of basic-units in the product.  May be zero.
142      *	basicUnits	Pointer to an array of basic-units in the product.
143      *	powers		Pointer to an array of powers to which the respective
144      *			basic-units are raised.
145      *	arg		Client pointer passed to ut_accept_visitor().
146      * Returns:
147      *	UT_SUCCESS	Success.
148      *	else		Failure.
149      */
150     ut_status	(*visit_product)(const ut_unit* unit, int count,
151 	const ut_unit* const* basicUnits, const int* powers, void* arg);
152 
153     /*
154      * Visits a Galilean-unit.  A Galilean-unit has an underlying unit and a
155      * non-unity scale factor or a non-zero offset.
156      *
157      * Arguments:
158      *	unit		Pointer to the Galilean-unit.
159      *	scale		The scale factor (e.g., 1000 for a kilometer when the
160      *			underlying unit is a meter).
161      *	underlyingUnit	Pointer to the underlying unit.
162      *	offset		Pointer to the underlying unit.
163      *	arg		Client pointer passed to ut_accept_visitor().
164      * Returns:
165      *	UT_SUCCESS	Success.
166      *	else		Failure.
167      */
168     ut_status	(*visit_galilean)(const ut_unit* unit, double scale,
169 	const ut_unit* underlyingUnit, double offset, void* arg);
170 
171     /*
172      * Visits a timestamp-unit.  A timestamp-unit has an underlying unit of time
173      * and an encoded time-origin.
174      *
175      * Arguments:
176      *	unit		Pointer to the timestamp-unit.
177      *	timeUnit	Pointer to the underlying unit of time.
178      *  origin          Encoded origin of the timestamp-unit.
179      *	arg		Client pointer passed to ut_accept_visitor().
180      * Returns:
181      *	UT_SUCCESS	Success.
182      *	else		Failure.
183      */
184     ut_status	(*visit_timestamp)(const ut_unit* unit,
185 	const ut_unit* timeUnit, double origin, void* arg);
186 
187     /*
188      * Visits a logarithmic-unit.  A logarithmic-unit has a logarithmic base and
189      * a unit that specifies the reference level.
190      *
191      * Arguments:
192      *	unit		Pointer to the logarithmic-unit.
193      *  base            The logarithmic base (e.g., 2, M_E, 10).
194      *	reference	Pointer to the unit that specifies the reference level.
195      *	arg		Client pointer passed to ut_accept_visitor().
196      * Returns:
197      *	UT_SUCCESS	Success.
198      *	else		Failure.
199      */
200     ut_status	(*visit_logarithmic)(const ut_unit* unit, double base,
201 	const ut_unit* reference, void* arg);
202 } ut_visitor;
203 
204 
205 typedef int (*ut_error_message_handler)(const char* fmt, va_list args);
206 
207 
208 #ifdef __cplusplus
209 EXTERNL "C" {
210 #endif
211 
212 
213 /******************************************************************************
214  * Unit System:
215  ******************************************************************************/
216 
217 
218 /**
219  * Returns the pathname of the XML database.
220  *
221  * @param path      The pathname of the XML file or NULL.
222  * @param status    Status. One of UT_OPEN_ARG, UT_OPEN_ENV, or UT_OPEN_DEFAULT.
223  * @return          If "path" is not NULL, then it is returned; otherwise, the
224  *                  pathname specified by the environment variable
225  *                  UDUNITS2_XML_PATH is returned if set; otherwise, the
226  *                  compile-time pathname of the installed, default, unit
227  *                  database is returned.
228  */
229 EXTERNL const char*
230 ut_get_path_xml(
231 	const char*	path,
232 	ut_status*  status);
233 
234 /*
235  * Returns the unit-system corresponding to an XML file.  This is the usual way
236  * that a client will obtain a unit-system.
237  *
238  * Arguments:
239  *	path	The pathname of the XML file or NULL.  If NULL, then the
240  *		pathname specified by the environment variable UDUNITS2_XML_PATH
241  *		is used if set; otherwise, the compile-time pathname of the
242  *		installed, default, unit database is used.
243  * Returns:
244  *	NULL	Failure.  "ut_get_status()" will be
245  *		    UT_OPEN_ARG		"path" is non-NULL but file couldn't be
246  *					opened.  See "errno" for reason.
247  *		    UT_OPEN_ENV		"path" is NULL and environment variable
248  *					UDUNITS2_XML_PATH is set but file
249  *					couldn't be opened.  See "errno" for
250  *					reason.
251  *		    UT_OPEN_DEFAULT	"path" is NULL, environment variable
252  *					UDUNITS2_XML_PATH is unset, and the
253  *					installed, default, unit database
254  *					couldn't be opened.  See "errno" for
255  *					reason.
256  *		    UT_PARSE		Couldn't parse unit database.
257  *		    UT_OS		Operating-system error.  See "errno".
258  *	else	Pointer to the unit-system defined by "path".
259  */
260 EXTERNL ut_system*
261 ut_read_xml(
262     const char*	path);
263 
264 
265 /*
266  * Returns a new unit-system.  On success, the unit-system will only contain
267  * the dimensionless unit one.  See "ut_get_dimensionless_unit_one()".
268  *
269  * Returns:
270  *	NULL	Failure.  "ut_get_status()" will be:
271  *		    UT_OS	Operating-system error.  See "errno".
272  *	else	Pointer to a new unit system.
273  */
274 EXTERNL ut_system*
275 ut_new_system(void);
276 
277 
278 /*
279  * Frees a unit-system.  All unit-to-identifier and identifier-to-unit mappings
280  * will be removed.
281  *
282  * Arguments:
283  *	system		Pointer to the unit-system to be freed.  Use of "system"
284  *			upon return results in undefined behavior.
285  */
286 EXTERNL void
287 ut_free_system(
288     ut_system*	system);
289 
290 
291 /*
292  * Returns the unit-system to which a unit belongs.
293  *
294  * Arguments:
295  *	unit	Pointer to the unit in question.
296  * Returns:
297  *	NULL	Failure.  "ut_get_status()" will be
298  *		    UT_BAD_ARG	"unit" is NULL.
299  *	else	Pointer to the unit-system to which "unit" belongs.
300  */
301 EXTERNL ut_system*
302 ut_get_system(
303     const ut_unit* const	unit);
304 
305 
306 /*
307  * Returns the dimensionless-unit one of a unit-system.
308  *
309  * Arguments:
310  *	system	Pointer to the unit-system for which the dimensionless-unit one
311  *		will be returned.
312  * Returns:
313  *	NULL	Failure.  "ut_get_status()" will be:
314  *		    UT_BAD_ARG	"system" is NULL.
315  *	else	Pointer to the dimensionless-unit one associated with "system".
316  *		While not necessary, the pointer may be passed to ut_free()
317  *		when the unit is no longer needed by the client.
318  */
319 EXTERNL ut_unit*
320 ut_get_dimensionless_unit_one(
321     const ut_system* const	system);
322 
323 
324 /*
325  * Returns the unit with a given name from a unit-system.  Name comparisons
326  * are case-insensitive.
327  *
328  * Arguments:
329  *	system	Pointer to the unit-system.
330  *	name	Pointer to the name of the unit to be returned.
331  * Returns:
332  *	NULL	Failure.  "ut_get_status()" will be
333  *		    UT_SUCCESS		"name" doesn't map to a unit of
334  *					"system".
335  *		    UT_BAD_ARG		"system" or "name" is NULL.
336  *	else	Pointer to the unit of the unit-system with the given name.
337  *		The pointer should be passed to ut_free() when the unit is
338  *		no longer needed.
339  */
340 EXTERNL ut_unit*
341 ut_get_unit_by_name(
342     const ut_system* const	system,
343     const char* const		name);
344 
345 
346 /*
347  * Returns the unit with a given symbol from a unit-system.  Symbol
348  * comparisons are case-sensitive.
349  *
350  * Arguments:
351  *	system		Pointer to the unit-system.
352  *	symbol		Pointer to the symbol associated with the unit to be
353  *			returned.
354  * Returns:
355  *	NULL	Failure.  "ut_get_status()" will be
356  *		    UT_SUCCESS		"symbol" doesn't map to a unit of
357  *					"system".
358  *		    UT_BAD_ARG		"system" or "symbol" is NULL.
359  *	else	Pointer to the unit in the unit-system with the given symbol.
360  *		The pointer should be passed to ut_free() when the unit is no
361  *		longer needed.
362  */
363 EXTERNL ut_unit*
364 ut_get_unit_by_symbol(
365     const ut_system* const	system,
366     const char* const		symbol);
367 
368 
369 /*
370  * Sets the "second" unit of a unit-system.  This function must be called before
371  * the first call to "ut_offset_by_time()". ut_read_xml() calls this function if the
372  * resulting unit-system contains a unit named "second".
373  *
374  * Arguments:
375  *	second		Pointer to the "second" unit.
376  * Returns:
377  *	UT_BAD_ARG	"second" is NULL.
378  *	UT_EXISTS	The second unit of the unit-system to which "second"
379  *			belongs is set to a different unit.
380  *	UT_SUCCESS	Success.
381  */
382 EXTERNL ut_status
383 ut_set_second(
384     const ut_unit* const	second);
385 
386 
387 /******************************************************************************
388  * Defining Unit Prefixes:
389  ******************************************************************************/
390 
391 
392 /*
393  * Adds a name-prefix to a unit-system.  A name-prefix is something like "mega"
394  * or "milli".  Comparisons between name-prefixes are case-insensitive.
395  *
396  * Arguments:
397  *	system		Pointer to the unit-system.
398  *	name		Pointer to the name-prefix (e.g., "mega").  May be freed
399  *			upon return.
400  *	value		The value of the prefix (e.g., 1e6).
401  * Returns:
402  *	UT_SUCCESS	Success.
403  *	UT_BAD_ARG	"system" or "name" is NULL, or "value" is 0.
404  *	UT_EXISTS	"name" already maps to a different value.
405  *	UT_OS		Operating-system failure.  See "errno".
406  */
407 EXTERNL ut_status
408 ut_add_name_prefix(
409     ut_system* const	system,
410     const char* const	name,
411     const double	value);
412 
413 
414 /*
415  * Adds a symbol-prefix to a unit-system.  A symbol-prefix is something like
416  * "M" or "y".  Comparisons between symbol-prefixes are case-sensitive.
417  *
418  * Arguments:
419  *	system		Pointer to the unit-system.
420  *	symbol		Pointer to the symbol-prefix (e.g., "M").  May be freed
421  *			upon return.
422  *	value		The value of the prefix (e.g., 1e6).
423  * Returns:
424  *	UT_SUCCESS	Success.
425  *	UT_BADSYSTEM	"system" or "symbol" is NULL.
426  *	UT_BAD_ARG	"value" is 0.
427  *	UT_EXISTS	"symbol" already maps to a different value.
428  *	UT_OS		Operating-system failure.  See "errno".
429  */
430 EXTERNL ut_status
431 ut_add_symbol_prefix(
432     ut_system* const	system,
433     const char* const	symbol,
434     const double	value);
435 
436 
437 /******************************************************************************
438  * Defining and Deleting Units:
439  ******************************************************************************/
440 
441 
442 /*
443  * Adds a base-unit to a unit-system.  Clients that use ut_read_xml() should not
444  * normally need to call this function.
445  *
446  * Arguments:
447  *	system	Pointer to the unit-system to which to add the new base-unit.
448  * Returns:
449  *	NULL	Failure.  "ut_get_status()" will be
450  *		    UT_BAD_ARG		"system" or "name" is NULL.
451  *		    UT_OS		Operating-system error.  See "errno".
452  *	else	Pointer to the new base-unit.  The pointer should be passed to
453  *		ut_free() when the unit is no longer needed by the client (the
454  *		unit will remain in the unit-system).
455  */
456 EXTERNL ut_unit*
457 ut_new_base_unit(
458     ut_system* const	system);
459 
460 
461 /*
462  * Adds a dimensionless-unit to a unit-system.  In the SI system of units, the
463  * derived-unit radian is a dimensionless-unit.  Clients that use ut_read_xml()
464  * should not normally need to call this function.
465  *
466  * Arguments:
467  *	system	Pointer to the unit-system to which to add the new
468  *		dimensionless-unit.
469  * Returns:
470  *	NULL	Failure.  "ut_get_status()" will be
471  *		    UT_BAD_ARG		"system" is NULL.
472  *		    UT_OS		Operating-system error.  See "errno".
473  *	else	Pointer to the new dimensionless-unit.  The pointer should be
474  *		passed to ut_free() when the unit is no longer needed by the
475  *		client (the unit will remain in the unit-system).
476  */
477 EXTERNL ut_unit*
478 ut_new_dimensionless_unit(
479     ut_system* const	system);
480 
481 
482 /*
483  * Returns a clone of a unit.
484  *
485  * Arguments:
486  *	unit	Pointer to the unit to be cloned.
487  * Returns:
488  *	NULL	Failure.  ut_get_status() will be
489  *		    UT_OS	Operating-system failure.  See "errno".
490  *		    UT_BAD_ARG	"unit" is NULL.
491  *	else	Pointer to the clone of "unit".  The pointer should be
492  *		passed to ut_free() when the unit is no longer needed by the
493  *		client.
494  */
495 EXTERNL ut_unit*
496 ut_clone(
497     const ut_unit* const unit);
498 
499 
500 /*
501  * Frees resources associated with a unit.  This function should be invoked on
502  * all units that are no longer needed by the client.  Use of the unit upon
503  * return from this function will result in undefined behavior.
504  *
505  * Arguments:
506  *	unit	Pointer to the unit to have its resources freed or NULL.
507  */
508 EXTERNL void
509 ut_free(
510     ut_unit* const	unit);
511 
512 
513 /******************************************************************************
514  * Mapping between Units and Names:
515  ******************************************************************************/
516 
517 
518 /*
519  * Returns the name in a given encoding to which a unit maps.
520  *
521  * Arguments:
522  *	unit		Pointer to the unit whose name should be returned.
523  *	encoding	The desired encoding of the name.
524  * Returns:
525  *	NULL		Failure.  "ut_get_status()" will be
526  *			    UT_BAD_ARG		"unit" is NULL.
527  *			    UT_SUCCESS		"unit" doesn't map to a name in
528  *						in the given encoding.
529  *	else		Pointer to the name in the given encoding to which
530  *			"unit" maps.
531  */
532 EXTERNL const char*
533 ut_get_name(
534     const ut_unit* const	unit,
535     const ut_encoding		encoding);
536 
537 
538 /*
539  * Adds a mapping from a name to a unit.
540  *
541  * Arguments:
542  *	name		Pointer to the name to be mapped to "unit".  May be
543  *			freed upon return.
544  *      encoding        The character encoding of "name".
545  *	unit		Pointer to the unit to be mapped-to by "name".  May be
546  *			freed upon return.
547  * Returns:
548  *	UT_BAD_ARG	"name" or "unit" is NULL.
549  *	UT_OS		Operating-system error.  See "errno".
550  *	UT_EXISTS	"name" already maps to a different unit.
551  *	UT_SUCCESS	Success.
552  */
553 EXTERNL ut_status
554 ut_map_name_to_unit(
555     const char* const		name,
556     const ut_encoding		encoding,
557     const ut_unit* const	unit);
558 
559 
560 /*
561  * Removes a mapping from a name to a unit.  After this function,
562  * ut_get_unit_by_name(system,name) will no longer return a unit.
563  *
564  * Arguments:
565  *	system		The unit-system to which the unit belongs.
566  *	name		The name of the unit.
567  *      encoding        The character encoding of "name".
568  * Returns:
569  *	UT_SUCCESS	Success.
570  *	UT_BAD_ARG	"system" or "name" is NULL.
571  */
572 EXTERNL ut_status
573 ut_unmap_name_to_unit(
574     ut_system*		system,
575     const char* const	name,
576     const ut_encoding   encoding);
577 
578 
579 /*
580  * Adds a mapping from a unit to a name.
581  *
582  * Arguments:
583  *	unit		Pointer to the unit to be mapped to "name".  May be
584  *			freed upon return.
585  *	name		Pointer to the name to be mapped-to by "unit".  May be
586  *			freed upon return.
587  *	encoding	The encoding of "name".
588  * Returns:
589  *	UT_SUCCESS	Success.
590  *	UT_BAD_ARG	"unit" or "name" is NULL, or "name" is not in the
591  *                      specified encoding.
592  *	UT_OS		Operating-system error.  See "errno".
593  *	UT_EXISTS	"unit" already maps to a name.
594  */
595 EXTERNL ut_status
596 ut_map_unit_to_name(
597     const ut_unit* const	unit,
598     const char* const		name,
599     ut_encoding			encoding);
600 
601 
602 /*
603  * Removes a mapping from a unit to a name.
604  *
605  * Arguments:
606  *	unit		Pointer to the unit.  May be freed upon return.
607  *	encoding	The encoding to be removed.  No other encodings will be
608  *			removed.
609  * Returns:
610  *	UT_BAD_ARG	"unit" is NULL.
611  *	UT_SUCCESS	Success.
612  */
613 EXTERNL ut_status
614 ut_unmap_unit_to_name(
615     const ut_unit* const	unit,
616     ut_encoding			encoding);
617 
618 
619 /******************************************************************************
620  * Mapping between Units and Symbols:
621  ******************************************************************************/
622 
623 
624 /*
625  * Returns the symbol in a given encoding to which a unit maps.
626  *
627  * Arguments:
628  *	unit		Pointer to the unit whose symbol should be returned.
629  *	encoding	The desired encoding of the symbol.
630  * Returns:
631  *	NULL		Failure.  "ut_get_status()" will be
632  *			    UT_BAD_ARG		"unit" is NULL.
633  *			    UT_SUCCESS		"unit" doesn't map to a symbol
634  *						in the given encoding.
635  *	else		Pointer to the symbol in the given encoding to which
636  *			"unit" maps.
637  */
638 EXTERNL const char*
639 ut_get_symbol(
640     const ut_unit* const	unit,
641     const ut_encoding	encoding);
642 
643 
644 /*
645  * Adds a mapping from a symbol to a unit.
646  *
647  * Arguments:
648  *	symbol		Pointer to the symbol to be mapped to "unit".  May be
649  *			freed upon return.
650  *      ut_encoding     The character encoding of "symbol".
651  *	unit		Pointer to the unit to be mapped-to by "symbol".  May
652  *			be freed upon return.
653  * Returns:
654  *	UT_BAD_ARG	"symbol" or "unit" is NULL.
655  *	UT_OS		Operating-system error.  See "errno".
656  *	UT_EXISTS	"symbol" already maps to a different unit.
657  *	UT_SUCCESS	Success.
658  */
659 EXTERNL ut_status
660 ut_map_symbol_to_unit(
661     const char* const		symbol,
662     const ut_encoding		encoding,
663     const ut_unit* const	unit);
664 
665 
666 /*
667  * Removes a mapping from a symbol to a unit.  After this function,
668  * ut_get_unit_by_symbol(system,symbol) will no longer return a unit.
669  *
670  * Arguments:
671  *	system		The unit-system to which the unit belongs.
672  *	symbol		The symbol of the unit.
673  *      encoding        The character encoding of "symbol".
674  * Returns:
675  *	UT_SUCCESS	Success.
676  *	UT_BAD_ARG	"system" or "symbol" is NULL.
677  */
678 EXTERNL ut_status
679 ut_unmap_symbol_to_unit(
680     ut_system*		system,
681     const char* const	symbol,
682     const ut_encoding   encoding);
683 
684 
685 /*
686  * Adds a mapping from a unit to a symbol.
687  *
688  * Arguments:
689  *	unit		Pointer to the unit to be mapped to "symbol".  May be
690  *			freed upon return.
691  *	symbol		Pointer to the symbol to be mapped-to by "unit".  May
692  *			be freed upon return.
693  *	encoding	The encoding of "symbol".
694  * Returns:
695  *	UT_SUCCESS	Success.
696  *	UT_BAD_ARG	"unit" or "symbol" is NULL.
697  *	UT_OS		Operating-system error.  See "errno".
698  *	UT_EXISTS	"unit" already maps to a symbol.
699  */
700 EXTERNL ut_status
701 ut_map_unit_to_symbol(
702     const ut_unit*		unit,
703     const char* const		symbol,
704     ut_encoding			encoding);
705 
706 
707 /*
708  * Removes a mapping from a unit to a symbol.
709  *
710  * Arguments:
711  *	unit		Pointer to the unit to be unmapped to a symbol.  May be
712  *			freed upon return.
713  *	encoding	The encoding to be removed.  The mappings for "unit" in
714  *			other encodings will not be removed.
715  * Returns:
716  *	UT_SUCCESS	Success.
717  *	UT_BAD_ARG	"unit" is NULL.
718  */
719 EXTERNL ut_status
720 ut_unmap_unit_to_symbol(
721     const ut_unit* const	unit,
722     ut_encoding			encoding);
723 
724 
725 /******************************************************************************
726  * Getting Information about a Unit:
727  ******************************************************************************/
728 
729 
730 /*
731  * Indicates if a given unit is dimensionless or not.  Note that logarithmic
732  * units are dimensionless by definition.
733  *
734  * Arguments:
735  *	unit	Pointer to the unit in question.
736  * Returns:
737  *	0	"unit" is dimensionfull or an error occurred.  "ut_get_status()"
738  *		 will be
739  *		    UT_BAD_ARG		"unit" is NULL.
740  *		    UT_SUCCESS		"unit" is dimensionfull.
741  *	else	"unit" is dimensionless.
742  */
743 EXTERNL int
744 ut_is_dimensionless(
745     const ut_unit* const	unit);
746 
747 
748 /*
749  * Indicates if two units belong to the same unit-system.
750  *
751  * Arguments:
752  *	unit1		Pointer to a unit.
753  *	unit2		Pointer to another unit.
754  * Returns:
755  *	0		Failure or the units belong to different unit-systems.
756  *			"ut_get_status()" will be
757  *	    		    UT_BAD_ARG		"unit1" or "unit2" is NULL.
758  *	    		    UT_SUCCESS		The units belong to different
759  *						unit-systems.
760  *	else		The units belong to the same unit-system.
761  */
762 EXTERNL int
763 ut_same_system(
764     const ut_unit* const	unit1,
765     const ut_unit* const	unit2);
766 
767 
768 /*
769  * Compares two units.  Returns a value less than, equal to, or greater than
770  * zero as the first unit is considered less than, equal to, or greater than
771  * the second unit, respectively.  Units from different unit-systems never
772  * compare equal.
773  *
774  * Arguments:
775  *	unit1		Pointer to a unit or NULL.
776  *	unit2		Pointer to another unit or NULL.
777  * Returns:
778  *	<0	The first unit is less than the second unit.
779  *	 0	The first and second units are equal or both units are NULL.
780  *	>0	The first unit is greater than the second unit.
781  */
782 EXTERNL int
783 ut_compare(
784     const ut_unit* const	unit1,
785     const ut_unit* const	unit2);
786 
787 
788 /*
789  * Indicates if numeric values in one unit are convertible to numeric values in
790  * another unit via "ut_get_converter()".  In making this determination,
791  * dimensionless units are ignored.
792  *
793  * Arguments:
794  *	unit1		Pointer to a unit.
795  *	unit2		Pointer to another unit.
796  * Returns:
797  *	0		Failure.  "ut_get_status()" will be
798  *	    		    UT_BAD_ARG		"unit1" or "unit2" is NULL.
799  *			    UT_NOT_SAME_SYSTEM	"unit1" and "unit2" belong to
800  *						different unit-sytems.
801  *			    UT_SUCCESS		Conversion between the units is
802  *						not possible (e.g., "unit1" is
803  *						"meter" and "unit2" is
804  *						"kilogram").
805  *	else	Numeric values can be converted between the units.
806  */
807 EXTERNL int
808 ut_are_convertible(
809     const ut_unit* const	unit1,
810     const ut_unit* const	unit2);
811 
812 
813 /*
814  * Returns a converter of numeric values in one unit to numeric values in
815  * another unit.  The returned converter should be passed to cv_free() when it is
816  * no longer needed by the client.
817  *
818  * NOTE:  Leap seconds are not taken into account when converting between
819  * timestamp units.
820  *
821  * Arguments:
822  *	from		Pointer to the unit from which to convert values.
823  *	to		Pointer to the unit to which to convert values.
824  * Returns:
825  *	NULL		Failure.  "ut_get_status()" will be:
826  *			    UT_BAD_ARG		"from" or "to" is NULL.
827  *			    UT_NOT_SAME_SYSTEM	"from" and "to" belong to
828  *						different unit-systems.
829  *			    UT_MEANINGLESS	Conversion between the units is
830  *						not possible.  See
831  *						"ut_are_convertible()".
832  *	else		Pointer to the appropriate converter.  The pointer
833  *			should be passed to cv_free() when no longer needed by
834  *			the client.
835  */
836 EXTERNL cv_converter*
837 ut_get_converter(
838     ut_unit* const	from,
839     ut_unit* const	to);
840 
841 
842 /******************************************************************************
843  * Arithmetic Unit Manipulation:
844  ******************************************************************************/
845 
846 
847 /*
848  * Returns a unit equivalent to another unit scaled by a numeric factor,
849  * e.g.,
850  *	const ut_unit*	meter = ...
851  *	const ut_unit*	kilometer = ut_scale(1000, meter);
852  *
853  * Arguments:
854  *	factor		The numeric scale factor.
855  *	unit		Pointer to the unit to be scaled.
856  * Returns:
857  *	NULL		Failure.  "ut_get_status()" will be
858  *			    UT_BAD_ARG  	"factor" is 0 or "unit" is NULL.
859  *			    UT_OS		Operating-system error.  See
860  *						"errno".
861  *	else		Pointer to the resulting unit.  The pointer should be
862  *			passed to ut_free() when the unit is no longer needed by
863  *			the client.
864  */
865 EXTERNL ut_unit*
866 ut_scale(
867     const double		factor,
868     const ut_unit* const	unit);
869 
870 
871 /*
872  * Returns a unit equivalent to another unit offset by a numeric amount,
873  * e.g.,
874  *	const ut_unit*	kelvin = ...
875  *	const ut_unit*	celsius = ut_offset(kelvin, 273.15);
876  *
877  * Arguments:
878  *	unit		Pointer to the unit to be offset.
879  *	offset		The numeric offset.
880  * Returns:
881  *	NULL		Failure.  "ut_get_status()" will be
882  *			    UT_BAD_ARG		"unit" is NULL.
883  *			    UT_OS		Operating-system error.  See
884  *						"errno".
885  *	else		Pointer to the resulting unit.  The pointer should be
886  *			passed to ut_free() when the unit is no longer needed by
887  *			the client.
888  */
889 EXTERNL ut_unit*
890 ut_offset(
891     const ut_unit* const	unit,
892     const double	offset);
893 
894 
895 /*
896  * Returns a unit equivalent to another unit relative to a particular time.
897  * e.g.,
898  *	const ut_unit*	second = ...
899  *	const ut_unit*	secondsSinceTheEpoch =
900  *              ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0.0));
901  *
902  * Arguments:
903  *	unit	Pointer to the time-unit to be made relative to a time-origin.
904  *	origin	The origin as returned by ut_encode_time().
905  * Returns:
906  *	NULL	Failure.  "ut_get_status()" will be
907  *		    UT_BAD_ARG		"unit" is NULL.
908  *		    UT_OS		Operating-system error.  See "errno".
909  *		    UT_MEANINGLESS	Creation of a timestamp unit based on
910  *					"unit" is not meaningful.
911  *		    UT_NO_SECOND	The associated unit-system doesn't
912  *					contain a "second" unit.  See
913  *					ut_set_second().
914  *	else	Pointer to the resulting unit.  The pointer should be passed
915  *		to ut_free() when the unit is no longer needed by the client.
916  */
917 EXTERNL ut_unit*
918 ut_offset_by_time(
919     const ut_unit* const	unit,
920     const double	origin);
921 
922 
923 /*
924  * Returns the result of multiplying one unit by another unit.
925  *
926  * Arguments:
927  *	unit1	Pointer to a unit.
928  *	unit2	Pointer to another unit.
929  * Returns:
930  *	NULL	Failure.  "ut_get_status()" will be:
931  *		    UT_BAD_ARG		"unit1" or "unit2" is NULL.
932  *		    UT_NOT_SAME_SYSTEM	"unit1" and "unit2" belong to
933  *					different unit-systems.
934  *		    UT_OS		Operating-system error. See "errno".
935  *	else	Pointer to the resulting unit.  The pointer should be passed
936  *		to ut_free() when the unit is no longer needed by the client.
937  */
938 EXTERNL ut_unit*
939 ut_multiply(
940     const ut_unit* const	unit1,
941     const ut_unit* const	unit2);
942 
943 
944 /*
945  * Returns the inverse (i.e., reciprocal) of a unit.  This convenience function
946  * is equal to "ut_raise(unit, -1)".
947  *
948  * Arguments:
949  *	unit	Pointer to the unit.
950  * Returns:
951  *	NULL	Failure.  "ut_get_status()" will be:
952  *		    UT_BAD_ARG		"unit" is NULL.
953  *		    UT_OS		Operating-system error. See "errno".
954  *	else	Pointer to the resulting unit.  The pointer should be passed to
955  *		ut_free() when the unit is no longer needed by the client.
956  */
957 EXTERNL ut_unit*
958 ut_invert(
959     const ut_unit* const	unit);
960 
961 
962 /*
963  * Returns the result of dividing one unit by another unit.  This convenience
964  * function is equivalent to the following sequence:
965  *     {
966  *         ut_unit* inverse = ut_invert(denom);
967  *         ut_multiply(numer, inverse);
968  *         ut_free(inverse);
969  *     }
970  *
971  * Arguments:
972  *	numer	Pointer to the numerator (top, dividend) unit.
973  *	denom	Pointer to the denominator (bottom, divisor) unit.
974  * Returns:
975  *	NULL	Failure.  "ut_get_status()" will be:
976  *		    UT_BAD_ARG		"numer" or "denom" is NULL.
977  *		    UT_NOT_SAME_SYSTEM	"unit1" and "unit2" belong to
978  *					different unit-systems.
979  *		    UT_OS		Operating-system error. See "errno".
980  *	else	Pointer to the resulting unit.  The pointer should be passed to
981  *		ut_free() when the unit is no longer needed by the client.
982  */
983 EXTERNL ut_unit*
984 ut_divide(
985     const ut_unit* const	numer,
986     const ut_unit* const	denom);
987 
988 
989 /*
990  * Returns the result of raising a unit to a power.
991  *
992  * Arguments:
993  *	unit	Pointer to the unit.
994  *	power	The power by which to raise "unit".  Must be greater than or
995  *		equal to -255 and less than or equal to 255.
996  * Returns:
997  *	NULL	Failure.  "ut_get_status()" will be:
998  *		    UT_BAD_ARG		"unit" is NULL or "power" is invalid.
999  *		    UT_OS		Operating-system error. See "errno".
1000  *	else	Pointer to the resulting unit.  The pointer should be passed to
1001  *		ut_free() when the unit is no longer needed by the client.
1002  */
1003 EXTERNL ut_unit*
1004 ut_raise(
1005     const ut_unit* const	unit,
1006     const int			power);
1007 
1008 
1009 /*
1010  * Returns the result of taking the root of a unit.
1011  *
1012  * Arguments:
1013  *	unit	Pointer to the unit.
1014  *	root	The root to take of "unit".  Must be greater than or
1015  *		equal to 1 and less than or equal to 255.
1016  * Returns:
1017  *	NULL	Failure.  "ut_get_status()" will be:
1018  *		    UT_BAD_ARG		"unit" is NULL, or "root" is invalid.
1019  *		                        In particular, all powers of base units
1020  *		                        in "unit" must be integral multiples of
1021  *		                        "root".
1022  *		    UT_OS		Operating-system error. See "errno".
1023  *	else	Pointer to the resulting unit.  The pointer should be passed to
1024  *		ut_free() when the unit is no longer needed by the client.
1025  */
1026 EXTERNL ut_unit*
1027 ut_root(
1028     const ut_unit* const	unit,
1029     const int			root);
1030 
1031 
1032 /*
1033  * Returns the logarithmic unit corresponding to a logarithmic base and a
1034  * reference level.  For example, the following creates a decibel unit with a
1035  * one milliwatt reference level:
1036  *
1037  *     const ut_unit* watt = ...;
1038  *     const ut_unit* milliWatt = ut_scale(0.001, watt);
1039  *
1040  *     if (milliWatt != NULL) {
1041  *         const ut_unit* bel_1_mW = ut_log(10.0, milliWatt);
1042  *
1043  *         if (bel_1_mW != NULL) {
1044  *             const ut_unit* decibel_1_mW = ut_scale(0.1, bel_1_mW);
1045  *
1046  *             if (decibel_1_mW != NULL) {
1047  *                 ...
1048  *                 ut_free(decibel_1_mW);
1049  *             }			// "decibel_1_mW" allocated
1050  *
1051  *             ut_free(bel_1_mW);
1052  *         }				// "bel_1_mW" allocated
1053  *
1054  *         ut_free(milliWatt);
1055  *     }				// "milliWatt" allocated
1056  *
1057  * Arguments:
1058  *	base		The logarithmic base (e.g., 2, M_E, 10).  Must be
1059  *                      greater than one.  "M_E" is defined in <math.h>.
1060  *	reference	Pointer to the reference value as a unit.
1061  * Returns:
1062  *	NULL		Failure.  "ut_get_status()" will be:
1063  *			    UT_BAD_ARG	        "base" is invalid or "reference"
1064  *                                              is NULL.
1065  *			    UT_OS		Operating-system error. See
1066  *						"errno".
1067  *	else		Pointer to the resulting unit.  The pointer should be
1068  *			passed to ut_free() when the unit is no longer needed by
1069  *			the client.
1070  */
1071 EXTERNL ut_unit*
1072 ut_log(
1073     const double		base,
1074     const ut_unit* const	reference);
1075 
1076 
1077 /******************************************************************************
1078  * Parsing and Formatting Units:
1079  ******************************************************************************/
1080 
1081 
1082 /*
1083  * Returns the binary representation of a unit corresponding to a string
1084  * representation.
1085  *
1086  * Arguments:
1087  *	system		Pointer to the unit-system in which the parsing will
1088  *			occur.
1089  *	string		The string to be parsed (e.g., "millimeters").  There
1090  *			should be no leading or trailing whitespace in the
1091  *			string.  See ut_trim().
1092  *	encoding	The encoding of "string".
1093  * Returns:
1094  *	NULL		Failure.  "ut_get_status()" will be one of
1095  *			    UT_BAD_ARG		"system" or "string" is NULL.
1096  *			    UT_SYNTAX		"string" contained a syntax
1097  *						error.
1098  *			    UT_UNKNOWN		"string" contained an unknown
1099  *						identifier.
1100  *			    UT_OS		Operating-system failure.  See
1101  *						"errno".
1102  *	else		Pointer to the unit corresponding to "string".
1103  */
1104 EXTERNL ut_unit*
1105 ut_parse(
1106     const ut_system* const	system,
1107     const char* const		string,
1108     ut_encoding		        encoding);
1109 
1110 
1111 /*
1112  * Removes leading and trailing whitespace from a string.
1113  *
1114  * Arguments:
1115  *	string		NUL-terminated string.  Will be modified if it contains
1116  *                      whitespace..
1117  *	encoding	The character-encoding of "string".
1118  * Returns:
1119  *      "string", with all leading and trailing whitespace removed.
1120  */
1121 EXTERNL char*
1122 ut_trim(
1123     char* const	        string,
1124     const ut_encoding	encoding);
1125 
1126 
1127 /*
1128  * Formats a unit.
1129  *
1130  * Arguments:
1131  *	unit		Pointer to the unit to be formatted.
1132  *	buf		Pointer to the buffer into which to format "unit".
1133  *	size		Size of the buffer in bytes.
1134  *	opts		Formatting options: bitwise-OR of zero or more of the
1135  *			following:
1136  *			    UT_NAMES		Use unit names instead of
1137  *						symbols
1138  *                          UT_DEFINITION       The formatted string should be
1139  *                                              the definition of "unit" in
1140  *                                              terms of basic-units instead of
1141  *						stopping any expansion at the
1142  *						highest level possible.
1143  *			    UT_ASCII		The string should be formatted
1144  *						using the ASCII character set
1145  *						(default).
1146  *			    UT_LATIN1		The string should be formatted
1147  *						using the ISO Latin-1 (alias
1148  *						ISO-8859-1) character set.
1149  *			    UT_UTF8		The string should be formatted
1150  *						using the UTF-8 character set.
1151  *			UT_LATIN1 and UT_UTF8 are mutually exclusive: they may
1152  *			not both be specified.
1153  * Returns:
1154  *	-1		Failure:  "ut_get_status()" will be
1155  *			    UT_BAD_ARG		"unit" or "buf" is NULL, or both
1156  *                                              UT_LATIN1 and UT_UTF8 specified.
1157  *			    UT_CANT_FORMAT	"unit" can't be formatted in
1158  *						the desired manner.
1159  *      else		Success.  Number of characters printed in "buf".  If
1160  *			the number is equal to the size of the buffer, then the
1161  *			buffer is too small to have a terminating NUL character.
1162  */
1163 EXTERNL int
1164 ut_format(
1165     const ut_unit* const	unit,
1166     char*		buf,
1167     size_t		size,
1168     unsigned		opts);
1169 
1170 
1171 /*
1172  * Accepts a visitor to a unit.
1173  *
1174  * Arguments:
1175  *	unit		Pointer to the unit to accept the visitor.
1176  *	visitor		Pointer to the visitor of "unit".
1177  *	arg		An arbitrary pointer that will be passed to "visitor".
1178  * Returns:
1179  *	UT_BAD_ARG	"unit" or "visitor" is NULL.
1180  *	UT_VISIT_ERROR	A error occurred in "visitor" while visiting "unit".
1181  *	UT_SUCCESS	Success.
1182  */
1183 EXTERNL ut_status
1184 ut_accept_visitor(
1185     const ut_unit* const		unit,
1186     const ut_visitor* const	visitor,
1187     void* const			arg);
1188 
1189 
1190 /******************************************************************************
1191  * Time Handling:
1192  ******************************************************************************/
1193 
1194 
1195 /*
1196  * Encodes a date as a double-precision value.
1197  *
1198  * Arguments:
1199  *	year		The year.
1200  *	month		The month.
1201  *	day		The day (1 = the first of the month).
1202  * Returns:
1203  *	The date encoded as a scalar value.
1204  */
1205 EXTERNL double
1206 ut_encode_date(
1207     int		year,
1208     int		month,
1209     int		day);
1210 
1211 
1212 /*
1213  * Encodes a time as a double-precision value. If an input value isn't within
1214  * its allowed range, then zero is returned and `ut_get_status()` will return
1215  * `UT_BAD_ARG`.
1216  *
1217  * @param[in] hours    The number of hours (0 = midnight). `abs(hours)` must be
1218  *                     less than 24.
1219  * @param[in] minutes  The number of minutes. `abs(minutes)` must be less than
1220  *                     60.
1221  * @param[in] seconds  The number of seconds. `fabs(seconds)` must be less than
1222  *                     or equal to 62.
1223  * @return             The clock-time encoded as a scalar value.
1224  */
1225 EXTERNL double
1226 ut_encode_clock(
1227     int    hours,
1228     int    minutes,
1229     double seconds);
1230 
1231 
1232 /*
1233  * Encodes a time as a double-precision value.  The convenience function is
1234  * equivalent to "ut_encode_date(year,month,day) +
1235  * ut_encode_clock(hour,minute,second)"
1236  *
1237  * Arguments:
1238  *	year	The year.
1239  *	month	The month.
1240  *	day	The day.
1241  *	hour	The hour.
1242  *	minute	The minute.
1243  *	second	The second.
1244  * Returns:
1245  *	The time encoded as a scalar value.
1246  */
1247 EXTERNL double
1248 ut_encode_time(
1249     const int		year,
1250     const int		month,
1251     const int		day,
1252     const int		hour,
1253     const int		minute,
1254     const double	second);
1255 
1256 
1257 /*
1258  * Decodes a time from a double-precision value.
1259  *
1260  * Arguments:
1261  *      value           The value to be decoded.
1262  *      year            Pointer to the variable to be set to the year.
1263  *      month           Pointer to the variable to be set to the month.
1264  *      day             Pointer to the variable to be set to the day.
1265  *      hour            Pointer to the variable to be set to the hour.
1266  *      minute          Pointer to the variable to be set to the minute.
1267  *      second          Pointer to the variable to be set to the second.
1268  *      resolution      Pointer to the variable to be set to the resolution
1269  *                      of the decoded time in seconds.
1270  */
1271 EXTERNL void
1272 ut_decode_time(
1273     double	value,
1274     int		*year,
1275     int		*month,
1276     int		*day,
1277     int		*hour,
1278     int		*minute,
1279     double	*second,
1280     double	*resolution);
1281 
1282 
1283 /******************************************************************************
1284  * Error Handling:
1285  ******************************************************************************/
1286 
1287 
1288 /*
1289  * Returns the status of the last operation by the units module.  This function
1290  * will not change the status.
1291  */
1292 EXTERNL ut_status
1293 ut_get_status(void);
1294 
1295 
1296 /*
1297  * Sets the status of the units module.  This function would not normally be
1298  * called by the user unless they were doing their own parsing or formatting.
1299  *
1300  * Arguments:
1301  *	status	The status of the units module.
1302  */
1303 EXTERNL void
1304 ut_set_status(
1305     ut_status	status);
1306 
1307 
1308 /*
1309  * Handles an error-message.
1310  *
1311  * Arguments:
1312  *	fmt	The format for the error-message.
1313  *	...	The arguments for "fmt".
1314  * Returns:
1315  *	<0	An output error was encountered.
1316  *	else	The number of bytes of "fmt" and "arg" written excluding any
1317  *		terminating NUL.
1318  */
1319 EXTERNL int
1320 ut_handle_error_message(
1321     const char* const	fmt,
1322     ...);
1323 
1324 
1325 /*
1326  * Returns the previously-installed error-message handler and optionally
1327  * installs a new handler.  The initial handler is "ut_write_to_stderr()".
1328  *
1329  * Arguments:
1330  *      handler		NULL or pointer to the error-message handler.  If NULL,
1331  *			then the handler is not changed.  The
1332  *			currently-installed handler can be obtained this way.
1333  * Returns:
1334  *	Pointer to the previously-installed error-message handler.
1335  */
1336 EXTERNL ut_error_message_handler
1337 ut_set_error_message_handler(
1338     ut_error_message_handler	handler);
1339 
1340 
1341 /*
1342  * Writes an error-message to the standard-error stream when received and
1343  * appends a newline.  This is the initial error-message handler.
1344  *
1345  * Arguments:
1346  *	fmt	The format for the error-message.
1347  *	args	The arguments of "fmt".
1348  * Returns:
1349  *	<0	A output error was encountered.  See "errno".
1350  *	else	The number of bytes of "fmt" and "arg" written excluding any
1351  *		terminating NUL.
1352  */
1353 EXTERNL int
1354 ut_write_to_stderr(
1355     const char* const	fmt,
1356     va_list		args);
1357 
1358 
1359 /*
1360  * Does nothing with an error-message.
1361  *
1362  * Arguments:
1363  *	fmt	The format for the error-message.
1364  *	args	The arguments of "fmt".
1365  * Returns:
1366  *	0	Always.
1367  */
1368 EXTERNL int
1369 ut_ignore(
1370     const char* const	fmt,
1371     va_list		args);
1372 
1373 
1374 #ifdef __cplusplus
1375 }
1376 #endif
1377 
1378 #endif
1379