Update units(1) to allow conversion between degC and degF
authorMatthias Schmidt <matthias@dragonflybsd.org>
Thu, 4 Dec 2008 14:10:23 +0000 (15:10 +0100)
committerMatthias Schmidt <matthias@dragonflybsd.org>
Thu, 4 Dec 2008 14:10:23 +0000 (15:10 +0100)
This patch (in modified form from FreeBSD) rested for some time on
my disk, so I'll throw it in.  It allows conversion between Celsius
and Fahrenheit:

You have: 20 degC
You want: degF
68

Reminded-by: corecode@
usr.bin/units/units.1
usr.bin/units/units.c
usr.bin/units/units.lib

index 491d165..8232e99 100644 (file)
@@ -1,6 +1,6 @@
 .\" $FreeBSD: src/usr.bin/units/units.1,v 1.18 2005/02/13 22:25:25 ru Exp $
 .\" $DragonFly: src/usr.bin/units/units.1,v 1.4 2008/08/12 09:28:22 matthias Exp $
-.Dd August 12, 2008
+.Dd December 4, 2008
 .Dt UNITS 1
 .Os
 .Sh NAME
@@ -37,8 +37,7 @@ The
 .Nm
 program can only
 handle multiplicative scale changes.
-It cannot convert Celsius
-to Fahrenheit, for example.
+Experimental support is available to convert Celsius to Fahrenheit.
 It works interactively by prompting
 the user for input:
 .Bd -literal
@@ -61,6 +60,10 @@ the user for input:
     You want: cm
             * 1.27
             / 0.78740157
+
+    You have: 20 degC
+    You want: degF
+            68
 .Ed
 .Pp
 Powers of units can be specified using the '^' character as shown in
index a05e224..0f3fb9a 100644 (file)
@@ -14,7 +14,7 @@
  * I would appreciate (though I do not require) receiving a copy of any
  * improvements you might make to this program.
  *
- * $FreeBSD: src/usr.bin/units/units.c,v 1.6.2.2 2001/03/04 09:22:35 kris Exp $
+ * $FreeBSD: src/usr.bin/units/units.c,v 1.11 2008/08/16 16:27:41 dwmalone Exp $
  * $DragonFly: src/usr.bin/units/units.c,v 1.4 2006/08/13 19:19:44 swildner Exp $
  */
 
@@ -51,6 +51,8 @@ struct unittype {
        char *numerator[MAXSUBUNITS];
        char *denominator[MAXSUBUNITS];
        double factor;
+       double offset;
+       int quantity;
 };
 
 struct {
@@ -72,7 +74,7 @@ int prefixcount;
 
 
 static int      addsubunit(char *[], char *);
-static int      addunit(struct unittype *, char *, int);
+static int      addunit(struct unittype *, char *, int, int);
 static void     cancelunit(struct unittype *);
 static int      compare(const void *, const void *);
 static int      compareproducts(char **, char **);
@@ -207,8 +209,10 @@ readunits(const char *userfile)
 void 
 initializeunit(struct unittype * theunit)
 {
-       theunit->factor = 1.0;
        theunit->numerator[0] = theunit->denominator[0] = NULL;
+       theunit->factor = 1.0;
+       theunit->offset = 0.0;
+       theunit->quantity = 0;
 }
 
 
@@ -237,6 +241,8 @@ showunit(struct unittype * theunit)
        int counter = 1;
 
        printf("\t%.8g", theunit->factor);
+       if (theunit->offset)
+               printf("&%.8g", theunit->offset);
        for (ptr = theunit->numerator; *ptr; ptr++) {
                if (ptr > theunit->numerator && **ptr &&
                    !strcmp(*ptr, *(ptr - 1)))
@@ -284,16 +290,17 @@ zeroerror(void)
 /*
    Adds the specified string to the unit.
    Flip is 0 for adding normally, 1 for adding reciprocal.
+   Quantity is 1 if this is a quantity to be converted rather than a pure unit.
 
    Returns 0 for successful addition, nonzero on error.
 */
 
 int 
-addunit(struct unittype * theunit, char *toadd, int flip)
+addunit(struct unittype * theunit, char *toadd, int flip, int quantity)
 {
        char *scratch, *savescr;
        char *item;
-       char *divider, *slash;
+       char *divider, *slash, *offset;
        int doingtop;
 
        if (!strlen(toadd))
@@ -313,7 +320,17 @@ addunit(struct unittype * theunit, char *toadd, int flip)
                item = strtok(scratch, " *\t\n/");
                while (item) {
                        if (strchr("0123456789.", *item)) { /* item is a number */
-                               double num;
+                               double num, offsetnum;
+
+                               if (quantity)
+                                       theunit->quantity = 1;
+
+                               offset = strchr(item, '&');
+                               if (offset) {
+                                       *offset = 0;
+                                       offsetnum = atof(offset+1);
+                               } else
+                                       offsetnum = 0.0;
 
                                divider = strchr(item, '|');
                                if (divider) {
@@ -323,19 +340,25 @@ addunit(struct unittype * theunit, char *toadd, int flip)
                                                zeroerror();
                                                return 1;
                                        }
-                                       if (doingtop ^ flip)
+                                       if (doingtop ^ flip) {
                                                theunit->factor *= num;
-                                       else
+                                               theunit->offset *= num;
+                                       } else {
                                                theunit->factor /= num;
+                                               theunit->offset /= num;
+                                       }
                                        num = atof(divider + 1);
                                        if (!num) {
                                                zeroerror();
                                                return 1;
                                        }
-                                       if (doingtop ^ flip)
+                                       if (doingtop ^ flip) {
                                                theunit->factor /= num;
-                                       else
+                                               theunit->offset /= num;
+                                       } else {
                                                theunit->factor *= num;
+                                               theunit->offset *= num;
+                                       }
                                }
                                else {
                                        num = atof(item);
@@ -343,12 +366,16 @@ addunit(struct unittype * theunit, char *toadd, int flip)
                                                zeroerror();
                                                return 1;
                                        }
-                                       if (doingtop ^ flip)
+                                       if (doingtop ^ flip) {
                                                theunit->factor *= num;
-                                       else
+                                               theunit->offset *= num;
+                                       } else {
                                                theunit->factor /= num;
-
+                                               theunit->offset /= num;
+                                       }
                                }
+                               if (doingtop ^ flip)
+                                       theunit->offset += offsetnum;
                        }
                        else {  /* item is not a number */
                                int repeat = 1;
@@ -534,7 +561,7 @@ reduceproduct(struct unittype * theunit, int flip)
                                free(*product);
                                *product = NULLUNIT;
                        }
-                       if (addunit(theunit, toadd, flip))
+                       if (addunit(theunit, toadd, flip, 0))
                                return ERROR;
                }
        }
