PageRenderTime 25ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/udunits/prog/udunits2.c

https://bitbucket.org/iridl/netcdf
C | 464 lines | 357 code | 89 blank | 18 comment | 73 complexity | 3ff1b0e4d760eebad3ebad5e5f1c905b MD5 | raw file
  1. /*
  2. * Copyright 2007, 2008, 2009 University Corporation for Atmospheric Research
  3. *
  4. * This file is part of the UDUNITS-2 package. See the file LICENSE
  5. * in the top-level source-directory of the package for copying and
  6. * redistribution conditions.
  7. */
  8. /*
  9. * This program prints definitions of units of physical qantities and converts
  10. * values between such units.
  11. */
  12. #ifndef _XOPEN_SOURCE
  13. # define _XOPEN_SOURCE 500
  14. #endif
  15. #include <errno.h>
  16. #include <limits.h>
  17. #include <sys/types.h>
  18. #include <regex.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <strings.h>
  23. #include <unistd.h>
  24. #include <udunits2.h>
  25. static int _reveal;
  26. static int _encodingSet;
  27. static ut_encoding _encoding;
  28. static const char* _progname = "udunits2";
  29. static const char* _xmlPath;
  30. static ut_system* _unitSystem;
  31. static char _haveUnitSpec[_POSIX_MAX_INPUT+1];
  32. static char _wantSpec[_POSIX_MAX_INPUT+1];
  33. static ut_unit* _haveUnit;
  34. static ut_unit* _wantUnit;
  35. static int _wantDefinition;
  36. static int _formattingOptions = UT_DEFINITION;
  37. static int _exitStatus = EXIT_FAILURE;
  38. static void
  39. usage(void)
  40. {
  41. (void)fprintf(stderr,
  42. "Usage: %s [-A|-L|-U] [-hr] [XML_file]\n"
  43. "\n"
  44. "where:\n"
  45. " -A Use ASCII encoding.\n"
  46. " -L Use ISO-8859-1 (ISO Latin-1) encoding.\n"
  47. " -U Use UTF-8 encoding.\n"
  48. " -h Help. Print this message.\n"
  49. " -r Reveal any problems in the database.\n"
  50. " XML_file XML database file.\n",
  51. _progname);
  52. }
  53. static int
  54. decodeCommandLine(
  55. int argc,
  56. char* const* argv)
  57. {
  58. int c;
  59. int success = 0;
  60. while ((c = getopt(argc, argv, "ALUhr")) != -1) {
  61. switch (c) {
  62. case 'A':
  63. _encoding = UT_ASCII;
  64. _encodingSet = 1;
  65. continue;
  66. case 'L':
  67. _encoding = UT_LATIN1;
  68. _encodingSet = 1;
  69. continue;
  70. case 'U':
  71. _encoding = UT_UTF8;
  72. _encodingSet = 1;
  73. continue;
  74. case 'r':
  75. _reveal = 1;
  76. continue;
  77. case 'h':
  78. _exitStatus = EXIT_SUCCESS;
  79. /*FALLTHROUGH*/
  80. case '?':
  81. usage();
  82. break;
  83. default:
  84. (void)fprintf(stderr, "%s: Unknown option \"%c\"\n",
  85. _progname, c);
  86. usage();
  87. }
  88. break;
  89. }
  90. if (c == -1) {
  91. _xmlPath =
  92. optind < argc
  93. ? argv[optind]
  94. : NULL;
  95. success = 1;
  96. }
  97. return success;
  98. }
  99. static int
  100. ensureXmlPathSet(void)
  101. {
  102. if (_xmlPath == NULL)
  103. (void)fprintf(stderr, "%s: Using default XML database\n", _progname);
  104. return 1;
  105. }
  106. static void
  107. setEncoding(
  108. char* value)
  109. {
  110. if (value != NULL) {
  111. typedef struct {
  112. const char* pattern;
  113. ut_encoding encoding;
  114. regex_t reg;
  115. } Entry;
  116. static Entry entries[] = {
  117. {"^c$", UT_ASCII},
  118. {"^posix$", UT_ASCII},
  119. {"ascii", UT_ASCII},
  120. {"latin.?1([^0-9]|$)", UT_LATIN1},
  121. {"8859.?1([^0-9]|$)", UT_LATIN1},
  122. {"utf.?8([^0-9]|$)", UT_UTF8},
  123. };
  124. static int initialized = 0;
  125. static int entryCount = sizeof(entries)/sizeof(entries[0]);
  126. if (!initialized) {
  127. int status = 0;
  128. int i;
  129. for (i = 0; i < entryCount; i++) {
  130. Entry* entry = entries + i;
  131. regex_t* reg = &entry->reg;
  132. const char* pattern = entry->pattern;
  133. status =
  134. regcomp(reg, entries[i].pattern,
  135. REG_EXTENDED | REG_ICASE | REG_NOSUB);
  136. if (status != 0) {
  137. char buf[132];
  138. (void)regerror(status, reg, buf, sizeof(buf));
  139. (void)fprintf(stderr, "%s: Unable to compile regular "
  140. "expression \"%s\": %s\n", _progname, pattern, buf);
  141. break;
  142. }
  143. }
  144. if (status == 0)
  145. initialized = 1;
  146. }
  147. if (initialized) {
  148. int i;
  149. int status = 0;
  150. for (i = 0; i < entryCount; i++) {
  151. Entry* entry = entries + i;
  152. regex_t* reg = &entry->reg;
  153. status = regexec(reg, value, 0, NULL, 0);
  154. if (status == 0)
  155. break;
  156. if (status != REG_NOMATCH) {
  157. char buf[132];
  158. (void)regerror(status, reg, buf, sizeof(buf));
  159. (void)fprintf(stderr,
  160. "%s: Unable to execute regular expression \"%s\": %s\n",
  161. _progname, entry->pattern, buf);
  162. break;
  163. }
  164. }
  165. if (status == 0 && i < entryCount) {
  166. _encoding = entries[i].encoding;
  167. _encodingSet = 1;
  168. }
  169. }
  170. }
  171. }
  172. static int
  173. ensureEncodingSet()
  174. {
  175. if (!_encodingSet) {
  176. setEncoding(getenv("LC_ALL"));
  177. if (!_encodingSet) {
  178. setEncoding(getenv("LC_CTYPE"));
  179. if (!_encodingSet) {
  180. setEncoding(getenv("LANG"));
  181. if (!_encodingSet) {
  182. (void)fprintf(stderr, "%s: Character encoding not "
  183. "specified and not settable from environment variables "
  184. "LC_ALL, LC_CTYPE, or LANG. Assuming ASCII "
  185. "encoding.\n", _progname);
  186. setEncoding("ASCII");
  187. }
  188. }
  189. }
  190. }
  191. if (_encodingSet)
  192. _formattingOptions |= _encoding;
  193. return _encodingSet;
  194. }
  195. static int
  196. readXmlDatabase(void)
  197. {
  198. int success = 0;
  199. if (!_reveal)
  200. ut_set_error_message_handler(ut_ignore);
  201. _unitSystem = ut_read_xml(_xmlPath);
  202. ut_set_error_message_handler(ut_write_to_stderr);
  203. if (_unitSystem != NULL) {
  204. success = 1;
  205. }
  206. else {
  207. (void)fprintf(stderr, "%s: Couldn't initialize unit-system from "
  208. "database \"%s\"\n", _progname, _xmlPath);
  209. }
  210. return success;
  211. }
  212. /*
  213. * Get a specification.
  214. */
  215. static int
  216. getSpec(
  217. const char* const prompt,
  218. char* const spec,
  219. const size_t size)
  220. {
  221. int nbytes = -1; /* failure */
  222. if (fputs(prompt, stdout) == EOF) {
  223. (void)fprintf(stderr, "%s: Couldn't write prompt: %s\n",
  224. _progname, strerror(errno));
  225. } else if (fgets(spec, size, stdin) == NULL) {
  226. putchar('\n');
  227. if (feof(stdin)) {
  228. _exitStatus = EXIT_SUCCESS;
  229. } else {
  230. (void)fprintf(stderr, "%s: Couldn't read from standard input: %s\n",
  231. _progname, strerror(errno));
  232. }
  233. } else {
  234. /*
  235. * Trim any whitespace from the specification.
  236. */
  237. (void)ut_trim(spec, _encoding);
  238. nbytes = strlen(spec);
  239. }
  240. return nbytes;
  241. }
  242. static int
  243. getInputValue(void)
  244. {
  245. int success = 0;
  246. for (;;) {
  247. char buf[sizeof(_haveUnitSpec)];
  248. int nbytes = getSpec("You have: ", buf, sizeof(buf));
  249. if (nbytes < 0)
  250. break;
  251. if (nbytes > 0) {
  252. (void)strcpy(_haveUnitSpec, buf);
  253. ut_free(_haveUnit);
  254. _haveUnit = ut_parse(_unitSystem, _haveUnitSpec, _encoding);
  255. if (_haveUnit == NULL) {
  256. (void)fprintf(stderr, "%s: Don't recognize \"%s\"\n",
  257. _progname, _haveUnitSpec);
  258. }
  259. else {
  260. success = 1;
  261. break;
  262. }
  263. }
  264. }
  265. return success;
  266. }
  267. static int
  268. getOutputRequest(void)
  269. {
  270. int success = 0;
  271. for (;;) {
  272. int nbytes =
  273. getSpec("You want: ", _wantSpec, sizeof(_wantSpec));
  274. if (nbytes < 0)
  275. break;
  276. if (nbytes == 0) {
  277. _wantDefinition = 1;
  278. success = 1;
  279. break;
  280. }
  281. _wantDefinition = 0;
  282. ut_free(_wantUnit);
  283. _wantUnit = ut_parse(_unitSystem, _wantSpec, _encoding);
  284. if (_wantUnit == NULL) {
  285. (void)fprintf(stderr, "%s: Don't recognize \"%s\"\n",
  286. _progname, _wantSpec);
  287. }
  288. else {
  289. success = 1;
  290. break;
  291. }
  292. }
  293. return success;
  294. }
  295. static int
  296. handleRequest(void)
  297. {
  298. int success = 0;
  299. if (getInputValue()) {
  300. if (getOutputRequest()) {
  301. if (_wantDefinition) {
  302. char buf[256];
  303. int nbytes = ut_format(_haveUnit, buf, sizeof(buf),
  304. _formattingOptions);
  305. if (nbytes >= sizeof(buf)) {
  306. (void)fprintf(stderr, "%s: Resulting unit "
  307. "specification is too long\n", _progname);
  308. }
  309. else if (nbytes >= 0) {
  310. buf[nbytes] = 0;
  311. (void)printf(" %s\n", buf);
  312. }
  313. }
  314. else if (!ut_are_convertible(_wantUnit, _haveUnit)) {
  315. (void)fprintf(stderr, "%s: Units are not convertible\n",
  316. _progname);
  317. }
  318. else {
  319. cv_converter* conv = ut_get_converter(_haveUnit, _wantUnit);
  320. if (conv == NULL) {
  321. (void)fprintf(stderr, "%s: Couldn't get unit converter\n",
  322. _progname);
  323. }
  324. else {
  325. char haveExp[_POSIX_MAX_INPUT+1];
  326. char exp[_POSIX_MAX_INPUT+1];
  327. char whiteSpace[] = " \t\n\r\f\v\xa0";
  328. int needsParens =
  329. strpbrk(_wantSpec, whiteSpace) != NULL;
  330. int n;
  331. (void)printf(
  332. needsParens
  333. ? " %s = %g (%s)\n"
  334. : " %s = %g %s\n",
  335. _haveUnitSpec,
  336. cv_convert_double(conv, 1.0), _wantSpec);
  337. (void)sprintf(haveExp,
  338. strpbrk(_haveUnitSpec, whiteSpace) ||
  339. strpbrk(_haveUnitSpec, "/")
  340. ? "(x/(%s))"
  341. : "(x/%s)",
  342. _haveUnitSpec);
  343. n = cv_get_expression(conv, exp, sizeof(exp), haveExp);
  344. if (n >= 0)
  345. (void)printf(
  346. strpbrk(_wantSpec, whiteSpace) ||
  347. strpbrk(_wantSpec, "/")
  348. ? " x/(%s) = %*s\n"
  349. : " x/%s = %*s\n",
  350. _wantSpec, n, exp);
  351. cv_free(conv);
  352. }
  353. }
  354. success = 1;
  355. }
  356. }
  357. return success;
  358. }
  359. int
  360. main(
  361. const int argc,
  362. char* const* const argv)
  363. {
  364. if (decodeCommandLine(argc, argv)) {
  365. if (ensureEncodingSet()) {
  366. if (ensureXmlPathSet()) {
  367. if (readXmlDatabase()) {
  368. while (handleRequest())
  369. ; /* EMPTY */
  370. }
  371. }
  372. }
  373. }
  374. return _exitStatus;
  375. }