]> Zhao Yanbai Git Server - minix.git/commitdiff
Importing usr.bin/units 60/1060/1
authorThomas Cort <tcort@minix3.org>
Wed, 23 Oct 2013 23:24:43 +0000 (19:24 -0400)
committerThomas Cort <tcort@minix3.org>
Wed, 23 Oct 2013 23:24:43 +0000 (19:24 -0400)
No Minix-specific changes needed.

Change-Id: I2a3411bf78d5e31875d577dcd6df68f76da98137

distrib/sets/lists/minix/mi
releasetools/nbsd_ports
usr.bin/Makefile
usr.bin/units/Makefile [new file with mode: 0644]
usr.bin/units/README [new file with mode: 0644]
usr.bin/units/pathnames.h [new file with mode: 0644]
usr.bin/units/units.1 [new file with mode: 0644]
usr.bin/units/units.c [new file with mode: 0644]
usr.bin/units/units.lib [new file with mode: 0644]

index f600054ec580ea0c8de1f43375032ad41a417f47..c86b1cb3d062f3adc23a9590e95356c04701cc62 100644 (file)
 ./usr/bin/uncompress                   minix-sys
 ./usr/bin/unexpand                     minix-sys
 ./usr/bin/uniq                         minix-sys
+./usr/bin/units                                minix-sys
 ./usr/bin/unlzma                       minix-sys
 ./usr/bin/unstack                      minix-sys
 ./usr/bin/unxz                         minix-sys
 ./usr/man/man1/uncompress.1            minix-sys
 ./usr/man/man1/unexpand.1              minix-sys
 ./usr/man/man1/uniq.1                  minix-sys
+./usr/man/man1/units.1                 minix-sys
 ./usr/man/man1/unlzma.1                        minix-sys
 ./usr/man/man1/unset.1                 minix-sys
 ./usr/man/man1/unxz.1                  minix-sys
 ./usr/share/misc/texinfo.dtd           minix-sys
 ./usr/share/misc/texinfo.tex           minix-sys
 ./usr/share/misc/texinfo.xsl           minix-sys
+./usr/share/misc/units.lib             minix-sys
 ./usr/share/misc/zipcodes              minix-sys
 ./usr/share/mk                         minix-sys
 ./usr/share/mk/bsd.clang-analyze.mk    minix-sys
index 2a129af267f7ca414051fabe6481511ef2dce7ad..1f2765f461ea88eae3c282388c10f5a4c66ef9fb 100644 (file)
 2012/10/17 12:00:00,usr.bin/tr
 2012/10/17 12:00:00,usr.bin/tsort
 2010/10/06 07:59:18,usr.bin/uniq
+2013/10/23 12:00:00,usr.bin/units
 2013/10/14 12:00:00,usr.bin/unzip
 2013/10/14 12:00:00,usr.bin/users
 2012/10/17 12:00:00,usr.bin/wc
index 3ed62c4512055560b8e386bc83816b0c4e003445..e8b64c5fb5f2a5d49e0b464edca38c78fd8fc8dc 100644 (file)
@@ -28,7 +28,7 @@ SUBDIR= \
        tee tic tput \
        tr tsort unexpand \
        toproto \
-       uniq unzip users \
+       uniq units unzip users \
        \
        wc whatis who \
        xargs xinstall yes