@@ -613,6 +640,20 @@ showanswer(struct unittype * have, struct unittype * want)
                showunit(have);
                showunit(want);
        }
+       else if (have->offset != want->offset) {
+               if (want->quantity)
+                       printf("WARNING: conversion of non-proportional quantities.\n");
+               printf("\t");
+               if (have->quantity)
+                       printf("%.8g\n",
+                           (have->factor + have->offset-want->offset)/want->factor);
+               else
+                       printf(" (-> x*%.8g %+.8g)\n\t (<- y*%.8g %+.8g)\n",
+                           have->factor / want->factor,
+                           (have->offset-want->offset)/want->factor,
+                           want->factor / have->factor,
+                           (want->offset - have->offset)/have->factor);
+       }
        else
                printf("\t* %.8g\n\t/ %.8g\n", have->factor / want->factor,
                    want->factor / have->factor);
@@ -666,10 +707,10 @@ main(int argc, char **argv)
                strlcpy(havestr, argv[optind], sizeof(havestr));
                strlcpy(wantstr, argv[optind + 1], sizeof(wantstr));
                initializeunit(&have);
-               addunit(&have, havestr, 0);
+               addunit(&have, havestr, 0, 1);
                completereduce(&have);
                initializeunit(&want);
-               addunit(&want, wantstr, 0);
+               addunit(&want, wantstr, 0, 1);
                completereduce(&want);
                showanswer(&have, &want);
        }
@@ -687,7 +728,7 @@ main(int argc, char **argv)
                                                putchar('\n');
                                        exit(0);
                                }
-                       } while (addunit(&have, havestr, 0) ||
+                       } while (addunit(&have, havestr, 0, 1) ||
                            completereduce(&have));
                        do {
                                initializeunit(&want);
@@ -698,7 +739,7 @@ main(int argc, char **argv)
                                                putchar('\n');
                                        exit(0);
                                }
-                       } while (addunit(&want, wantstr, 0) ||
+                       } while (addunit(&want, wantstr, 0, 1) ||
                            completereduce(&want));
                        showanswer(&have, &want);
                }
index 8e247fb..47e2616 100644 (file)
@@ -1,5 +1,4 @@
-/ $FreeBSD: src/usr.bin/units/units.lib,v 1.18 2008/08/07 05:35:01 edwin Exp $
-/ $DragonFly: src/usr.bin/units/units.lib,v 1.4 2008/08/12 09:28:22 matthias Exp $
+/ $FreeBSD: src/usr.bin/units/units.lib,v 1.19 2008/08/16 16:27:41 dwmalone Exp $
 
 / primitive units
 
@@ -672,14 +671,14 @@ Xunit                     1.00206e-13 m
 k                      1.38047e-16 erg/degC
 
 
-degC                   K
+degC                   1&+273.15 K
 kelvin                 K
 brewster               1e-12 m2/newton
-degF                   5|9 degC
-degreesrankine         degF
+degF                   5|9&255.37222222222222222222 K
+degreesrankine         5|9 K
 degrankine             degreesrankine
-degreerankine          degF
-degreaumur             10|8 degC
+degreerankine          degreesrankine
+degreaumur             10|8&+273.15 K
 drachm                 60 grain
 poncelet               100 kg m g / sec
 denier                 .05|450 gram / m