/udunits/prog/udunits2.c
C | 464 lines | 357 code | 89 blank | 18 comment | 73 complexity | 3ff1b0e4d760eebad3ebad5e5f1c905b MD5 | raw file
- /*
- * Copyright 2007, 2008, 2009 University Corporation for Atmospheric Research
- *
- * This file is part of the UDUNITS-2 package. See the file LICENSE
- * in the top-level source-directory of the package for copying and
- * redistribution conditions.
- */
- /*
- * This program prints definitions of units of physical qantities and converts
- * values between such units.
- */
- #ifndef _XOPEN_SOURCE
- # define _XOPEN_SOURCE 500
- #endif
- #include <errno.h>
- #include <limits.h>
- #include <sys/types.h>
- #include <regex.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <strings.h>
- #include <unistd.h>
- #include <udunits2.h>
- static int _reveal;
- static int _encodingSet;
- static ut_encoding _encoding;
- static const char* _progname = "udunits2";
- static const char* _xmlPath;
- static ut_system* _unitSystem;
- static char _haveUnitSpec[_POSIX_MAX_INPUT+1];
- static char _wantSpec[_POSIX_MAX_INPUT+1];
- static ut_unit* _haveUnit;
- static ut_unit* _wantUnit;
- static int _wantDefinition;
- static int _formattingOptions = UT_DEFINITION;
- static int _exitStatus = EXIT_FAILURE;
- static void
- usage(void)
- {
- (void)fprintf(stderr,
- "Usage: %s [-A|-L|-U] [-hr] [XML_file]\n"
- "\n"
- "where:\n"
- " -A Use ASCII encoding.\n"
- " -L Use ISO-8859-1 (ISO Latin-1) encoding.\n"
- " -U Use UTF-8 encoding.\n"
- " -h Help. Print this message.\n"
- " -r Reveal any problems in the database.\n"
- " XML_file XML database file.\n",
- _progname);
- }
- static int
- decodeCommandLine(
- int argc,
- char* const* argv)
- {
- int c;
- int success = 0;
- while ((c = getopt(argc, argv, "ALUhr")) != -1) {
- switch (c) {
- case 'A':
- _encoding = UT_ASCII;
- _encodingSet = 1;
- continue;
- case 'L':
- _encoding = UT_LATIN1;
- _encodingSet = 1;
- continue;
- case 'U':
- _encoding = UT_UTF8;
- _encodingSet = 1;
- continue;
- case 'r':
- _reveal = 1;
- continue;
- case 'h':
- _exitStatus = EXIT_SUCCESS;
- /*FALLTHROUGH*/
- case '?':
- usage();
- break;
- default:
- (void)fprintf(stderr, "%s: Unknown option \"%c\"\n",
- _progname, c);
- usage();
- }
- break;
- }
- if (c == -1) {
- _xmlPath =
- optind < argc
- ? argv[optind]
- : NULL;
- success = 1;
- }
- return success;
- }
- static int
- ensureXmlPathSet(void)
- {
- if (_xmlPath == NULL)
- (void)fprintf(stderr, "%s: Using default XML database\n", _progname);
- return 1;
- }
- static void
- setEncoding(
- char* value)
- {
- if (value != NULL) {
- typedef struct {
- const char* pattern;
- ut_encoding encoding;
- regex_t reg;
- } Entry;
- static Entry entries[] = {
- {"^c$", UT_ASCII},
- {"^posix$", UT_ASCII},
- {"ascii", UT_ASCII},
- {"latin.?1([^0-9]|$)", UT_LATIN1},
- {"8859.?1([^0-9]|$)", UT_LATIN1},
- {"utf.?8([^0-9]|$)", UT_UTF8},
- };
- static int initialized = 0;
- static int entryCount = sizeof(entries)/sizeof(entries[0]);
- if (!initialized) {
- int status = 0;
- int i;
- for (i = 0; i < entryCount; i++) {
- Entry* entry = entries + i;
- regex_t* reg = &entry->reg;
- const char* pattern = entry->pattern;
- status =
- regcomp(reg, entries[i].pattern,
- REG_EXTENDED | REG_ICASE | REG_NOSUB);
- if (status != 0) {
- char buf[132];
- (void)regerror(status, reg, buf, sizeof(buf));
- (void)fprintf(stderr, "%s: Unable to compile regular "
- "expression \"%s\": %s\n", _progname, pattern, buf);
- break;
- }
- }
- if (status == 0)
- initialized = 1;
- }
- if (initialized) {
- int i;
- int status = 0;
- for (i = 0; i < entryCount; i++) {
- Entry* entry = entries + i;
- regex_t* reg = &entry->reg;
- status = regexec(reg, value, 0, NULL, 0);
- if (status == 0)
- break;
- if (status != REG_NOMATCH) {
- char buf[132];
- (void)regerror(status, reg, buf, sizeof(buf));
- (void)fprintf(stderr,
- "%s: Unable to execute regular expression \"%s\": %s\n",
- _progname, entry->pattern, buf);
- break;
- }
- }
- if (status == 0 && i < entryCount) {
- _encoding = entries[i].encoding;
- _encodingSet = 1;
- }
- }
- }
- }
- static int
- ensureEncodingSet()
- {
- if (!_encodingSet) {
- setEncoding(getenv("LC_ALL"));
- if (!_encodingSet) {
- setEncoding(getenv("LC_CTYPE"));
- if (!_encodingSet) {
- setEncoding(getenv("LANG"));
- if (!_encodingSet) {
- (void)fprintf(stderr, "%s: Character encoding not "
- "specified and not settable from environment variables "
- "LC_ALL, LC_CTYPE, or LANG. Assuming ASCII "
- "encoding.\n", _progname);
- setEncoding("ASCII");
- }
- }
- }
- }
- if (_encodingSet)
- _formattingOptions |= _encoding;
- return _encodingSet;
- }
- static int
- readXmlDatabase(void)
- {
- int success = 0;
- if (!_reveal)
- ut_set_error_message_handler(ut_ignore);
- _unitSystem = ut_read_xml(_xmlPath);
- ut_set_error_message_handler(ut_write_to_stderr);
- if (_unitSystem != NULL) {
- success = 1;
- }
- else {
- (void)fprintf(stderr, "%s: Couldn't initialize unit-system from "
- "database \"%s\"\n", _progname, _xmlPath);
- }
- return success;
- }
- /*
- * Get a specification.
- */
- static int
- getSpec(
- const char* const prompt,
- char* const spec,
- const size_t size)
- {
- int nbytes = -1; /* failure */
- if (fputs(prompt, stdout) == EOF) {
- (void)fprintf(stderr, "%s: Couldn't write prompt: %s\n",
- _progname, strerror(errno));
- } else if (fgets(spec, size, stdin) == NULL) {
- putchar('\n');
- if (feof(stdin)) {
- _exitStatus = EXIT_SUCCESS;
- } else {
- (void)fprintf(stderr, "%s: Couldn't read from standard input: %s\n",
- _progname, strerror(errno));
- }
- } else {
- /*
- * Trim any whitespace from the specification.
- */
- (void)ut_trim(spec, _encoding);
- nbytes = strlen(spec);
- }
- return nbytes;
- }
- static int
- getInputValue(void)
- {
- int success = 0;
- for (;;) {
- char buf[sizeof(_haveUnitSpec)];
- int nbytes = getSpec("You have: ", buf, sizeof(buf));
- if (nbytes < 0)
- break;
- if (nbytes > 0) {
- (void)strcpy(_haveUnitSpec, buf);
- ut_free(_haveUnit);
- _haveUnit = ut_parse(_unitSystem, _haveUnitSpec, _encoding);
- if (_haveUnit == NULL) {
- (void)fprintf(stderr, "%s: Don't recognize \"%s\"\n",
- _progname, _haveUnitSpec);
- }
- else {
- success = 1;
- break;
- }
- }
- }
- return success;
- }
- static int
- getOutputRequest(void)
- {
- int success = 0;
- for (;;) {
- int nbytes =
- getSpec("You want: ", _wantSpec, sizeof(_wantSpec));
- if (nbytes < 0)
- break;
- if (nbytes == 0) {
- _wantDefinition = 1;
- success = 1;
- break;
- }
- _wantDefinition = 0;
- ut_free(_wantUnit);
- _wantUnit = ut_parse(_unitSystem, _wantSpec, _encoding);
- if (_wantUnit == NULL) {
- (void)fprintf(stderr, "%s: Don't recognize \"%s\"\n",
- _progname, _wantSpec);
- }
- else {
- success = 1;
- break;
- }
- }
- return success;
- }
- static int
- handleRequest(void)
- {
- int success = 0;
- if (getInputValue()) {
- if (getOutputRequest()) {
- if (_wantDefinition) {
- char buf[256];
- int nbytes = ut_format(_haveUnit, buf, sizeof(buf),
- _formattingOptions);
- if (nbytes >= sizeof(buf)) {
- (void)fprintf(stderr, "%s: Resulting unit "
- "specification is too long\n", _progname);
- }
- else if (nbytes >= 0) {
- buf[nbytes] = 0;
- (void)printf(" %s\n", buf);
- }
- }
- else if (!ut_are_convertible(_wantUnit, _haveUnit)) {
- (void)fprintf(stderr, "%s: Units are not convertible\n",
- _progname);
- }
- else {
- cv_converter* conv = ut_get_converter(_haveUnit, _wantUnit);
- if (conv == NULL) {
- (void)fprintf(stderr, "%s: Couldn't get unit converter\n",
- _progname);
- }
- else {
- char haveExp[_POSIX_MAX_INPUT+1];
- char exp[_POSIX_MAX_INPUT+1];
- char whiteSpace[] = " \t\n\r\f\v\xa0";
- int needsParens =
- strpbrk(_wantSpec, whiteSpace) != NULL;
- int n;
- (void)printf(
- needsParens
- ? " %s = %g (%s)\n"
- : " %s = %g %s\n",
- _haveUnitSpec,
- cv_convert_double(conv, 1.0), _wantSpec);
- (void)sprintf(haveExp,
- strpbrk(_haveUnitSpec, whiteSpace) ||
- strpbrk(_haveUnitSpec, "/")
- ? "(x/(%s))"
- : "(x/%s)",
- _haveUnitSpec);
- n = cv_get_expression(conv, exp, sizeof(exp), haveExp);
- if (n >= 0)
- (void)printf(
- strpbrk(_wantSpec, whiteSpace) ||
- strpbrk(_wantSpec, "/")
- ? " x/(%s) = %*s\n"
- : " x/%s = %*s\n",
- _wantSpec, n, exp);
- cv_free(conv);
- }
- }
- success = 1;
- }
- }
- return success;
- }
- int
- main(
- const int argc,
- char* const* const argv)
- {
- if (decodeCommandLine(argc, argv)) {
- if (ensureEncodingSet()) {
- if (ensureXmlPathSet()) {
- if (readXmlDatabase()) {
- while (handleRequest())
- ; /* EMPTY */
- }
- }
- }
- }
- return _exitStatus;
- }