diff --git a/usr.bin/units/Makefile b/usr.bin/units/Makefile
new file mode 100644 (file)
index 0000000..8bd174d
--- /dev/null
@@ -0,0 +1,11 @@
+#      $NetBSD: Makefile,v 1.6 1999/02/13 02:54:56 lukem Exp $
+
+.include <bsd.own.mk>
+
+PROG=  units
+.if ${MKSHARE} != "no"
+FILES=  units.lib
+FILESDIR=/usr/share/misc
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/units/README b/usr.bin/units/README
new file mode 100644 (file)
index 0000000..ce33534
--- /dev/null
@@ -0,0 +1,18 @@
+#      $NetBSD: README,v 1.2 1996/04/06 06:00:59 thorpej Exp $
+
+This is a program which I wrote as a clone of the UNIX 'units'
+command.  I threw it together in a couple days, but it seems to work,
+with some restrictions.  I have tested it under DOS with Borland C and
+Ultrix 4.2, and SunOS 4.1.  
+
+This program differs from the unix units program in the following
+ways:
+   it can gracefully handle exponents larger than 9 in output
+   it uses 'e' to denote exponentiation in numbers
+   prefixes are listed in the units file
+   it tries both -s and -es plurals
+   it allows use of * for multiply and ^ for exponentiation in the input
+   the output format is somewhat different
+
+Adrian Mariano (adrian@cam.cornell.edu or mariano@geom.umn.edu)
+
diff --git a/usr.bin/units/pathnames.h b/usr.bin/units/pathnames.h
new file mode 100644 (file)
index 0000000..a2105bf
--- /dev/null
@@ -0,0 +1,37 @@
+/* $NetBSD: pathnames.h,v 1.6 2003/07/26 20:34:14 salo Exp $ */
+
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *          This product includes software developed for the
+ *          NetBSD Project.  See http://www.NetBSD.org/ for
+ *          information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
+ */
+
+#define        _PATH_UNITSLIB  "/usr/share/misc/units.lib"
diff --git a/usr.bin/units/units.1 b/usr.bin/units/units.1
new file mode 100644 (file)
index 0000000..afac609
--- /dev/null
@@ -0,0 +1,229 @@
+.\"    $NetBSD: units.1,v 1.21 2013/07/20 21:40:01 wiz Exp $
+.Dd January 6, 2013
+.Dt UNITS 1
+.Os
+.Sh NAME
+.Nm units
+.Nd conversion program
+.Sh SYNOPSIS
+.Nm
+.Op Fl Llqv
+.Op Fl f Ar filename
+.Oo
+.Op Ar count
+.Ar from-unit to-unit
+.Oc
+.Sh DESCRIPTION
+.Nm
+converts quantities expression in various scales to
+their equivalents in other scales.
+.Nm
+can only handle multiplicative scale changes.
+It cannot convert Centigrade to Fahrenheit, for example.
+.Pp
+The following options and arguments are supported:
+.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.
+.It Fl v
+Prints the version number.
+.It Oo Ar count Oc Ar from-unit Ar to-unit
+Allows a single unit conversion to be done directly from the command
+line.
+No prompting will occur.
+.Nm
+will print out only the result of this single conversion.
+Specifying
+.Ar count
+and
+.Ar from-unit
+as two separate arguments is equivalent to embedding both parts
+inside a single
+.Ar from-unit
+argument, with the parts separated by a space.
+.El
+.Pp
+.Nm
+works interactively by prompting the user for input:
+.Bd -literal
+    You have: meters
+    You want: feet
+            * 3.2808399
+            / 0.3048
+
+    You have: cm^3
+    You want: gallons
+            * 0.00026417205
+            / 3785.4118
+.Ed
+.Pp
+Powers of units can be specified using the
+.Dq \&^
+character as shown in the example, or by simple concatenation:
+.Dq cm3
+is equivalent to
+.Dq cm^3 .
+Multiplication of units can be specified by using spaces, a dash or
+an asterisk.
+Division of units is indicated by the slash
+.Pq Sq \&/ .
+Note that multiplication has a higher precedence than division,
+so
+.Dq m/s/s
+is the same as
+.Dq m/s^2
+or
+.Dq "m/s s" .
+If the user enters incompatible unit types, the
+.Nm
+program will print a message indicating that the units are not
+conformable and it will display the reduced form for each unit:
+.Bd -literal
+    You have: ergs/hour
+    You want: fathoms kg^2 / day
+    conformability error
+            2.7777778e-11 kg m^2 / sec^3
+            2.1166667e-05 kg^2 m / sec
+.Ed
+.Pp
+The conversion information is read from a units data file.
+The default
+file includes definitions for most familiar units, abbreviations and
+metric prefixes.
+Some constants of nature included are:
+.Bl -tag -width mercury -compact -offset indent
+.It pi
+ratio of circumference to diameter
+.It c
+speed of light
+.It e
+charge on an electron
+.It g
+acceleration of gravity
+.It force
+same as g
+.It mole
+Avogadro's number
+.It water
+pressure per unit height of water
+.It mercury
+pressure per unit height of mercury
+.It au
+astronomical unit
+.El
+.Pp
+.Dq pound
+is a unit of mass.
+Compound names are run together
+so
+.Dq poundforce
+is a unit of force.
+British units that differ from their
+US counterparts are prefixed with
+.Dq br ,
+and currency is prefixed with
+its country name:
+.Dq belgiumfranc ,
+.Dq britainpound .
+When searching for
+a unit, if the specified string does not appear exactly as a unit
+name, then the
+.Nm
+program will try to remove a trailing
+.Dq s
+or a trailing
+.Dq es
+and check again for a match.
+.Pp
+All of these definitions can be read in the standard units file, or you
+can supply your own file.
+A unit is specified on a single line by
+giving its name and an equivalence.
+One should be careful to define
+new units in terms of old ones so that a reduction leads to the
+primitive units which are marked with
+.Sq \&!
+characters.
+.Nm
+will not detect infinite loops that could be caused
+by careless unit definitions.
+.Pp
+Prefixes are defined in the same way as standard units, but with
+a trailing dash at the end of the prefix name.
+.Sh FILES
+.Bl -tag -width /usr/share/misc/units.lib -compact
+.It Pa /usr/share/misc/units.lib
+the standard units library
+.El
+.Sh AUTHORS
+.An Adrian Mariano Aq Mt adrian@cam.cornell.edu
+or
+.Aq mariano@geom.umn.edu
+.Sh CAVEATS
+While
+.Nm
+can be used as a calculator for many unit-related computations,
+caution is required: many computations require additional constant
+factors deriving from the physics (or chemistry or whatever) of the
+situation.
+As these factors are dimensionless,
+.Nm
+cannot itself either provide them or warn the user when they have been
+forgotten.
+For example, one joule is one kilogram meter squared per second
+squared, by definition; however, the kinetic energy of a one-kilogram
+object moving at one meter per second is half a joule, not one joule,
+because of a dimensionless factor that arises from integration.
+.Pp
+Also, some pairs of units that have the same dimensionality are
+nonetheless used to measure different things and attempting to convert
+between them may require additional fudge factors or be entirely
+meaningless.
+For example, torque and energy have the same dimensionality, but
+attempting to convert torque in newton-meters to energy in joules is
+nonsensical.
+There is no practical way for
+.Nm
+to warn about these issues either.
+.Sh BUGS
+The effect of including a
+.Sq \&/
+in a prefix is surprising.
+.Pp
+Exponents entered by the user can be only one digit.
+You can work around this by multiplying several terms.
+.Pp
+The user must use
+.Sq \&|
+to indicate division of numbers and
+.Sq \&/
+to indicate division of symbols.
+This distinction should not be necessary.
+.Pp
+The program contains various arbitrary limits on the length
+of the units converted and on the length of the data file.
+.Pp
+The program should use a hash table to store units so that
+it doesn't take so long to load the units list and check
+for duplication.
diff --git a/usr.bin/units/units.c b/usr.bin/units/units.c
new file mode 100644 (file)
index 0000000..98dd243
--- /dev/null
@@ -0,0 +1,910 @@
+/*     $NetBSD: units.c,v 1.24 2013/01/06 00:19:13 wiz Exp $   */
+
+/*
+ * units.c   Copyright (c) 1993 by Adrian Mariano (adrian@cam.cornell.edu)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * Disclaimer:  This software is provided by the author "as is".  The author
+ * shall not be liable for any damages caused in any way by this software.
+ *
+ * I would appreciate (though I do not require) receiving a copy of any
+ * improvements you might make to this program.
+ */
+
+#include <ctype.h>
+#include <err.h>
+#include <float.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+#define VERSION "1.0"
+
+#ifndef UNITSFILE
+#define UNITSFILE _PATH_UNITSLIB
+#endif
+
+#define MAXUNITS 1000
+#define MAXPREFIXES 50
+
+#define MAXSUBUNITS 500
+
+#define PRIMITIVECHAR '!'
+
+static int precision = 8;              /* for printf with "%.*g" format */
+
+static const char *errprefix = NULL;   /* if not NULL, then prepend this
+                                        * to error messages and send them to
+                                        * stdout instead of stderr.
+                                        */
+
+static const char *powerstring = "^";
+
+static struct {
+       const char *uname;
+       const char *uval;
+}      unittable[MAXUNITS];
+
+struct unittype {
+       const char *numerator[MAXSUBUNITS];
+       const char *denominator[MAXSUBUNITS];
+       double factor;
+};
+
+struct {
+       const char *prefixname;
+       const char *prefixval;
+}      prefixtable[MAXPREFIXES];
+
+
+static const char *NULLUNIT = "";
+
+static int unitcount;
+static int prefixcount;
+
+
+static int     addsubunit(const char *[], const char *);
+static int     addunit(struct unittype *, const char *, int);
+static void    cancelunit(struct unittype *);
+static int     compare(const void *, const void *);
+static int     compareproducts(const char **, const char **);
+static int     compareunits(struct unittype *, struct unittype *);
+static int     compareunitsreciprocal(struct unittype *, struct unittype *);
+static int     completereduce(struct unittype *);
+static void    initializeunit(struct unittype *);
+static void    readerror(int);
+static void    readunits(const char *);
+static int     reduceproduct(struct unittype *, int);
+static int     reduceunit(struct unittype *);
+static void    showanswer(struct unittype *, struct unittype *);
+static void    showunit(struct unittype *);
+static void    sortunit(struct unittype *);
+__dead static void     usage(void);
+static void    zeroerror(void);
+static char   *dupstr(const char *);
+static const char *lookupunit(const char *);
+
+static char *
+dupstr(const char *str)
+{
+       char *ret;
+
+       ret = strdup(str);
+       if (!ret)
+               err(3, "Memory allocation error");
+       return (ret);
+}
+
+
+static void
+mywarnx(const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       if (errprefix) {
+               /* warn to stdout, with errprefix prepended */
+               printf("%s", errprefix);
+               vprintf(fmt, args);
+               printf("%s", "\n");
+       } else {
+               /* warn to stderr */
+               vwarnx(fmt, args);
+       }
+       va_end(args);
+}
+
+static void
+readerror(int linenum)
+{
+       mywarnx("Error in units file '%s' line %d", UNITSFILE, linenum);
+}
+
+
+static void
+readunits(const char *userfile)
+{
+       FILE *unitfile;
+       char line[80], *lineptr;
+       int len, linenum, i, isdup;
+
+       unitcount = 0;
+       linenum = 0;
+
+       if (userfile) {
+               unitfile = fopen(userfile, "rt");
+               if (!unitfile)
+                       err(1, "Unable to open units file '%s'", userfile);
+       }
+       else {
+               unitfile = fopen(UNITSFILE, "rt");
+               if (!unitfile) {
+                       char *direc, *env;
+                       char filename[1000];
+                       char separator[2];
+
+                       env = getenv("PATH");
+                       if (env) {
+                               if (strchr(env, ';'))
+                                       strlcpy(separator, ";",
+                                           sizeof(separator));
+                               else
+                                       strlcpy(separator, ":",
+                                           sizeof(separator));
+                               direc = strtok(env, separator);
+                               while (direc) {
+                                       strlcpy(filename, "", sizeof(filename));
+                                       strlcat(filename, direc,
+                                           sizeof(filename));
+                                       strlcat(filename, "/",
+                                           sizeof(filename));
+                                       strlcat(filename, UNITSFILE,
+                                           sizeof(filename));
+                                       unitfile = fopen(filename, "rt");
+                                       if (unitfile)
+                                               break;
+                                       direc = strtok(NULL, separator);
+                               }
+                       }
+                       if (!unitfile)
+                               errx(1, "Can't find units file '%s'",
+                                   UNITSFILE);
+               }
+       }
+       while (!feof(unitfile)) {
+               if (!fgets(line, 79, unitfile))
+                       break;
+               linenum++;
+               lineptr = line;
+               if (*lineptr == '/')
+                       continue;
+               lineptr += strspn(lineptr, " \n\t");
+               len = strcspn(lineptr, " \n\t");
+               lineptr[len] = 0;
+               if (!strlen(lineptr))
+                       continue;
+               if (lineptr[strlen(lineptr) - 1] == '-') { /* it's a prefix */
+                       if (prefixcount == MAXPREFIXES) {
+                               mywarnx(
+                       "Memory for prefixes exceeded in line %d",
+                                       linenum);
+                               continue;
+                       }
+                       lineptr[strlen(lineptr) - 1] = 0;
+                       for (isdup = 0, i = 0; i < prefixcount; i++) {
+                               if (!strcmp(prefixtable[i].prefixname,
+                                   lineptr)) {
+                                       isdup = 1;
+                                       break;
+                               }
+                       }
+                       if (isdup) {
+                               mywarnx(
+                       "Redefinition of prefix '%s' on line %d ignored",
+                                   lineptr, linenum);
+                               continue;
+                       }
+                       prefixtable[prefixcount].prefixname = dupstr(lineptr);
+                       lineptr += len + 1;
+                       if (!strlen(lineptr)) {
+                               readerror(linenum);
+                               continue;
+                       }
+                       lineptr += strspn(lineptr, " \n\t");
+                       len = strcspn(lineptr, "\n\t");
+                       lineptr[len] = 0;
+                       prefixtable[prefixcount++].prefixval = dupstr(lineptr);
+               }
+               else {          /* it's not a prefix */
+                       if (unitcount == MAXUNITS) {
+                               mywarnx("Memory for units exceeded in line %d",
+                                   linenum);
+                               continue;
+                       }
+                       for (isdup = 0, i = 0; i < unitcount; i++) {
+                               if (!strcmp(unittable[i].uname, lineptr)) {
+                                       isdup = 1;
+                                       break;
+                               }
+                       }
+                       if (isdup) {
+                               mywarnx(
+                               "Redefinition of unit '%s' on line %d ignored",
+                                   lineptr, linenum);
+                               continue;
+                       }
+                       unittable[unitcount].uname = dupstr(lineptr);
+                       lineptr += len + 1;
+                       lineptr += strspn(lineptr, " \n\t");
+                       if (!strlen(lineptr)) {
+                               readerror(linenum);
+                               continue;
+                       }
+                       len = strcspn(lineptr, "\n\t");
+                       lineptr[len] = 0;
+                       unittable[unitcount++].uval = dupstr(lineptr);
+               }
+       }
+       fclose(unitfile);
+}
+
+static void
+initializeunit(struct unittype * theunit)
+{
+       theunit->factor = 1.0;
+       theunit->numerator[0] = theunit->denominator[0] = NULL;
+}
+
+static int
+addsubunit(const char *product[], const char *toadd)
+{
+       const char **ptr;
+
+       for (ptr = product; *ptr && *ptr != NULLUNIT; ptr++);
+       if (ptr >= product + MAXSUBUNITS) {
+               mywarnx("Memory overflow in unit reduction");
+               return 1;
+       }
+       if (!*ptr)
+               *(ptr + 1) = 0;
+       *ptr = dupstr(toadd);
+       return 0;
+}
+
+static void
+showunit(struct unittype * theunit)
+{
+       const char **ptr;
+       int printedslash;
+       int counter = 1;
+
+       printf("\t%.*g", precision, theunit->factor);
+       for (ptr = theunit->numerator; *ptr; ptr++) {
+               if (ptr > theunit->numerator && **ptr &&
+                   !strcmp(*ptr, *(ptr - 1)))
+                       counter++;
+               else {
+                       if (counter > 1)
+                               printf("%s%d", powerstring, counter);
+                       if (**ptr)
+                               printf(" %s", *ptr);
+                       counter = 1;
+               }
+       }
+       if (counter > 1)
+               printf("%s%d", powerstring, counter);
+       counter = 1;
+       printedslash = 0;
+       for (ptr = theunit->denominator; *ptr; ptr++) {
+               if (ptr > theunit->denominator && **ptr &&
+                   !strcmp(*ptr, *(ptr - 1)))
+                       counter++;
+               else {
+                       if (counter > 1)
+                               printf("%s%d", powerstring, counter);
+                       if (**ptr) {
+                               if (!printedslash)
+                                       printf(" /");
+                               printedslash = 1;
+                               printf(" %s", *ptr);
+                       }
+                       counter = 1;
+               }
+       }
+       if (counter > 1)
+               printf("%s%d", powerstring, counter);
+       printf("\n");
+}
+
+static void
+zeroerror(void)
+{
+       mywarnx("Unit reduces to zero");
+}
+
+/*
+   Adds the specified string to the unit.
+   Flip is 0 for adding normally, 1 for adding reciprocal.
+
+   Returns 0 for successful addition, nonzero on error.
+*/
+
+static int
+addunit(struct unittype * theunit, const char *toadd, int flip)
+{
+       char *scratch, *savescr;
+       char *item;
+       char *divider, *slash;
+       int doingtop;
+
+       savescr = scratch = dupstr(toadd);
+       for (slash = scratch + 1; *slash; slash++)
+               if (*slash == '-' &&
+                   (tolower((unsigned char)*(slash - 1)) != 'e' ||
+                   !strchr(".0123456789", *(slash + 1))))
+                       *slash = ' ';
+       slash = strchr(scratch, '/');
+       if (slash)
+               *slash = 0;
+       doingtop = 1;
+       do {
+               item = strtok(scratch, " *\t\n/");
+               while (item) {
+                       if (strchr("0123456789.", *item)) {
+                               /* item starts with a number */
+                               char *endptr;
+                               double num;
+
+                               divider = strchr(item, '|');
+                               if (divider) {
+                                       *divider = 0;
+                                       num = strtod(item, &endptr);
+                                       if (!num) {
+                                               zeroerror();
+                                               return 1;
+                                       }
+                                       if (endptr != divider) {
+                                               /* "6foo|2" is an error */
+                                               mywarnx("Junk before '|'");
+                                               return 1;
+                                       }
+                                       if (doingtop ^ flip)
+                                               theunit->factor *= num;
+                                       else
+                                               theunit->factor /= num;
+                                       num = strtod(divider + 1, &endptr);
+                                       if (!num) {
+                                               zeroerror();
+                                               return 1;
+                                       }
+                                       if (doingtop ^ flip)
+                                               theunit->factor /= num;
+                                       else
+                                               theunit->factor *= num;
+                                       if (*endptr) {
+                                               /* "6|2foo" is like "6|2 foo" */
+                                               item = endptr;
+                                               continue;
+                                       }
+                               }
+                               else {
+                                       num = strtod(item, &endptr);
+                                       if (!num) {
+                                               zeroerror();
+                                               return 1;
+                                       }
+                                       if (doingtop ^ flip)
+                                               theunit->factor *= num;
+                                       else
+                                               theunit->factor /= num;
+                                       if (*endptr) {
+                                               /* "3foo" is like "3 foo" */
+                                               item = endptr;
+                                               continue;
+                                       }
+                               }
+                       }
+                       else {  /* item is not a number */
+                               int repeat = 1;
+
+                               if (strchr("23456789",
+                                   item[strlen(item) - 1])) {
+                                       repeat = item[strlen(item) - 1] - '0';
+                                       item[strlen(item) - 1] = 0;
+                               }
+                               for (; repeat; repeat--)
+                                       if (addsubunit(doingtop ^ flip ? theunit->numerator : theunit->denominator, item))
+                                               return 1;
+                       }
+                       item = strtok(NULL, " *\t/\n");
+               }
+               doingtop--;
+               if (slash) {
+                       scratch = slash + 1;
+               }
+               else
+                       doingtop--;
+       } while (doingtop >= 0);
+       free(savescr);
+       return 0;
+}
+
+static int
+compare(const void *item1, const void *item2)
+{
+       return strcmp(*(const char * const *) item1,
+                     *(const char * const *) item2);
+}
+
+static void
+sortunit(struct unittype * theunit)
+{
+       const char **ptr;
+       int count;
+
+       for (count = 0, ptr = theunit->numerator; *ptr; ptr++, count++);
+       qsort(theunit->numerator, count, sizeof(char *), compare);
+       for (count = 0, ptr = theunit->denominator; *ptr; ptr++, count++);
+       qsort(theunit->denominator, count, sizeof(char *), compare);
+}
+
+static void
+cancelunit(struct unittype * theunit)
+{
+       const char **den, **num;
+       int comp;
+
+       den = theunit->denominator;
+       num = theunit->numerator;
+
+       while (*num && *den) {
+               comp = strcmp(*den, *num);
+               if (!comp) {
+/*      if (*den!=NULLUNIT) free(*den);
+      if (*num!=NULLUNIT) free(*num);*/
+                       *den++ = NULLUNIT;
+                       *num++ = NULLUNIT;
+               }
+               else if (comp < 0)
+                       den++;
+               else
+                       num++;
+       }
+}
+
+
+
+
+/*
+   Looks up the definition for the specified unit.
+   Returns a pointer to the definition or a null pointer
+   if the specified unit does not appear in the units table.
+*/
+
+static char buffer[100];       /* buffer for lookupunit answers with
+                                  prefixes */
+
+static const char *
+lookupunit(const char *unit)
+{
+       int i;
+       char *copy;
+
+       for (i = 0; i < unitcount; i++) {
+               if (!strcmp(unittable[i].uname, unit))
+                       return unittable[i].uval;
+       }
+
+       if (unit[strlen(unit) - 1] == '^') {
+               copy = dupstr(unit);
+               copy[strlen(copy) - 1] = 0;
+               for (i = 0; i < unitcount; i++) {
+                       if (!strcmp(unittable[i].uname, copy)) {
+                               strlcpy(buffer, copy, sizeof(buffer));
+                               free(copy);
+                               return buffer;
+                       }
+               }
+               free(copy);
+       }
+       if (unit[strlen(unit) - 1] == 's') {
+               copy = dupstr(unit);
+               copy[strlen(copy) - 1] = 0;
+               for (i = 0; i < unitcount; i++) {
+                       if (!strcmp(unittable[i].uname, copy)) {
+                               strlcpy(buffer, copy, sizeof(buffer));
+                               free(copy);
+                               return buffer;
+                       }
+               }
+               if (copy[strlen(copy) - 1] == 'e') {
+                       copy[strlen(copy) - 1] = 0;
+                       for (i = 0; i < unitcount; i++) {
+                               if (!strcmp(unittable[i].uname, copy)) {
+                                       strlcpy(buffer, copy, sizeof(buffer));
+                                       free(copy);
+                                       return buffer;
+                               }
+                       }
+               }
+               free(copy);
+       }
+       for (i = 0; i < prefixcount; i++) {
+               if (!strncmp(prefixtable[i].prefixname, unit,
+                       strlen(prefixtable[i].prefixname))) {
+                       unit += strlen(prefixtable[i].prefixname);
+                       if (!strlen(unit) || lookupunit(unit)) {
+                               strlcpy(buffer, prefixtable[i].prefixval,
+                                   sizeof(buffer));
+                               strlcat(buffer, " ", sizeof(buffer));
+                               strlcat(buffer, unit, sizeof(buffer));
+                               return buffer;
+                       }
+               }
+       }
+       return 0;
+}
+
+
+
+/*
+   reduces a product of symbolic units to primitive units.
+   The three low bits are used to return flags:
+
+     bit 0 (1) set on if reductions were performed without error.
+     bit 1 (2) set on if no reductions are performed.
+     bit 2 (4) set on if an unknown unit is discovered.
+*/
+
+
+#define ERROR 4
+
+static int
+reduceproduct(struct unittype * theunit, int flip)
+{
+
+       const char *toadd;
+       const char **product;
+       int didsomething = 2;
+
+       if (flip)
+               product = theunit->denominator;
+       else
+               product = theunit->numerator;
+
+       for (; *product; product++) {
+
+               for (;;) {
+                       if (!strlen(*product))
+                               break;
+                       toadd = lookupunit(*product);
+                       if (!toadd) {
+                               mywarnx("Unknown unit '%s'", *product);
+                               return ERROR;
+                       }
+                       if (strchr(toadd, PRIMITIVECHAR))
+                               break;
+                       didsomething = 1;
+                       if (*product != NULLUNIT) {
+                               free(__UNCONST(*product));
+                               *product = NULLUNIT;
+                       }
+                       if (addunit(theunit, toadd, flip))
+                               return ERROR;
+               }
+       }
+       return didsomething;
+}
+
+
+/*
+   Reduces numerator and denominator of the specified unit.
+   Returns 0 on success, or 1 on unknown unit error.
+*/
+
+static int
+reduceunit(struct unittype * theunit)
+{
+       int ret;
+
+       ret = 1;
+       while (ret & 1) {
+               ret = reduceproduct(theunit, 0) | reduceproduct(theunit, 1);
+               if (ret & 4)
+                       return 1;
+       }
+       return 0;
+}
+
+static int
+compareproducts(const char **one, const char **two)
+{
+       while (*one || *two) {
+               if (!*one && *two != NULLUNIT)
+                       return 1;
+               if (!*two && *one != NULLUNIT)
+                       return 1;
+               if (*one == NULLUNIT)
+                       one++;
+               else if (*two == NULLUNIT)
+                       two++;
+               else if (*one && *two && strcmp(*one, *two))
+                       return 1;
+               else
+                       one++, two++;
+       }
+       return 0;
+}
+
+
+/* Return zero if units are compatible, nonzero otherwise */
+
+static int
+compareunits(struct unittype * first, struct unittype * second)
+{
+       return
+       compareproducts(first->numerator, second->numerator) ||
+       compareproducts(first->denominator, second->denominator);
+}
+
+static int
+compareunitsreciprocal(struct unittype * first, struct unittype * second)
+{
+       return
+       compareproducts(first->numerator, second->denominator) ||
+       compareproducts(first->denominator, second->numerator);
+}
+
+
+static int
+completereduce(struct unittype * unit)
+{
+       if (reduceunit(unit))
+               return 1;
+       sortunit(unit);
+       cancelunit(unit);
+       return 0;
+}
+
+
+static void
+showanswer(struct unittype * have, struct unittype * want)
+{
+       if (compareunits(have, want)) {
+               if (compareunitsreciprocal(have, want)) {
+                       printf("conformability error\n");
+                       showunit(have);
+                       showunit(want);
+               } else {
+                       printf("\treciprocal conversion\n");
+                       printf("\t* %.*g\n\t/ %.*g\n",
+                           precision, 1 / (have->factor * want->factor),
+                           precision, want->factor * have->factor);
+               }
+       }
+       else
+               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;
+       int printexpansion;
+
+       /*
+        * send error and warning messages to stdout,
+        * and make them look like comments.
+        */
+       errprefix = "/ ";
+
+#if 0 /* debug */
+       printf("/ expand=%d precision=%d unitcount=%d prefixcount=%d\n",
+           expand, precision, unitcount, prefixcount);
+#endif
+
+       /* 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++) {
+               printexpansion = expand;
+               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++;
+                               printexpansion = 0;
+                               mywarnx("Error in prefix '%s-'", thename);
+                       }
+               }
+               if (printexpansion) {
+                       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++) {
+               printexpansion = expand;
+               thename = unittable[i].uname;
+               thedefn = unittable[i].uval;
+               if (thedefn[0] == PRIMITIVECHAR)
+                       continue;
+               if (expand) {
+                       /*
+                        * expand thename, not thedefn, so that
+                        * we can catch errors in the name itself.
+                        * e.g. a name that contains a hyphen
+                        * will be interpreted as multiplication.
+                        */
+                       initializeunit(&theunit);
+                       if (addunit(&theunit, thename, 0) != 0
+                           || completereduce(&theunit) != 0) {
+                               errors++;
+                               printexpansion = 0;
+                               mywarnx("Error in unit '%s'", thename);
+                       }
+               }
+               if (printexpansion) {
+                       printf("%s", thename);
+                       showunit(&theunit);
+               } else
+                       printf("%s\t%s\n", thename, thedefn);
+       }
+
+       if (errors)
+               mywarnx("Definitions with errors: %d", errors);
+       return (errors ? 1 : 0);
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr,
+           "\nunits [-Llqv] [-f filename] [[count] from-unit to-unit]\n");
+       fprintf(stderr, "\n    -f specify units file\n");
+       fprintf(stderr, "    -L list units in standardized base units\n");
+       fprintf(stderr, "    -l list units\n");
+       fprintf(stderr, "    -q suppress prompting (quiet)\n");
+       fprintf(stderr, "    -v print version number\n");
+       exit(3);
+}
+
+int
+main(int argc, char **argv)
+{
+
+       struct unittype have, want;
+       char havestr[81], wantstr[81];
+       int optchar;
+       const char *userfile = 0;
+       int list = 0, listexpand = 0;
+       int quiet = 0;
+
+       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;
+               case 'q':
+                       quiet = 1;
+                       break;
+               case 'v':
+                       fprintf(stderr, "\n  units version %s  Copyright (c) 1993 by Adrian Mariano\n",
+                           VERSION);
+                       fprintf(stderr, "                    This program may be freely distributed\n");
+                       usage();
+               default:
+                       usage();
+                       break;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if ((argc != 3 && argc != 2 && argc != 0)
+           || (list && argc != 0))
+               usage();
+
+       if (list)
+               errprefix = "/ ";       /* set this before reading the file */
+
+       readunits(userfile);
+
+       if (list)
+               return listunits(listexpand);
+
+       if (argc == 3) {
+               strlcpy(havestr, argv[0], sizeof(havestr));
+               strlcat(havestr, " ", sizeof(havestr));
+               strlcat(havestr, argv[1], sizeof(havestr));
+               argc--;
+               argv++;
+               argv[0] = havestr;
+       }
+
+       if (argc == 2) {
+               strlcpy(havestr, argv[0], sizeof(havestr));
+               strlcpy(wantstr, argv[1], sizeof(wantstr));
+               initializeunit(&have);
+               addunit(&have, havestr, 0);
+               completereduce(&have);
+               initializeunit(&want);
+               addunit(&want, wantstr, 0);
+               completereduce(&want);
+               showanswer(&have, &want);
+       }
+       else {
+               if (!quiet)
+                       printf("%d units, %d prefixes\n\n", unitcount,
+                           prefixcount);
+               for (;;) {
+                       do {
+                               initializeunit(&have);
+                               if (!quiet)
+                                       printf("You have: ");
+                               if (!fgets(havestr, 80, stdin)) {
+                                       if (!quiet)
+                                               putchar('\n');
+                                       exit(0);
+                               }
+                       } while (addunit(&have, havestr, 0) ||
+                           completereduce(&have));
+                       do {
+                               initializeunit(&want);
+                               if (!quiet)
+                                       printf("You want: ");
+                               if (!fgets(wantstr, 80, stdin)) {
+                                       if (!quiet)
+                                               putchar('\n');
+                                       exit(0);
+                               }
+                       } while (addunit(&want, wantstr, 0) ||
+                           completereduce(&want));
+                       showanswer(&have, &want);
+               }
+       }
+       return (0);
+}
diff --git a/usr.bin/units/units.lib b/usr.bin/units/units.lib
new file mode 100644 (file)
index 0000000..81763f6
--- /dev/null
@@ -0,0 +1,651 @@
+/      $NetBSD: units.lib,v 1.17 2012/12/28 17:57:46 apb Exp $
+
+/ primitive units
+
+m                      !a!
+kg                     !b!
+sec                    !c!
+coul                   !d!
+candela                        !e!
+dollar                 !f!
+bit                    !h!
+erlang                 !i!
+K                      !j!
+
+/ prefixes
+
+yotta-                 1e24
+zetta-                 1e21
+exa-                   1e18
+peta-                  1e15
+tera-                  1e12
+giga-                  1e9
+mega-                  1e6
+myria-                 1e4
+kilo-                  1e3
+hecto-                 1e2
+deka-                  1e1
+deci-                  1e-1
+centi-                 1e-2
+milli-                 1e-3
+micro-                 1e-6
+nano-                  1e-9
+pico-                  1e-12
+femto-                 1e-15
+atto-                  1e-18
+zopto-                 1e-21
+yocto-                 1e-24
+
+semi-                  .5
+demi-                  .5
+
+Y-                     yotta
+Z-                     zetta
+E-                     exa
+P-                     peta
+T-                     tera
+G-                     giga
+M-                     mega
+k-                     kilo
+h-                     hecto
+da-                    deka
+d-                     deci
+c-                     centi
+m-                     milli
+p-                     pico
+f-                     femto
+a-                     atto
+z-                     zopto
+y-                     yocto
+
+/ constants
+
+fuzz                   1
+pi                     3.14159265358979323846
+c                      2.99792458e+8 m/sec fuzz
+g                      9.80665 m/sec2
+au                     1.49597871e+11 m fuzz
+mole                   6.022169e+23 fuzz
+e                      1.6021917e-19 coul fuzz
+energy                 c2
+force                  g
+mercury                        1.33322e+5 kg/m2-sec2
+hg                     mercury
+
+/ dimensionless
+
+radian                 .5 / pi
+degree                 1|180 pi-radian
+circle                 2 pi-radian
+turn                   2 pi-radian
+revolution                     turn
+rev                    turn
+grade                  .9 degree
+arcdeg                 1 degree
+arcmin                 1|60 arcdeg
+ccs                    1|36 erlang
+arcsec                 1|60 arcmin
+
+steradian              radian2
+sphere                 4 pi-steradian
+sr                     steradian
+
+/ Time
+
+second                 sec
+s                      sec
+minute                 60 sec
+min                    minute
+hour                   60 min
+hr                     hour
+day                    24 hr
+da                     day
+week                   7 day
+year                   365.24219879 day fuzz
+yr                     year
+month                  1|12 year
+ms                     millisec
+us                     microsec
+
+/ Mass
+
+gram                   millikg
+gm                     gram
+mg                     milligram
+metricton              kilokg
+
+/ Avoirdupois
+
+lb                     .45359237 kg
+pound                  lb
+lbf                    lb g
+ounce                  1|16 lb
+oz                     ounce
+dram                   1|16 oz
+dr                     dram
+grain                  1|7000 lb
+gr                     grain
+shortton               2000 lb
+ton                    shortton
+longton                        2240 lb
+
+/ Apothecary
+
+scruple                        20 grain
+apdram                 60 grain
+apounce                        480 grain
+appound                        5760 grain
+troypound              appound
+
+/ Length
+
+meter                  m
+cm                     centimeter
+mm                     millimeter
+km                     kilometer
+nm                     nanometer
+micron                 micrometer
+angstrom               decinanometer
+
+inch                   2.54 cm
+in                     inch
+foot                   12 in
+feet                   foot
+ft                     foot
+yard                   3 ft
+yd                     yard
+rod                    5.5 yd
+rd                     rod
+mile                   5280 ft
+mi                     mile
+
+british                        1200|3937 m/ft
+nmile                  1852 m
+
+acre                   4840 yd2
+
+cc                     cm3
+liter                  kilocc
+ml                     milliliter
+
+/ US Liquid
+
+gallon                 231 in3
+imperial               1.20095
+gal                    gallon
+quart                  1|4 gal
+qt                     quart
+pint                   1|2 qt
+pt                     pint
+
+floz                   1|16 pt
+fldr                   1|8 floz
+
+/ US Dry
+
+dry                    268.8025 in3/gallon fuzz
+peck                   8 dry-quart
+pk                     peck
+bushel                 4 peck
+bu                     bushel
+chaldron               36 bushel
+
+/ British
+
+brgallon               277.420 in3 fuzz
+brquart                        1|4 brgallon
+brpint                 1|2 brquart
+brfloz                 1|20 brpint
+brpeck                 554.84 in3 fuzz
+brbushel               4 brpeck
+
+/ Bottles
+
+bottle                 750 milliliter
+/bottle                        fifth
+
+miniature              100 milliliter
+split                  1|4 bottle
+half                   1|2 bottle
+magnum                 2 bottle
+jeroboam               4 bottle
+rehoboam               6 bottle
+methuselah             8 bottle
+salmanazar             12 bottle
+balthazar              16 bottle
+nebuchadnezzar         20 bottle
+sovereign              34 bottle
+
+/ Bottles - alternate names and spellings
+
+pony                   split
+fillette               half
+tappithen              3 bottle
+rheoboam               rehoboam
+shalmaneser            salmanazar
+
+/ Energy Work
+
+newton                 kg-m/sec2
+nt                     newton
+N                      newton
+joule                  nt-m
+cal                    4.1868 joule
+
+/ Electrical
+
+coulomb                        coul
+C                      coul
+ampere                 coul/sec
+amp                    ampere
+watt                   joule/sec
+volt                   watt/amp
+ohm                    volt/amp
+mho                    /ohm
+farad                  coul/volt
+henry                  sec2/farad
+weber                  volt-sec
+
+/ Light
+
+cd                     candela
+lumen                  cd sr
+lux                    cd sr/m2
+
+/ Wall Street Journal, July 2, 1993
+
+$                      dollar
+argentinapeso          $
+australiadollar                .66 $
+bahraindinar           2.6522 $
+brazilcruzeiro         .000019 $
+britainpound           1.49 $
+canadadollar           .77 $
+czechkoruna            .034 $
+chilepeso              .0025 $
+chinarenminbi          .174856 $
+colombiapeso           .001495 $
+denmarkkrone           .15 $
+ecuadorsucre           .000539 $
+europeeuro             0.9142 $
+greatbritainpound      britainpound
+hongkongdollar         .13  $
+hungaryforint          .011 $
+indiarupee             .03211 $
+indonesiarupiah                .0004782 $
+israelshekel           .3642 $
+japanyen               .0093 $
+jordandinar            1.4682 $
+kuwaitdinar            3.3173 $
+lebanonpound           .000578 $
+malaysiaringgit                .338 $
+maltalira              2.6042 $
+mexicopeso             .3205128 $
+newzealanddollar       .539 $
+norwaykrone            .139 $
+pakistanrupee          .037 $
+perunewsol             .5065 $
+philippinespeso                .03738 $
+polandzloty            .000059 $
+saudiarabiariyal       .26702 $
+singaporedollar                .6157 $
+slovakkoruna           .034 $
+southafricarand                .21 $
+southkoreawon          .001 $
+swedenkrona            .13 $
+switzerlandfranc       .66 $
+taiwandollar           .038285 $
+thailandbaht           .03962 $
+turkeylira             .0000929 $
+unitedarabdirham       .2723 $
+uruguaynewpeso         .246852 $
+venezuelabolivar       .011 $
+
+/ The following currencies are locked to the Euro:
+/ <URL:http://www.ecb.int/change/conversion.htm>
+belgiumfranc           1|40.3399 euro
+germanymark            1|1.95583 euro
+spainpeseta            1|166.386 euro
+francefranc            1|6.55957 euro
+irelandpunt            1|.787564 euro
+italylira              1|1936.27 euro
+luxembourgfranc                1|40.3399 euro
+netherlandsguilder     1|2.20371 euro
+austriaschilling       1|13.7603 euro
+portugalescudo         1|200.482 euro
+finlandmarkka          1|5.94573 euro
+greecedrachma          1|340.750 euro
+
+mark                   germanymark
+euro                   europeeuro
+bolivar                        venezuelabolivar
+peseta                 spainpeseta
+rand                   southafricarand
+escudo                 portugalescudo
+newsol                 perunewsol
+guilder                        netherlandsguilder
+hollandguilder         netherlandsguilder
+peso                   mexicopeso
+yen                    japanyen
+lira                   italylira
+rupee                  indiarupee
+drachma                        greecedrachma
+franc                  francefranc
+markka                 finlandmarkka
+sucre                  ecuadorsucre
+poundsterling          britainpound
+cruzeiro               brazilcruzeiro
+
+/ computer
+
+baud                   bit/sec
+byte                   8 bit
+block                  512 byte
+kbyte                  1024 byte
+megabyte               1024 kbyte
+gigabyte               1024 megabyte
+meg                    megabyte
+
+
+/ Trivia
+
+%                      1|100
+admiraltyknot          6080 ft/hr
+apostilb               cd/pi-m2
+are                    1e+2 m2
+arpentcan              27.52 mi
+arpentlin              191.835 ft
+astronomicalunit       au
+atmosphere             1.01325e+5 nt/m2
+atm                    atmosphere
+atomicmassunit         1.66044e-27 kg fuzz
+amu                    atomicmassunit
+bag                    94 lb
+bakersdozen            13
+bar                    1e+5 nt/m2
+barie                  1e-1 nt/m2
+barleycorn             1|3 in
+barn                   1e-28 m2
+barrel                 42 gal
+barye                  1e-1 nt/m2
+bev                    1e+9 e-volt
+biot                   10 amp
+blondel                        cd/pi-m2
+boardfoot              144 in3
+bolt                   40 yd
+bottommeasure          1|40 in
+britishthermalunit     1.05506e+3 joule fuzz
+btu                    britishthermalunit
+refrigeration          12000 btu/ton-hour
+buck                   dollar
+Ci                     curie
+cable                  720 ft
+caliber                        1e-2 in
+calorie                        cal
+carat                  205 mg
+caratgold              1|24
+cent                   centidollar
+cental                 100 lb
+centesimalminute       1e-2 grade
+centesimalsecond       1e-4 grade
+century                        100 year
+cfs                    ft3/sec
+chain                  66 ft
+circularinch           1|4 pi-in2
+circularmil            1e-6|4 pi-in2
+clusec                 1e-8 mm-hg m3/s
+coomb                  4 bu
+cord                   128 ft3
+cordfoot               cord
+crith                  9.06e-2 gm
+cubit                  18 in
+cup                    1|2 pt
+curie                  3.7e+10 /sec
+dalton                 amu
+decade                 10 yr
+diopter                        /m
+displacementton                35 ft3
+doppelzentner          100 kg
+dozen                  12
+drop                   .03 cm3
+dyne                   cm-gm/sec2
+electronvolt           e-volt
+ell                    45 in
+engineerschain         100 ft
+engineerslink          100|100 ft
+equivalentfootcandle   lumen/pi-ft2
+equivalentlux          lumen/pi-m2
+equivalentphot         cd/pi-cm2
+erg                    cm2-gm/sec2
+ev                     e-volt
+faraday                        9.652e+4 coul
+fathom                 6 ft
+fermi                  1e-15 m
+fifth                  4|5 qt
+fin                    5 dollar
+finger                 7|8 in
+firkin                 9 gal
+footcandle             lumen/ft2
+footlambert            cd/pi-ft2
+fortnight              14 da
+franklin               3.33564e-10 coul
+frigorie               kilocal
+furlong                        220 yd
+Gy                     gray
+galileo                        1e-2 m/sec2
+gamma                  1e-9 weber/m2
+gauss                  1e-4 weber/m2
+geodeticfoot           british-ft
+geographicalmile       1852 m
+gilbert                        7.95775e-1 amp
+gill                   1|4 pt
+gray                   joule/kg
+gross                  144
+gunterschain           22 yd
+hand                   4 in
+hectare                        1e+4 m2
+hefnercandle           .92 cd
+hertz                  /sec
+Hz                     hertz
+hogshead               63 gallon
+hd                     hogshead
+homestead              1|4 mi2
+horsepower             550 ft-lb-g/sec
+hp                     horsepower
+hyl                    gm force sec2/m
+hz                     /sec
+imaginarycubicfoot     1.4 ft3
+karat                  1|24
+kcal                   kilocal
+kcalorie               kilocal
+kev                    1e+3 e-volt
+key                    kg
+khz                    1e+3 /sec
+kilderkin              18 gal
+knot                   nmile/hr
+lambert                        cd/pi-cm2
+langley                        cal/cm2
+last                   80 bu
+league                 3 mi
+lightyear              c-yr
+line                   1|12 in
+link                   66|100 ft
+longhundredweight      112 lb
+longquarter            28 lb
+lusec                  1e-6 mm-hg m3/s
+mach                   331.46 m/sec
+marineleague           3 nmile
+maxwell                        1e-8 weber
+metriccarat            200 mg
+mgd                    megagal/day
+mh                     millihenry
+mhz                    1e+6 /sec
+mil                    1e-3 in
+millennium             1000 year
+minersinch             1.5 ft3/min
+minim                  1|60 fldr
+mo                     month
+mpg                    mile/gal
+mph                    mile/hr
+nail                   1|16 yd
+nauticalmile           nmile
+nit                    cd/m2
+noggin                 1|8 qt
+nox                    1e-3 lux
+ns                     nanosec
+oersted                        2.5e+2 pi-amp/m
+oe                     oersted
+pace                   36 in
+palm                   3 in
+parasang               3.5 mi
+parsec                 au-radian/arcsec
+pascal                 nt/m2
+pc                     parsec
+pennyweight            1|20 oz
+pwt                    pennyweight
+percent                        %
+perch                  rd
+pf                     picofarad
+phot                   lumen/cm2
+pica                   1|6 in
+pieze                  1e+3 nt/m2
+pipe                   4 barrel
+point                  1|72 in
+poise                  gm/cm-sec
+pole                   rd
+poundal                        ft-lb/sec2
+pdl                    poundal
+proof                  1|200
+psi                    lb-g/in2
+quarter                        9 in
+quartersection         1|4 mi2
+quintal                        100 kg
+quire                  25
+R                      roentgen
+rackunit               1.75 in
+rad                    100 erg/gm
+ream                   500
+registerton            100 ft3
+rem                    1e-2 sievert
+rhe                    10 m2/nt-sec
+roentgen               2.58e-4 coulomb/kg
+rontgen                        roentgen
+rood                   1.21e+3 yd
+rope                   20 ft
+RU                     rackunit
+rutherford             1e+6 /sec
+rydberg                        1.36054e+1 ev
+Sv                     sievert
+sabin                  1 ft2
+sack                   3 bu
+score                  20
+seam                   8 bu
+section                        mi2
+shed                   1e-24 barn
+shippington            40 ft3
+shorthundredweight     100 lb
+shortquarter           25 lb
+siemens                        /ohm
+sievert                        joule/kg
+sigma                  microsec
+skein                  120 yd
+skot                   1e-3 apostilb
+slug                   lb-g-sec2/ft
+smoot                  67 in
+span                   9 in
+spat                   4 pi sr
+spindle                        14400 yd
+square                 100 ft2
+stere                  m3
+sthene                 1e+3 nt
+stilb                  cd/cm2
+stoke                  1e-4 m2/sec
+stone                  14 lb
+strike                 2 bu
+surveyfoot             british-ft
+surveyyard             3 surveyfoot
+surveyorschain         66 ft
+surveyorslink          66|100 ft
+tablespoon             4 fldr
+teaspoon               4|3 fldr
+tesla                  weber/m2
+therm                  1e+5 btu
+thermie                        1e+6 cal
+timberfoot             ft3
+tnt                    4.6e+6 m2/sec2
+tonne                  1e+6 gm
+torr                   mm hg
+township               36 mi2
+tun                    8 barrel
+U                      rackunit
+water                  gram g / cc
+wey                    40 bu
+weymass                        252 lb
+Xunit                  1.00202e-13 m
+k                      1.38047e-16 erg/degC
+
+
+degC                   K
+kelvin                 K
+brewster               1e-12 m2/newton
+degF                   5|9 degC
+degreesrankine         degF
+degrankine             degreesrankine
+degreerankine          degF
+degreaumur             10|8 degC
+drachm                 60 grain
+poncelet               100 kg m g / sec
+denier                 .05|450 gram / m
+tex                    .001 gram / m
+englishell             45 inch
+scottishell            37.2 inch
+flemishell             27 inch
+planck                 6.626e-34 joule-sec
+hbar                   1.055e-34 joule-sec
+electronmass           9.1095e-31 kg
+protonmass             1.6726e-27 kg
+neutronmass            1.6606e-27 kg
+V                      volt
+eV                     e V
+bohrradius             hbar2-C2/8.988e9 N m2-e2-electronmass
+becquerel              1|3.7e10 curie
+fresnel                        1e12 hertz
+statcoul               1|2.99792458e9 coul
+statamp                        1|2.99792458e9 amp
+statvolt               2.99792458e2 volt
+statcoulomb            statcoul
+statampere             statamp
+debye                  3.336e-30 coul-m
+pulsatance             2 pi/sec
+rpm                    rev/minute
+rps                    rev/sec
+kilohm                 kiloohm
+megohm                 megaohm
+siderealyear           365.256360417 day
+siderealday            23.934469444 hour
+siderealhour           1|24 siderealday
+lunarmonth             29.5305555 day
+synodicmonth           lunarmonth
+siderealmonth          27.32152777 day
+tropicalyear           year
+solaryear              year
+lunaryear              12 lunarmonth
+cran                   37.5 brgallon
+kip                    1000 lbf
+frenchfoot             16|15 ft
+frenchfeet             frenchfoot
+toise                  6 frenchfeet
+candle                 1.02 candela
+militarypace           2.5 feet
+metre                  meter
+litre                  liter
+gramme                 gram
+iudiptheria            62.8 microgram
+iupenicillin           .6 microgram
+iuinsulin              41.67 microgram
+cottonyarncount                2520 ft/pound
+linenyarncount         900 ft/pound
+worstedyarncount       1680 ft/pound
+metricyarncount                meter/gram
+jewlerspoint           2 milligram
+