Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 16 Apr 1996 12:37:58 +0100 (BST)
From:      jez@netcraft.co.uk (Jeremy Prior)
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   bin/1147: units(1) command missing
Message-ID:  <199604161137.MAA18313@ns0.netcraft.co.uk>
Resent-Message-ID: <199604161140.EAA05382@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         1147
>Category:       bin
>Synopsis:       units(1) missing from FreeBSD -current and -stable
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Apr 16 04:40:02 PDT 1996
>Last-Modified:
>Originator:     Jeremy Prior
>Organization:
Netcraft Ltd
>Release:        FreeBSD 2.1-STABLE i386
>Environment:

	FreeBSD -current or less

>Description:

	FreeBSD is missing units(1) - Not sure why!

>How-To-Repeat:

	% units
	units: Command not found.

>Fix:
	
	Here's the one from NetBSD, written by Adrian Mariano
	(adrian@cam.cornell.edu or mariano@geom.umn.edu).
	Installs no problem.

	[The only thing missing is the caveat in the bugs section
	of the man page (you know;, the one about not basing
	financial plans on the currency conversions :-)]

-- Cut Here --
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	Makefile
#	pathnames.h
#	README
#	units.1
#	units.c
#	units.lib
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X#	$NetBSD: Makefile,v 1.2 1996/04/06 06:00:58 thorpej Exp $
X
XPROG=	units
X
Xbeforeinstall:
X	install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
X	    ${.CURDIR}/units.lib ${DESTDIR}/usr/share/misc
X
X.include <bsd.prog.mk>
END-of-Makefile
echo x - pathnames.h
sed 's/^X//' >pathnames.h << 'END-of-pathnames.h'
X/*	$NetBSD: pathnames.h,v 1.3 1996/04/06 06:01:00 thorpej Exp $	*/
X
X/*
X * Copyright (c) 1993 Christopher G. Demetriou
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *      This product includes software developed by Christopher G. Demetriou.
X * 4. The name of the author may not be used to endorse or promote products
X *    derived from this software without specific prior written permission
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
X * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
X * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
X * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
X * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
X * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X */
X
X#define	_PATH_UNITSLIB	"/usr/share/misc/units.lib"
END-of-pathnames.h
echo x - README
sed 's/^X//' >README << 'END-of-README'
X#	$NetBSD: README,v 1.2 1996/04/06 06:00:59 thorpej Exp $
X
XThis is a program which I wrote as a clone of the UNIX 'units'
Xcommand.  I threw it together in a couple days, but it seems to work,
Xwith some restrictions.  I have tested it under DOS with Borland C and
XUltrix 4.2, and SunOS 4.1.  
X
XThis program differs from the unix units program in the following
Xways:
X   it can gracefully handle exponents larger than 9 in output
X   it uses 'e' to denote exponentiation in numbers
X   prefixes are listed in the units file
X   it tries both -s and -es plurals
X   it allows use of * for multiply and ^ for exponentiation in the input
X   the output format is somewhat different
X
XAdrian Mariano (adrian@cam.cornell.edu or mariano@geom.umn.edu)
X
END-of-README
echo x - units.1
sed 's/^X//' >units.1 << 'END-of-units.1'
X.\" $NetBSD: units.1,v 1.6 1996/04/06 06:01:02 thorpej Exp $
X.TH UNITS 1  "14 July 1993"
X.SH NAME
Xunits - conversion program
X.SH SYNTAX
X.B units
X[-f filename] [-qv] [from-unit to-unit]
X.SH SUMMARY
X.TP 4
X.B -f filename
XSpecifies the name of the units data file to load.
X.LP
X.TP 4
X.B -q 
XSuppresses prompting of the user for units and the display of statistics
Xabout the number of units loaded.
X.LP
X.TP 4
X.B -v 
XPrints the version number.
X.LP
X.TP 4
X.B from-unit to-unit
XAllows a single unit conversion to be done directly from the command
Xline.  No prompting will occur.  The units program will print out
Xonly the result of this single conversion.
X
X.SH DESCRIPTION
XThe units program converts quantities expression in various scales to 
Xtheir equivalents in other scales.  The units program can only
Xhandle multiplicative scale changes.  It cannot convert Centigrade
Xto Fahrenheit, for example.  It works interactively by prompting
Xthe user for input:
X.nf
X
X    You have: meters
X    You want: feet
X            * 3.2808399
X            / 0.3048
X
X    You have: cm^3
X    You want: gallons
X            * 0.00026417205
X            / 3785.4118
X
X.fi
XPowers of units can be specified using the '^' character as shown in
Xthe example, or by simple concatenation: 'cm3' is equivalent to 'cm^3'.
XMultiplication of units can be specified by using spaces, a dash or
Xan asterisk.  Division of units is indicated by the slash ('/').  
XNote that multiplication has a higher precedence than division, 
Xso 'm/s/s' is the same as 'm/s^2' or 'm/s s'.
XIf the user enters incompatible unit types, the units program will
Xprint a message indicating that the units are not conformable and
Xit will display the reduced form for each unit:
X.nf
X
X    You have: ergs/hour
X    You want: fathoms kg^2 / day 
X    conformability error
X            2.7777778e-11 kg m^2 / sec^3
X            2.1166667e-05 kg^2 m / sec
X
X.fi
X.LP
XThe conversion information is read from a units data file.  The default
Xfile includes definitions for most familiar units, abbreviations and
Xmetric prefixes.  Some constants of nature included are:
X.in +4m
X.ta
X.ta 9m +
X.nf
X
Xpi	ratio of circumference to diameter
Xc	speed of light
Xe	charge on an electron
Xg	acceleration of gravity
Xforce	same as g
Xmole	Avogadro's number
Xwater	pressure per unit height of water
Xmercury	pressure per unit height of mercury
Xau	astronomical unit
X
X.fi
X.in -4m
X\'Pound' is a unit of mass.  Compound names are run together
Xso 'poundforce' is a unit of force.  British units that differ from their
XUS counterparts are prefixed with 'br', and currency is prefixed with
Xits country name: 'belgiumfranc', 'britainpound'.  When searching for
Xa unit, if the specified string does not appear exactly as a unit
Xname, then the units program will try to remove a trailing 's' or
Xa trailing 'es' and check again for a match.  
X.LP
XAll of these definitions can be read in the standard units file, or you
Xcan supply your own file.  A unit is specified on a single line by
Xgiving its name and an equivalence.  One should be careful to define
Xnew units in terms of old ones so that a reduction leads to the
Xprimitive units which are marked with '!' characters.  
XThe units program will not detect infinite loops that could be caused
Xby careless unit definitions.
X.LP
XPrefixes are defined in the same was as standard units, but with 
Xa trailing dash at the end of the prefix name.  
X.SH BUGS
X.LP
XThe effect of including a '/' in a prefix is surprising.
X.LP
XExponents entered by the user can be only one digit.
XYou can work around this by multiplying several terms.
X.LP
XThe user must use | to indicate division of numbers and / to
Xindicate division of symbols.  This distinction should not
Xbe necessary.
X.LP
XThe program contains various arbitrary limits on the length
Xof the units converted and on the length of the data file.
X.LP
XThe program should use a hash table to store units so that
Xit doesn't take so long to load the units list and check
Xfor duplication.  
X.SH FILES
X/usr/share/misc/units.lib - the standard units library
X.SH AUTHOR
XAdrian Mariano (adrian@cam.cornell.edu or mariano@geom.umn.edu)
END-of-units.1
echo x - units.c
sed 's/^X//' >units.c << 'END-of-units.c'
X/*	$NetBSD: units.c,v 1.6 1996/04/06 06:01:03 thorpej Exp $	*/
X
X/*
X * units.c   Copyright (c) 1993 by Adrian Mariano (adrian@cam.cornell.edu)
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. The name of the author may not be used to endorse or promote products
X *    derived from this software without specific prior written permission.
X * Disclaimer:  This software is provided by the author "as is".  The author
X * shall not be liable for any damages caused in any way by this software.
X *
X * I would appreciate (though I do not require) receiving a copy of any
X * improvements you might make to this program.
X */
X
X#include <ctype.h>
X#include <stdio.h>
X#include <string.h>
X#include <stdlib.h>
X
X#include "pathnames.h"
X
X#define VERSION "1.0"
X
X#ifndef UNITSFILE
X#define UNITSFILE _PATH_UNITSLIB
X#endif
X
X#define MAXUNITS 1000
X#define MAXPREFIXES 50
X
X#define MAXSUBUNITS 500
X
X#define PRIMITIVECHAR '!'
X
Xchar *powerstring = "^";
X
Xstruct {
X	char *uname;
X	char *uval;
X}      unittable[MAXUNITS];
X
Xstruct unittype {
X	char *numerator[MAXSUBUNITS];
X	char *denominator[MAXSUBUNITS];
X	double factor;
X};
X
Xstruct {
X	char *prefixname;
X	char *prefixval;
X}      prefixtable[MAXPREFIXES];
X
X
Xchar *NULLUNIT = "";
X
Xint unitcount;
Xint prefixcount;
X
X
Xchar *
Xdupstr(char *str)
X{
X	char *ret;
X
X	ret = malloc(strlen(str) + 1);
X	if (!ret) {
X		fprintf(stderr, "Memory allocation error\n");
X		exit(3);
X	}
X	strcpy(ret, str);
X	return (ret);
X}
X
X
Xvoid 
Xreaderror(int linenum)
X{
X	fprintf(stderr, "Error in units file '%s' line %d\n", UNITSFILE,
X	    linenum);
X}
X
X
Xvoid 
Xreadunits(char *userfile)
X{
X	FILE *unitfile;
X	char line[80], *lineptr;
X	int len, linenum, i;
X
X	unitcount = 0;
X	linenum = 0;
X
X	if (userfile) {
X		unitfile = fopen(userfile, "rt");
X		if (!unitfile) {
X			fprintf(stderr, "Unable to open units file '%s'\n",
X			    userfile);
X			exit(1);
X		}
X	}
X	else {
X		unitfile = fopen(UNITSFILE, "rt");
X		if (!unitfile) {
X			char *direc, *env;
X			char filename[1000];
X			char separator[2];
X
X			env = getenv("PATH");
X			if (env) {
X				if (strchr(env, ';'))
X					strcpy(separator, ";");
X				else
X					strcpy(separator, ":");
X				direc = strtok(env, separator);
X				while (direc) {
X					strcpy(filename, "");
X					strncat(filename, direc, 999);
X					strncat(filename, "/",
X					    999 - strlen(filename));
X					strncat(filename, UNITSFILE,
X					    999 - strlen(filename));
X					unitfile = fopen(filename, "rt");
X					if (unitfile)
X						break;
X					direc = strtok(NULL, separator);
X				}
X			}
X			if (!unitfile) {
X				fprintf(stderr, "Can't find units file '%s'\n",
X				    UNITSFILE);
X				exit(1);
X			}
X		}
X	}
X	while (!feof(unitfile)) {
X		if (!fgets(line, 79, unitfile))
X			break;
X		linenum++;
X		lineptr = line;
X		if (*lineptr == '/')
X			continue;
X		lineptr += strspn(lineptr, " \n\t");
X		len = strcspn(lineptr, " \n\t");
X		lineptr[len] = 0;
X		if (!strlen(lineptr))
X			continue;
X		if (lineptr[strlen(lineptr) - 1] == '-') { /* it's a prefix */
X			if (prefixcount == MAXPREFIXES) {
X				fprintf(stderr, "Memory for prefixes exceeded in line %d\n",
X				    linenum);
X				continue;
X			}
X			lineptr[strlen(lineptr) - 1] = 0;
X			prefixtable[prefixcount].prefixname = dupstr(lineptr);
X			for (i = 0; i < prefixcount; i++)
X				if (!strcmp(prefixtable[i].prefixname, lineptr)) {
X					fprintf(stderr, "Redefinition of prefix '%s' on line %d ignored\n",
X					    lineptr, linenum);
X					continue;
X				}
X			lineptr += len + 1;
X			if (!strlen(lineptr)) {
X				readerror(linenum);
X				continue;
X			}
X			lineptr += strspn(lineptr, " \n\t");
X			len = strcspn(lineptr, "\n\t");
X			lineptr[len] = 0;
X			prefixtable[prefixcount++].prefixval = dupstr(lineptr);
X		}
X		else {		/* it's not a prefix */
X			if (unitcount == MAXUNITS) {
X				fprintf(stderr, "Memory for units exceeded in line %d\n",
X				    linenum);
X				continue;
X			}
X			unittable[unitcount].uname = dupstr(lineptr);
X			for (i = 0; i < unitcount; i++)
X				if (!strcmp(unittable[i].uname, lineptr)) {
X					fprintf(stderr, "Redefinition of unit '%s' on line %d ignored\n",
X					    lineptr, linenum);
X					continue;
X				}
X			lineptr += len + 1;
X			lineptr += strspn(lineptr, " \n\t");
X			if (!strlen(lineptr)) {
X				readerror(linenum);
X				continue;
X			}
X			len = strcspn(lineptr, "\n\t");
X			lineptr[len] = 0;
X			unittable[unitcount++].uval = dupstr(lineptr);
X		}
X	}
X	fclose(unitfile);
X}
X
Xvoid 
Xinitializeunit(struct unittype * theunit)
X{
X	theunit->factor = 1.0;
X	theunit->numerator[0] = theunit->denominator[0] = NULL;
X}
X
X
Xint 
Xaddsubunit(char *product[], char *toadd)
X{
X	char **ptr;
X
X	for (ptr = product; *ptr && *ptr != NULLUNIT; ptr++);
X	if (ptr >= product + MAXSUBUNITS) {
X		fprintf(stderr, "Memory overflow in unit reduction\n");
X		return 1;
X	}
X	if (!*ptr)
X		*(ptr + 1) = 0;
X	*ptr = dupstr(toadd);
X	return 0;
X}
X
X
Xvoid 
Xshowunit(struct unittype * theunit)
X{
X	char **ptr;
X	int printedslash;
X	int counter = 1;
X
X	printf("\t%.8g", theunit->factor);
X	for (ptr = theunit->numerator; *ptr; ptr++) {
X		if (ptr > theunit->numerator && **ptr &&
X		    !strcmp(*ptr, *(ptr - 1)))
X			counter++;
X		else {
X			if (counter > 1)
X				printf("%s%d", powerstring, counter);
X			if (**ptr)
X				printf(" %s", *ptr);
X			counter = 1;
X		}
X	}
X	if (counter > 1)
X		printf("%s%d", powerstring, counter);
X	counter = 1;
X	printedslash = 0;
X	for (ptr = theunit->denominator; *ptr; ptr++) {
X		if (ptr > theunit->denominator && **ptr &&
X		    !strcmp(*ptr, *(ptr - 1)))
X			counter++;
X		else {
X			if (counter > 1)
X				printf("%s%d", powerstring, counter);
X			if (**ptr) {
X				if (!printedslash)
X					printf(" /");
X				printedslash = 1;
X				printf(" %s", *ptr);
X			}
X			counter = 1;
X		}
X	}
X	if (counter > 1)
X		printf("%s%d", powerstring, counter);
X	printf("\n");
X}
X
X
Xvoid 
Xzeroerror()
X{
X	fprintf(stderr, "Unit reduces to zero\n");
X}
X
X/*
X   Adds the specified string to the unit.
X   Flip is 0 for adding normally, 1 for adding reciprocal.
X
X   Returns 0 for successful addition, nonzero on error.
X*/
X
Xint 
Xaddunit(struct unittype * theunit, char *toadd, int flip)
X{
X	char *scratch, *savescr;
X	char *item;
X	char *divider, *slash;
X	int doingtop;
X
X	savescr = scratch = dupstr(toadd);
X	for (slash = scratch + 1; *slash; slash++)
X		if (*slash == '-' &&
X		    (tolower(*(slash - 1)) != 'e' ||
X		    !strchr(".0123456789", *(slash + 1))))
X			*slash = ' ';
X	slash = strchr(scratch, '/');
X	if (slash)
X		*slash = 0;
X	doingtop = 1;
X	do {
X		item = strtok(scratch, " *\t\n/");
X		while (item) {
X			if (strchr("0123456789.", *item)) { /* item is a number */
X				double num;
X
X				divider = strchr(item, '|');
X				if (divider) {
X					*divider = 0;
X					num = atof(item);
X					if (!num) {
X						zeroerror();
X						return 1;
X					}
X					if (doingtop ^ flip)
X						theunit->factor *= num;
X					else
X						theunit->factor /= num;
X					num = atof(divider + 1);
X					if (!num) {
X						zeroerror();
X						return 1;
X					}
X					if (doingtop ^ flip)
X						theunit->factor /= num;
X					else
X						theunit->factor *= num;
X				}
X				else {
X					num = atof(item);
X					if (!num) {
X						zeroerror();
X						return 1;
X					}
X					if (doingtop ^ flip)
X						theunit->factor *= num;
X					else
X						theunit->factor /= num;
X
X				}
X			}
X			else {	/* item is not a number */
X				int repeat = 1;
X
X				if (strchr("23456789",
X				    item[strlen(item) - 1])) {
X					repeat = item[strlen(item) - 1] - '0';
X					item[strlen(item) - 1] = 0;
X				}
X				for (; repeat; repeat--)
X					if (addsubunit(doingtop ^ flip ? theunit->numerator : theunit->denominator, item))
X						return 1;
X			}
X			item = strtok(NULL, " *\t/\n");
X		}
X		doingtop--;
X		if (slash) {
X			scratch = slash + 1;
X		}
X		else
X			doingtop--;
X	} while (doingtop >= 0);
X	free(savescr);
X	return 0;
X}
X
X
Xint 
Xcompare(const void *item1, const void *item2)
X{
X	return strcmp(*(char **) item1, *(char **) item2);
X}
X
X
Xvoid 
Xsortunit(struct unittype * theunit)
X{
X	char **ptr;
X	int count;
X
X	for (count = 0, ptr = theunit->numerator; *ptr; ptr++, count++);
X	qsort(theunit->numerator, count, sizeof(char *), compare);
X	for (count = 0, ptr = theunit->denominator; *ptr; ptr++, count++);
X	qsort(theunit->denominator, count, sizeof(char *), compare);
X}
X
X
Xvoid 
Xcancelunit(struct unittype * theunit)
X{
X	char **den, **num;
X	int comp;
X
X	den = theunit->denominator;
X	num = theunit->numerator;
X
X	while (*num && *den) {
X		comp = strcmp(*den, *num);
X		if (!comp) {
X/*      if (*den!=NULLUNIT) free(*den);
X      if (*num!=NULLUNIT) free(*num);*/
X			*den++ = NULLUNIT;
X			*num++ = NULLUNIT;
X		}
X		else if (comp < 0)
X			den++;
X		else
X			num++;
X	}
X}
X
X
X
X
X/*
X   Looks up the definition for the specified unit.
X   Returns a pointer to the definition or a null pointer
X   if the specified unit does not appear in the units table.
X*/
X
Xstatic char buffer[100];	/* buffer for lookupunit answers with
X				   prefixes */
X
Xchar *
Xlookupunit(char *unit)
X{
X	int i;
X	char *copy;
X
X	for (i = 0; i < unitcount; i++) {
X		if (!strcmp(unittable[i].uname, unit))
X			return unittable[i].uval;
X	}
X
X	if (unit[strlen(unit) - 1] == '^') {
X		copy = dupstr(unit);
X		copy[strlen(copy) - 1] = 0;
X		for (i = 0; i < unitcount; i++) {
X			if (!strcmp(unittable[i].uname, copy)) {
X				strcpy(buffer, copy);
X				free(copy);
X				return buffer;
X			}
X		}
X		free(copy);
X	}
X	if (unit[strlen(unit) - 1] == 's') {
X		copy = dupstr(unit);
X		copy[strlen(copy) - 1] = 0;
X		for (i = 0; i < unitcount; i++) {
X			if (!strcmp(unittable[i].uname, copy)) {
X				strcpy(buffer, copy);
X				free(copy);
X				return buffer;
X			}
X		}
X		if (copy[strlen(copy) - 1] == 'e') {
X			copy[strlen(copy) - 1] = 0;
X			for (i = 0; i < unitcount; i++) {
X				if (!strcmp(unittable[i].uname, copy)) {
X					strcpy(buffer, copy);
X					free(copy);
X					return buffer;
X				}
X			}
X		}
X		free(copy);
X	}
X	for (i = 0; i < prefixcount; i++) {
X		if (!strncmp(prefixtable[i].prefixname, unit,
X			strlen(prefixtable[i].prefixname))) {
X			unit += strlen(prefixtable[i].prefixname);
X			if (!strlen(unit) || lookupunit(unit)) {
X				strcpy(buffer, prefixtable[i].prefixval);
X				strcat(buffer, " ");
X				strcat(buffer, unit);
X				return buffer;
X			}
X		}
X	}
X	return 0;
X}
X
X
X
X/*
X   reduces a product of symbolic units to primitive units.
X   The three low bits are used to return flags:
X
X     bit 0 (1) set on if reductions were performed without error.
X     bit 1 (2) set on if no reductions are performed.
X     bit 2 (4) set on if an unknown unit is discovered.
X*/
X
X
X#define ERROR 4
X
Xint 
Xreduceproduct(struct unittype * theunit, int flip)
X{
X
X	char *toadd;
X	char **product;
X	int didsomething = 2;
X
X	if (flip)
X		product = theunit->denominator;
X	else
X		product = theunit->numerator;
X
X	for (; *product; product++) {
X
X		for (;;) {
X			if (!strlen(*product))
X				break;
X			toadd = lookupunit(*product);
X			if (!toadd) {
X				printf("unknown unit '%s'\n", *product);
X				return ERROR;
X			}
X			if (strchr(toadd, PRIMITIVECHAR))
X				break;
X			didsomething = 1;
X			if (*product != NULLUNIT) {
X				free(*product);
X				*product = NULLUNIT;
X			}
X			if (addunit(theunit, toadd, flip))
X				return ERROR;
X		}
X	}
X	return didsomething;
X}
X
X
X/*
X   Reduces numerator and denominator of the specified unit.
X   Returns 0 on success, or 1 on unknown unit error.
X*/
X
Xint 
Xreduceunit(struct unittype * theunit)
X{
X	int ret;
X
X	ret = 1;
X	while (ret & 1) {
X		ret = reduceproduct(theunit, 0) | reduceproduct(theunit, 1);
X		if (ret & 4)
X			return 1;
X	}
X	return 0;
X}
X
X
Xint 
Xcompareproducts(char **one, char **two)
X{
X	while (*one || *two) {
X		if (!*one && *two != NULLUNIT)
X			return 1;
X		if (!*two && *one != NULLUNIT)
X			return 1;
X		if (*one == NULLUNIT)
X			one++;
X		else if (*two == NULLUNIT)
X			two++;
X		else if (strcmp(*one, *two))
X			return 1;
X		else
X			one++, two++;
X	}
X	return 0;
X}
X
X
X/* Return zero if units are compatible, nonzero otherwise */
X
Xint 
Xcompareunits(struct unittype * first, struct unittype * second)
X{
X	return
X	compareproducts(first->numerator, second->numerator) ||
X	compareproducts(first->denominator, second->denominator);
X}
X
X
Xint 
Xcompletereduce(struct unittype * unit)
X{
X	if (reduceunit(unit))
X		return 1;
X	sortunit(unit);
X	cancelunit(unit);
X	return 0;
X}
X
X
Xvoid 
Xshowanswer(struct unittype * have, struct unittype * want)
X{
X	if (compareunits(have, want)) {
X		printf("conformability error\n");
X		showunit(have);
X		showunit(want);
X	}
X	else
X		printf("\t* %.8g\n\t/ %.8g\n", have->factor / want->factor,
X		    want->factor / have->factor);
X}
X
X
Xvoid 
Xusage()
X{
X	fprintf(stderr, "\nunits [-f unitsfile] [-q] [-v] [from-unit to-unit]\n");
X	fprintf(stderr, "\n    -f specify units file\n");
X	fprintf(stderr, "    -q supress prompting (quiet)\n");
X	fprintf(stderr, "    -v print version number\n");
X	exit(3);
X}
X
X
Xint
Xmain(int argc, char **argv)
X{
X
X	struct unittype have, want;
X	char havestr[81], wantstr[81];
X	int optchar;
X	char *userfile = 0;
X	int quiet = 0;
X
X	extern char *optarg;
X	extern int optind;
X
X	while ((optchar = getopt(argc, argv, "vqf:")) != -1) {
X		switch (optchar) {
X		case 'f':
X			userfile = optarg;
X			break;
X		case 'q':
X			quiet = 1;
X			break;
X		case 'v':
X			fprintf(stderr, "\n  units version %s  Copyright (c) 1993 by Adrian Mariano\n",
X			    VERSION);
X			fprintf(stderr, "                    This program may be freely distributed\n");
X			usage();
X		default:
X			usage();
X			break;
X		}
X	}
X
X	if (optind != argc - 2 && optind != argc)
X		usage();
X
X	readunits(userfile);
X
X	if (optind == argc - 2) {
X		strcpy(havestr, argv[optind]);
X		strcpy(wantstr, argv[optind + 1]);
X		initializeunit(&have);
X		addunit(&have, havestr, 0);
X		completereduce(&have);
X		initializeunit(&want);
X		addunit(&want, wantstr, 0);
X		completereduce(&want);
X		showanswer(&have, &want);
X	}
X	else {
X		if (!quiet)
X			printf("%d units, %d prefixes\n\n", unitcount,
X			    prefixcount);
X		for (;;) {
X			do {
X				initializeunit(&have);
X				if (!quiet)
X					printf("You have: ");
X				if (!fgets(havestr, 80, stdin)) {
X					if (!quiet);
X					putchar('\n');
X					exit(0);
X				}
X			} while (addunit(&have, havestr, 0) ||
X			    completereduce(&have));
X			do {
X				initializeunit(&want);
X				if (!quiet)
X					printf("You want: ");
X				if (!fgets(wantstr, 80, stdin)) {
X					if (!quiet)
X						putchar('\n');
X					exit(0);
X				}
X			} while (addunit(&want, wantstr, 0) ||
X			    completereduce(&want));
X			showanswer(&have, &want);
X		}
X	}
X}
END-of-units.c
echo x - units.lib
sed 's/^X//' >units.lib << 'END-of-units.lib'
X/ $NetBSD: units.lib,v 1.3 1996/04/06 06:01:04 thorpej Exp $
X
X/ primitive units
X
Xm			!a!
Xkg			!b!
Xsec			!c!
Xcoul			!d!
Xcandela			!e!
Xdollar			!f!
Xbit			!h!
Xerlang			!i!
XK			!j!
X
X/ prefixes
X
Xyotta-			1e24
Xzetta-			1e21
Xexa-			1e18
Xpeta-			1e15
Xtera-			1e12
Xgiga-			1e9
Xmega-			1e6
Xmyria-			1e4
Xkilo-			1e3
Xhecto-			1e2
Xdeka-			1e1
Xdeci-			1e-1
Xcenti-			1e-2
Xmilli-			1e-3
Xmicro-			1e-6
Xnano-			1e-9
Xpico-			1e-12
Xfemto-			1e-15
Xatto-			1e-18
Xzopto-			1e-21
Xyocto-			1e-24
X
Xsemi-			.5
Xdemi-			.5
X
XY-			yotta
XZ-			zetta
XE-			exa
XP-			peta
XT-			tera
XG-			giga
XM-			mega
Xk-			kilo
Xh-			hecto
Xda-			deka
Xd-			deci
Xc-			centi
Xm-			milli
Xp-			pico
Xf-			femto
Xa-			atto
Xz-			zopto
Xy-			yocto
X
X/ constants
X
Xfuzz			1
Xpi			3.14159265358979323846
Xc			2.99792458e+8 m/sec fuzz
Xg			9.80665 m/sec2
Xau			1.49597871e+11 m fuzz
Xmole			6.022169e+23 fuzz
Xe			1.6021917e-19 coul fuzz
Xenergy			c2
Xforce			g
Xmercury			1.33322e+5 kg/m2-sec2
Xhg			mercury
X
X/ dimensionless
X
Xradian			.5 / pi
Xdegree			1|180 pi-radian
Xcircle			2 pi-radian
Xturn			2 pi-radian
Xrevolution			turn
Xrev			turn
Xgrade			.9 degree
Xarcdeg			1 degree
Xarcmin			1|60 arcdeg
Xccs			1|36 erlang
Xarcsec			1|60 arcmin
X
Xsteradian		radian2
Xsphere			4 pi-steradian
Xsr			steradian
X
X/ Time
X
Xsecond			sec
Xs			sec
Xminute			60 sec
Xmin			minute
Xhour			60 min
Xhr			hour
Xday			24 hr
Xda			day
Xweek			7 day
Xyear			365.24219879 day fuzz
Xyr			year
Xmonth			1|12 year
Xms			millisec
Xus			microsec
X
X/ Mass
X
Xgram			millikg
Xgm			gram
Xmg			milligram
Xmetricton		kilokg
X
X/ Avoirdupois
X
Xlb			.45359237 kg
Xpound			lb
Xlbf			lb g
Xounce			1|16 lb
Xoz			ounce
Xdram			1|16 oz
Xdr			dram
Xgrain			1|7000 lb
Xgr			grain
Xshortton		2000 lb
Xton			shortton
Xlongton			2240 lb
X
X/ Apothecary
X
Xscruple			20 grain
Xapdram			60 grain
Xapounce			480 grain
Xappound			5760 grain
Xtroypound		appound
X
X/ Length
X
Xmeter			m
Xcm			centimeter
Xmm			millimeter
Xkm			kilometer
Xnm			nanometer
Xmicron			micrometer
Xangstrom		decinanometer
X
Xinch			2.54 cm
Xin			inch
Xfoot			12 in
Xfeet			foot
Xft			foot
Xyard			3 ft
Xyd			yard
Xrod			5.5 yd
Xrd			rod
Xmile			5280 ft
Xmi			mile
X
Xbritish			1200|3937 m/ft
Xnmile			1852 m
X
Xacre			4840 yd2
X
Xcc			cm3
Xliter			kilocc
Xml			milliliter
X
X/ US Liquid
X
Xgallon			231 in3
Ximperial		1.20095
Xgal			gallon
Xquart			1|4 gal
Xqt			quart
Xpint			1|2 qt
Xpt			pint
X
Xfloz			1|16 pt
Xfldr			1|8 floz
X
X/ US Dry
X
Xdry			268.8025 in3/gallon fuzz
Xpeck			8 dry-quart
Xpk			peck
Xbushel			4 peck
Xbu			bushel
Xchaldron		36 bushel
X
X/ British
X
Xbrgallon		277.420 in3 fuzz
Xbrquart			1|4 brgallon
Xbrpint			1|2 brquart
Xbrfloz			1|20 brpint
Xbrpeck			554.84 in3 fuzz
Xbrbushel		4 brpeck
X
X/ Energy Work
X
Xnewton			kg-m/sec2
Xnt			newton
XN			newton
Xjoule			nt-m
Xcal			4.1868 joule
X
X/ Electrical
X
Xcoulomb			coul
XC			coul
Xampere			coul/sec
Xamp			ampere
Xwatt			joule/sec
Xvolt			watt/amp
Xohm			volt/amp
Xmho			/ohm
Xfarad			coul/volt
Xhenry			sec2/farad
Xweber			volt-sec
X
X/ Light
X
Xcd			candela
Xlumen			cd sr
Xlux			cd sr/m2
X
X/ Wall Street Journal, July 2, 1993
X
X$			dollar
Xargentinapeso		$
Xaustraliadollar		.66 $
Xaustriaschilling	.83 $
Xbahraindinar		2.6522 $
Xbelgiumfranc		.028 $
Xbrazilcruzeiro		.000019 $
Xbritainpound		1.49 $
Xcanadadollar		.77 $
Xczechkoruna		.034 $
Xchilepeso		.0025 $
Xchinarenminbi		.174856 $
Xcolombiapeso		.001495 $
Xdenmarkkrone		.15 $
Xecuadorsucre		.000539 $
Xfinlandmarkka		.17 $
Xfrancefranc		.17 $
Xgermanymark		.58 $
Xgreatbritainpound	britainpound
Xgreecedrachma		.0043 $
Xhongkongdollar		.13  $
Xhungaryforint		.011 $
Xindiarupee		.03211 $
Xindonesiarupiah		.0004782 $
Xirelandpunt		1.43 $
Xisraelshekel		.3642 $
Xitalylira		.00064 $
Xjapanyen		.0093 $
Xjordandinar		1.4682 $
Xkuwaitdinar		3.3173 $
Xlebanonpound		.000578 $
Xmalaysiaringgit		.338 $
Xmaltalira		2.6042 $
Xmexicopeso		.3205128 $
Xnetherlandguilder	.52 $
Xnewzealanddollar	.539 $
Xnorwaykrone		.139 $
Xpakistanrupee		.037 $
Xperunewsol		.5065 $
Xphilippinespeso		.03738 $
Xpolandzloty		.000059 $
Xportugalescudo		.00617 $
Xsaudiarabiariyal	.26702 $
Xsingaporedollar		.6157 $
Xslovakkoruna		.034 $
Xsouthamericarand	.21 $
Xsouthkoreawon		.001 $
Xspainpeseta		.007 $
Xswedenkrona		.13 $
Xswitzerlandfranc	.66 $
Xtaiwandollar		.038285 $
Xthailandbaht		.03962 $
Xturkeylira		.0000929 $
Xunitedarabdirham	.2723 $
Xuruguaynewpeso		.246852 $
Xvenezuelabolivar	.011 $
X
Xmark			germanymark
Xbolivar			venezuelabolivar
Xpeseta			spainpeseta
Xrand			southafricarand
Xescudo			portugalescudo
Xsol			perusol
Xguilder			netherlandsguilder
Xhollandguilder		netherlandsguilder
Xpeso			mexicopeso
Xyen			japanyen
Xlira			italylira
Xrupee			indiarupee
Xdrachma			greecedrachma
Xfranc			francefranc
Xmarkka			finlandmarkka
Xsucre			ecuadorsucre
Xpoundsterling		britainpound
Xcruzeiro		brazilcruzeiro
X
X/ computer
X
Xbaud			bit/sec
Xbyte			8 bit
Xblock			512 byte
Xkbyte			1024 byte
Xmegabyte		1024 kbyte
Xgigabyte		1024 megabyte
Xmeg			megabyte
X
X
X/ Trivia
X
X%			1|100
Xadmiraltyknot		6080 ft/hr
Xapostilb		cd/pi-m2
Xare			1e+2 m2
Xarpentcan		27.52 mi
Xarpentlin		191.835 ft
Xastronomicalunit	au
Xatmosphere		1.01325e+5 nt/m2
Xatm			atmosphere
Xatomicmassunit		1.66044e-27 kg fuzz
Xamu			atomicmassunit
Xbag			94 lb
Xbakersdozen		13
Xbar			1e+5 nt/m2
Xbarie			1e-1 nt/m2
Xbarleycorn		1|3 in
Xbarn			1e-28 m2
Xbarrel			42 gal
Xbarye			1e-1 nt/m2
Xbev			1e+9 e-volt
Xbiot			10 amp
Xblondel			cd/pi-m2
Xboardfoot		144 in3
Xbolt			40 yd
Xbottommeasure		1|40 in
Xbritishthermalunit	1.05506e+3 joule fuzz
Xbtu			britishthermalunit
Xrefrigeration		12000 btu/ton-hour
Xbuck			dollar
Xcable			720 ft
Xcaliber			1e-2 in
Xcalorie			cal
Xcarat			205 mg
Xcaratgold		1|24
Xcent			centidollar
Xcental			100 lb
Xcentesimalminute	1e-2 grade
Xcentesimalsecond	1e-4 grade
Xcentury			100 year
Xcfs			ft3/sec
Xchain			66 ft
Xcircularinch		1|4 pi-in2
Xcircularmil		1e-6|4 pi-in2
Xclusec			1e-8 mm-hg m3/s
Xcoomb			4 bu
Xcord			128 ft3
Xcordfoot		cord
Xcrith			9.06e-2 gm
Xcubit			18 in
Xcup			1|2 pt
Xcurie			3.7e+10 /sec
Xdalton			amu
Xdecade			10 yr
Xdipotre			/m
Xdisplacementton		35 ft3
Xdoppelzentner		100 kg
Xdozen			12
Xdrop			.03 cm3
Xdyne			cm-gm/sec2
Xelectronvolt		e-volt
Xell			45 in
Xengineerschain		100 ft
Xengineerslink		100|100 ft
Xequivalentfootcandle	lumen/pi-ft2
Xequivalentlux		lumen/pi-m2
Xequivalentphot		cd/pi-cm2
Xerg			cm2-gm/sec2
Xev			e-volt
Xfaraday			9.652e+4 coul
Xfathom			6 ft
Xfermi			1e-15 m
Xfifth			4|5 qt
Xfin			5 dollar
Xfinger			7|8 in
Xfirkin			9 gal
Xfootcandle		lumen/ft2
Xfootlambert		cd/pi-ft2
Xfortnight		14 da
Xfranklin		3.33564e-10 coul
Xfrigorie		kilocal
Xfurlong			220 yd
Xgalileo			1e-2 m/sec2
Xgamma			1e-9 weber/m2
Xgauss			1e-4 weber/m2
Xgeodeticfoot		british-ft
Xgeographicalmile	1852 m
Xgilbert			7.95775e-1 amp
Xgill			1|4 pt
Xgross			144
Xgunterschain		22 yd
Xhand			4 in
Xhectare			1e+4 m2
Xhefnercandle		.92 cd
Xhertz			/sec
XHz			hertz
Xhogshead		2 barrel
Xhd			hogshead
Xhomestead		1|4 mi2
Xhorsepower		550 ft-lb-g/sec
Xhp			horsepower
Xhyl			gm force sec2/m
Xhz			/sec
Ximaginarycubicfoot	1.4 ft3
Xjeroboam		4|5 gal
Xkarat			1|24
Xkcal			kilocal
Xkcalorie		kilocal
Xkev			1e+3 e-volt
Xkey			kg
Xkhz			1e+3 /sec
Xkilderkin		18 gal
Xknot			nmile/hr
Xlambert			cd/pi-cm2
Xlangley			cal/cm2
Xlast			80 bu
Xleague			3 mi
Xlightyear		c-yr
Xline			1|12 in
Xlink			66|100 ft
Xlonghundredweight	112 lb
Xlongquarter		28 lb
Xlusec			1e-6 mm-hg m3/s
Xmach			331.46 m/sec
Xmagnum			2 qt
Xmarineleague		3 nmile
Xmaxwell			1e-8 weber
Xmetriccarat		200 mg
Xmgd			megagal/day
Xmh			millihenry
Xmhz			1e+6 /sec
Xmil			1e-3 in
Xmillenium		1000 year
Xminersinch		1.5 ft3/min
Xminim			1|60 fldr
Xmo			month
Xmpg			mile/gal
Xmph			mile/hr
Xnail			1|16 yd
Xnauticalmile		nmile
Xnit			cd/m2
Xnoggin			1|8 qt
Xnox			1e-3 lux
Xns			nanosec
Xoersted			2.5e+2 pi-amp/m
Xoe			oersted
Xpace			36 in
Xpalm			3 in
Xparasang		3.5 mi
Xparsec			au-radian/arcsec
Xpascal			nt/m2
Xpc			parsec
Xpennyweight		1|20 oz
Xpwt			pennyweight
Xpercent			%
Xperch			rd
Xpf			picofarad
Xphot			lumen/cm2
Xpica			1|6 in
Xpieze			1e+3 nt/m2
Xpipe			4 barrel
Xpoint			1|72 in
Xpoise			gm/cm-sec
Xpole			rd
Xpoundal			ft-lb/sec2
Xpdl			poundal
Xproof			1|200
Xpsi			lb-g/in2
Xquarter			9 in
Xquartersection		1|4 mi2
Xquintal			100 kg
Xquire			25
Xrad			100 erg/gm
Xream			500
Xregisterton		100 ft3
Xrehoboam		156 floz
Xrhe			10 m2/nt-sec
Xrontgen			2.58e-4 curie/kg
Xrood			1.21e+3 yd
Xrope			20 ft
Xrutherford		1e+6 /sec
Xrydberg			1.36054e+1 ev
Xsabin			1 ft2
Xsack			3 bu
Xseam			8 bu
Xsection			mi2
Xshippington		40 ft3
Xshorthundredweight	100 lb
Xshortquarter		25 lb
Xsiemens			/ohm
Xsigma			microsec
Xskein			120 yd
Xskot			1e-3 apostilb
Xslug			lb-g-sec2/ft
Xspan			9 in
Xspat			4 pi sr
Xspindle			14400 yd
Xsquare			100 ft2
Xstere			m3
Xsthene			1e+3 nt
Xstilb			cd/cm2
Xstoke			1e-4 m2/sec
Xstone			14 lb
Xstrike			2 bu
Xsurveyfoot		british-ft
Xsurveyyard		3 surveyfoot
Xsurveyorschain		66 ft
Xsurveyorslink		66|100 ft
Xtablespoon		4 fldr
Xteaspoon		4|3 fldr
Xtesla			weber/m2
Xtherm			1e+5 btu
Xthermie			1e+6 cal
Xtimberfoot		ft3
Xtnt			4.6e+6 m2/sec2
Xtonne			1e+6 gm
Xtorr			mm hg
Xtownship		36 mi2
Xtun			8 barrel
Xwater			gram g / cc
Xwey			40 bu
Xweymass			252 lb
XXunit			1.00202e-13 m
Xk			1.38047e-16 erg/degC
X
X
XdegC			K
Xkelvin			K
Xbrewster		1e-12 m2/newton
XdegF			5|9 degC
Xdegreesrankine		degF
Xdegrankine		degreesrankine
Xdegreerankine		degF
Xdegreaumur		10|8 degC
Xdrachm			60 grain
Xponcelet		100 kg m g / sec
Xdenier			.05|450 gram / m
Xtex			.001 gram / m
Xenglishell		45 inch
Xscottishell		37.2 inch
Xflemishell		27 inch
Xplanck			6.626e-34 joule-sec
Xhbar			1.055e-34 joule-sec
Xelectronmass		9.1095e-31 kg
Xprotonmass		1.6726e-27 kg
Xneutronmass		1.6606e-27 kg
XV			volt
XeV			e V
Xbohrradius		hbar2-C2/8.988e9 N m2-e2-electronmass
Xbecquerel		1|3.7e10 curie
Xfresnel			1e12 hertz
Xstatcoul		1|2.99792458e9 coul
Xstatamp			1|2.99792458e9 amp
Xstatvolt		2.99792458e2 volt
Xstatcoulomb		statcoul
Xstatampere		statamp
Xdebye			3.336e-30 coul-m
Xpulsatance		2 pi/sec
Xrpm			rev/minute
Xrps			rev/sec
Xkilohm			kiloohm
Xmegohm			megaohm
Xsiderealyear		365.256360417 day
Xsiderealday		23.934469444 hour
Xsiderealhour		1|24 sidereal day
Xlunarmonth		29.5305555 day
Xsynodicmonth		lunarmonth
Xsiderealmonth		27.32152777 day
Xtropicalyear		year
Xsolaryear		year
Xlunaryear		12 lunarmonth
Xcran			37.5 brgallon
Xkip			1000 lbf
Xfrenchfoot		16|15 ft
Xfrenchfeet		frenchfoot
Xtoise			6 frenchfeet
Xsievert			8.4 rontgen
Xcandle			1.02 candela
Xmilitarypace		2.5 feet
Xmetre			meter
Xlitre			liter
Xgramme			gram
Xiudiptheria		62.8 microgram
Xiupenicillin		.6 microgram
Xiuinsulin		41.67 microgram
Xcottonyarncount		2520 ft/pound
Xlinenyarncount		900 ft/pound
Xworstedyarncount	1680 ft/pound
Xmetricyarncount		meter/gram
Xjewlerspoint		2 milligram
X
END-of-units.lib
exit
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199604161137.MAA18313>