tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Add -l/-L (list) options to units(1)
The attached patch adds -l and -L options to units(1), to make it
list the internal database. Here's the relevant part of the man
page:
-l or -L List all unit definitions to the standard output,
instead of performing any conversions. The result
may include error messages and comments, beginning
with `/'.
With the -l option, unit definitions will be listed
in a format almost identical to the the units data
file that was loaded, except that comments will be
removed, spacing may be changed, and lines may be re-
ordered.
With the -L option, all unit definitions will be
reduced to a form that depends on only a few primi-
tive units (such as m, kg, sec).
The errors that I have just fixed in units.lib were found by
running "units -L". I suggest that it would be good practice to
compare the output from "units -L" before and after making changes
to units.lib.
--apb (Alan Barrett)
Index: units.c
===================================================================
--- units.c 20 Mar 2012 20:34:59 -0000 1.18
+++ units.c 28 Dec 2012 13:33:16 -0000
@@ -19,6 +19,7 @@
#include <ctype.h>
#include <err.h>
+#include <float.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -39,6 +40,10 @@
#define PRIMITIVECHAR '!'
+static int precision = 8; /* for printf with "%.*g" format */
+
+static const char *errorprefix = ""; /* printed before error messages */
+
static const char *powerstring = "^";
static struct {
@@ -249,7 +254,7 @@ showunit(struct unittype * theunit)
int printedslash;
int counter = 1;
- printf("\t%.8g", theunit->factor);
+ printf("\t%.*g", precision, theunit->factor);
for (ptr = theunit->numerator; *ptr; ptr++) {
if (ptr > theunit->numerator && **ptr &&
!strcmp(*ptr, *(ptr - 1)))
@@ -534,7 +539,8 @@ reduceproduct(struct unittype * theunit,
break;
toadd = lookupunit(*product);
if (!toadd) {
- printf("unknown unit '%s'\n", *product);
+ printf("%sunknown unit '%s'\n", errorprefix,
+ *product);
return ERROR;
}
if (strchr(toadd, PRIMITIVECHAR))
@@ -627,20 +633,100 @@ showanswer(struct unittype * have, struc
{
if (compareunits(have, want)) {
if (compareunitsreciprocal(have, want)) {
- printf("conformability error\n");
+ printf("%sconformability error\n", errorprefix);
showunit(have);
showunit(want);
} else {
printf("\treciprocal conversion\n");
- printf("\t* %.8g\n\t/ %.8g\n", 1 / (have->factor *
want->factor),
- want->factor * have->factor);
+ printf("\t* %.*g\n\t/ %.*g\n",
+ precision, 1 / (have->factor * want->factor),
+ precision, want->factor * have->factor);
}
}
else
- printf("\t* %.8g\n\t/ %.8g\n", have->factor / want->factor,
- want->factor / have->factor);
+ printf("\t* %.*g\n\t/ %.*g\n",
+ precision, have->factor / want->factor,
+ precision, want->factor / have->factor);
}
+static int
+listunits(int expand)
+{
+ struct unittype theunit;
+ const char *thename;
+ const char *thedefn;
+ int errors = 0;
+ int i;
+
+#if 0 /* debug */
+ printf("/ expand=%d precision=%d unitcount=%d prefixcount=%d\n",
+ expand, precision, unitcount, prefixcount);
+#endif
+
+ errorprefix = "/ ";
+
+ /* 1. Dump all primitive units, e.g. "m !a!", "kg !b!", ... */
+ printf("/ primitive units\n");
+ for (i = 0; i < unitcount; i++) {
+ thename = unittable[i].uname;
+ thedefn = unittable[i].uval;
+ if (thedefn[0] == PRIMITIVECHAR) {
+ printf("%s\t%s\n", thename, thedefn);
+ }
+ }
+
+ /* 2. Dump all prefixes, e.g. "yotta- 1e24", "zetta- 1e21", ... */
+ printf("/ prefixes\n");
+ for (i = 0; i < prefixcount; i++) {
+ thename = prefixtable[i].prefixname;
+ thedefn = prefixtable[i].prefixval;
+ if (expand) {
+ /*
+ * prefix names are sometimes identical to unit
+ * names, so we have to expand thedefn instead of
+ * expanding thename.
+ */
+ initializeunit(&theunit);
+ if (addunit(&theunit, thedefn, 0) != 0
+ || completereduce(&theunit) != 0) {
+ errors++;
+ printf("%serror in prefix '%s-'\n",
+ errorprefix, thename);
+ }
+ printf("%s-", thename);
+ showunit(&theunit);
+ } else {
+ printf("%s-\t%s\n", thename, thedefn);
+ }
+ }
+
+ /* 3. Dump all other units. */
+ printf("/ other units\n");
+ for (i = 0; i < unitcount; i++) {
+ thename = unittable[i].uname;
+ thedefn = unittable[i].uval;
+ if (thedefn[0] != PRIMITIVECHAR) {
+ if (expand) {
+ initializeunit(&theunit);
+ if (addunit(&theunit, thedefn, 0) != 0
+ || completereduce(&theunit) != 0) {
+ errors++;
+ printf("%serror in unit '%s'\n",
+ errorprefix, thename);
+ }
+ printf("%s", thename);
+ showunit(&theunit);
+ } else {
+ printf("%s\t%s\n", thename, thedefn);
+ }
+ }
+ }
+
+ if (errors) {
+ printf("%s%d errors\n", errorprefix, errors);
+ }
+ return (errors ? 1 : 0);
+}
static void
usage(void)
@@ -661,10 +747,19 @@ main(int argc, char **argv)
char havestr[81], wantstr[81];
int optchar;
const char *userfile = 0;
+ int list = 0, listexpand = 0;
int quiet = 0;
- while ((optchar = getopt(argc, argv, "vqf:")) != -1) {
+ while ((optchar = getopt(argc, argv, "lLvqf:")) != -1) {
switch (optchar) {
+ case 'l':
+ list = 1;
+ break;
+ case 'L':
+ list = 1;
+ listexpand = 1;
+ precision = DBL_DIG;
+ break;
case 'f':
userfile = optarg;
break;
@@ -690,6 +785,12 @@ main(int argc, char **argv)
readunits(userfile);
+ if (list) {
+ if (argc != 0)
+ usage();
+ return listunits(listexpand);
+ }
+
if (argc == 3) {
strlcpy(havestr, argv[0], sizeof(havestr));
strlcat(havestr, " ", sizeof(havestr));
Index: units.1
===================================================================
--- units.1 28 Dec 2012 13:25:25 -0000 1.18
+++ units.1 28 Dec 2012 13:33:16 -0000
@@ -8,7 +8,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl f Ar filename
-.Op Fl qv
+.Op Fl lLqv
.Oo
.Op Ar count
.Ar from-unit to-unit
@@ -25,6 +25,24 @@ The following options and arguments are
.Bl -tag -width "-fXfilenameX" -offset indent
.It Fl f Ar filename
Specifies the name of the units data file to load.
+.It Fl l No or Fl L
+List all unit definitions to the standard output,
+instead of performing any conversions.
+The result may include error messages and comments, beginning with
+.Ql \&/ .
+.Pp
+With the
+.Fl l
+option, unit definitions will be listed in a format
+almost identical to the the units data file that was loaded,
+except that comments will be removed, spacing may be changed,
+and lines may be re-ordered.
+.Pp
+With the
+.Fl L
+option, all unit definitions will be reduced to a form that
+depends on only a few primitive units (such as
+.Sy m , kg , sec ) .
.It Fl q
Suppresses prompting of the user for units and the display of statistics
about the number of units loaded.
Home |
Main Index |
Thread Index |
Old Index