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