Module Name: src Committed By: apb Date: Tue Jan 1 11:51:56 UTC 2013
Modified Files: src/usr.bin/units: units.1 units.c Log Message: Add -l and -L options to units(1). "-l" simply lists all unit definitions, while "-L" alsoreduces them to depend only on a few primitive units (such as m, kg, sec). To generate a diff of this commit: cvs rdiff -u -r1.18 -r1.19 src/usr.bin/units/units.1 cvs rdiff -u -r1.20 -r1.21 src/usr.bin/units/units.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/units/units.1 diff -u src/usr.bin/units/units.1:1.18 src/usr.bin/units/units.1:1.19 --- src/usr.bin/units/units.1:1.18 Fri Dec 28 13:25:25 2012 +++ src/usr.bin/units/units.1 Tue Jan 1 11:51:55 2013 @@ -1,4 +1,4 @@ -.\" $NetBSD: units.1,v 1.18 2012/12/28 13:25:25 apb Exp $ +.\" $NetBSD: units.1,v 1.19 2013/01/01 11:51:55 apb Exp $ .Dd December 28, 2012 .Dt UNITS 1 .Os @@ -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. Index: src/usr.bin/units/units.c diff -u src/usr.bin/units/units.c:1.20 src/usr.bin/units/units.c:1.21 --- src/usr.bin/units/units.c:1.20 Tue Jan 1 11:44:00 2013 +++ src/usr.bin/units/units.c Tue Jan 1 11:51:55 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: units.c,v 1.20 2013/01/01 11:44:00 apb Exp $ */ +/* $NetBSD: units.c,v 1.21 2013/01/01 11:51:55 apb Exp $ */ /* * units.c Copyright (c) 1993 by Adrian Mariano (adr...@cam.cornell.edu) @@ -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,13 @@ #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 { @@ -98,9 +106,27 @@ dupstr(const char *str) 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) { - warnx("Error in units file '%s' line %d", UNITSFILE, linenum); + mywarnx("Error in units file '%s' line %d", UNITSFILE, linenum); } @@ -168,8 +194,9 @@ readunits(const char *userfile) continue; if (lineptr[strlen(lineptr) - 1] == '-') { /* it's a prefix */ if (prefixcount == MAXPREFIXES) { - warnx("Memory for prefixes exceeded in line %d", - linenum); + mywarnx( + "Memory for prefixes exceeded in line %d", + linenum); continue; } lineptr[strlen(lineptr) - 1] = 0; @@ -181,7 +208,7 @@ readunits(const char *userfile) } } if (isdup) { - warnx( + mywarnx( "Redefinition of prefix '%s' on line %d ignored", lineptr, linenum); continue; @@ -199,7 +226,7 @@ readunits(const char *userfile) } else { /* it's not a prefix */ if (unitcount == MAXUNITS) { - warnx("Memory for units exceeded in line %d", + mywarnx("Memory for units exceeded in line %d", linenum); continue; } @@ -210,7 +237,7 @@ readunits(const char *userfile) } } if (isdup) { - warnx( + mywarnx( "Redefinition of unit '%s' on line %d ignored", lineptr, linenum); continue; @@ -244,7 +271,7 @@ addsubunit(const char *product[], const for (ptr = product; *ptr && *ptr != NULLUNIT; ptr++); if (ptr >= product + MAXSUBUNITS) { - warnx("Memory overflow in unit reduction"); + mywarnx("Memory overflow in unit reduction"); return 1; } if (!*ptr) @@ -260,7 +287,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))) @@ -301,7 +328,7 @@ showunit(struct unittype * theunit) static void zeroerror(void) { - warnx("Unit reduces to zero"); + mywarnx("Unit reduces to zero"); } /* @@ -347,8 +374,7 @@ addunit(struct unittype * theunit, const } if (endptr != divider) { /* "6foo|2" is an error */ - warnx("Junk between number " - "and '|'"); + mywarnx("Junk before '|'"); return 1; } if (doingtop ^ flip) @@ -562,7 +588,7 @@ reduceproduct(struct unittype * theunit, break; toadd = lookupunit(*product); if (!toadd) { - printf("unknown unit '%s'\n", *product); + mywarnx("Unknown unit '%s'", *product); return ERROR; } if (strchr(toadd, PRIMITIVECHAR)) @@ -660,15 +686,109 @@ showanswer(struct unittype * have, struc 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; + 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 + */ + initializeunit(&theunit); + if (addunit(&theunit, thedefn/*XXX*/, 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) @@ -689,10 +809,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; @@ -713,11 +842,18 @@ main(int argc, char **argv) argc -= optind; argv += optind; - if (argc != 3 && argc != 2 && argc != 0) + 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));