OpenSolaris_b135/cmd/units/units.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
/*	  All Rights Reserved  	*/

/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley Software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <locale.h>
#include <signal.h>

#define	NDIM	10
#define	NTAB	1009
char	*dfile	= "/usr/share/lib/unittab";
char	*unames[NDIM];
struct unit
{
	double	factor;
	char	dim[NDIM];
};

struct table
{
	double	factor;
	char	dim[NDIM];
	char	*name;
} table[NTAB];
char	names[NTAB*10];
struct prefix
{
	double	factor;
	char	*pname;
} prefix[] = 
{
	1e-21,	"zepto",
	1e-24,	"yocto",
	1e-18,	"atto",
	1e-15,	"femto",
	1e-12,	"pico",
	1e-9,	"nano",
	1e-6,	"micro",
	1e-3,	"milli",
	1e-2,	"centi",
	1e-1,	"deci",
	1e1,	"deka",
	1e1,	"deca",
	1e2,	"hecta",
	1e2,	"hecto",
	1e3,	"kilo",
	1e6,	"mega",
	1e6,	"meg",
	1e9,	"giga",
	1e12,	"tera",
	1e15,	"peta",
	1e18,	"exa",
	1e21,	"zetta",
	1e24,	"yotta",
	1<<10,	"kibi",
	1L<<20,	"mebi",
	1L<<30,	"gibi",
	1LL<<40,"tebi",
	0.0,	0
};
FILE	*inp;
int	fperrc;
int	peekc;
int	dumpflg;

void fperr(int sig);
double getflt(void);
struct table *hash(char *name);
int get(void);
void init(void);
int equal(char *s1, char *s2);
int lookup(char *name, struct unit *up, int den, int c);
int convr(struct unit *up);
int pu(int u, int i, int f);
void units(struct unit *up);

int
main(int argc, char *argv[])
{
	int i;
	char *file;
	struct unit u1, u2;
	double f;
	
	(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
        (void) textdomain(TEXT_DOMAIN);

	if(argc>1 && *argv[1]=='-') {
		argc--;
		argv++;
		dumpflg++;
	}
	file = dfile;
	if(argc > 1)
		file = argv[1];
	if ((inp = fopen(file, "r")) == NULL) {
		printf(gettext("no table\n"));
		exit(1);
	}
	signal(8, fperr);
	init();

loop:
	fperrc = 0;
	printf(gettext("you have: "));
	if(convr(&u1))
		goto loop;
	if(fperrc)
		goto fp;
loop1:
	printf(gettext("you want: "));
	if(convr(&u2))
		goto loop1;
	for(i=0; i<NDIM; i++)
		if(u1.dim[i] != u2.dim[i])
			goto conform;
	f = u1.factor/u2.factor;
	if(fperrc || f == 0.0)
		goto fp;
	printf("\t* %e\n", f);
	printf("\t/ %e\n", 1./f);
	goto loop;

conform:
	if(fperrc)
		goto fp;
	printf(gettext("conformability\n"));
	units(&u1);
	units(&u2);
	goto loop;

fp:
	printf(gettext("underflow or overflow\n"));
	goto loop;
}

void
units(struct unit *up)
{
	struct unit *p;
	int f, i;

	p = up;
	printf("\t%e ", p->factor);
	f = 0;
	for(i=0; i<NDIM; i++)
		f |= pu(p->dim[i], i, f);
	if(f&1) {
		putchar('/');
		f = 0;
		for(i=0; i<NDIM; i++)
			f |= pu(-p->dim[i], i, f);
	}
	putchar('\n');
}

int
pu(int u, int i, int f)
{

	if(u > 0) {
		if(f&2)
			putchar('-');
		if(unames[i])
			printf("%s", unames[i]); else
			printf(gettext("*%c*"), i+'a');
		if(u > 1)
			putchar(u+'0');
			return(2);
	}
	if(u < 0)
		return(1);
	return(0);
}

int
convr(struct unit *up)
{
	struct unit *p;
	int c;
	char *cp;
	char name[20];
	int den, err;

	p = up;
	for(c=0; c<NDIM; c++)
		p->dim[c] = 0;
	p->factor = getflt();
	if(p->factor == 0.)
		p->factor = 1.0;
	err = 0;
	den = 0;
	cp = name;

loop:
	switch(c=get()) {

	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	case '-':
	case '/':
	case ' ':
	case '\t':
	case '\n':
		if(cp != name) {
			*cp++ = 0;
			cp = name;
			err |= lookup(cp, p, den, c);
		}
		if(c == '/')
			den++;
		if(c == '\n')
			return(err);
		goto loop;
	}
	*cp++ = c;
	goto loop;
}

int
lookup(char *name, struct unit *up, int den, int c)
{
	struct unit *p;
	struct table *q;
	int i;
	char *cp1, *cp2;
	double e;

	p = up;
	e = 1.0;

loop:
	q = hash(name);
	if(q->name) {
		l1:
		if(den) {
			p->factor /= q->factor*e;
			for(i=0; i<NDIM; i++)
				p->dim[i] -= q->dim[i];
		} else {
			p->factor *= q->factor*e;
			for(i=0; i<NDIM; i++)
				p->dim[i] += q->dim[i];
		}
		if(c >= '2' && c <= '9') {
			c--;
			goto l1;
		}
		return(0);
	}
	for(i=0; cp1 = prefix[i].pname; i++) {
		cp2 = name;
		while(*cp1 == *cp2++)
			if(*cp1++ == 0) {
				cp1--;
				break;
			}
		if(*cp1 == 0) {
			e *= prefix[i].factor;
			name = cp2-1;
			goto loop;
		}
	}
	for(cp1 = name; *cp1; cp1++);
	if(cp1 > name+1 && *--cp1 == 's') {
		*cp1 = 0;
		goto loop;
	}
	printf(gettext("cannot recognize %s\n"), name);
	return(1);
}

int
equal(char *s1, char *s2)
{
	char *c1, *c2;

	c1 = s1;
	c2 = s2;
	while(*c1++ == *c2)
		if(*c2++ == 0)
			return(1);
	return(0);
}

void
init(void)
{
	char *cp;
	struct table *tp, *lp;
	int c, i, f, t;
	char *np;

	cp = names;
	for(i=0; i<NDIM; i++) {
		np = cp;
		*cp++ = '*';
		*cp++ = i+'a';
		*cp++ = '*';
		*cp++ = 0;
		lp = hash(np);
		lp->name = np;
		lp->factor = 1.0;
		lp->dim[i] = 1;
	}
	lp = hash("");
	lp->name = cp-1;
	lp->factor = 1.0;

l0:
	c = get();
	if(c == 0) {
		if(dumpflg) {
		printf(gettext("%d units; %d bytes\n\n"), i, cp-names);
		for(tp = &table[0]; tp < &table[NTAB]; tp++) {
			if(tp->name == 0)
				continue;
			printf("%s", tp->name);
			units((struct unit *)tp);
		} }
		fclose(inp);
		inp = stdin;
		return;
	}
	if(c == '/') {
		while(c != '\n' && c != 0)
			c = get();
		goto l0;
	}
	if(c == '\n')
		goto l0;
	np = cp;
	while(c != ' ' && c != '\t') {
		*cp++ = c;
		c = get();
		if (c==0)
			goto l0;
		if(c == '\n') {
			*cp++ = 0;
			tp = hash(np);
			if(tp->name)
				goto redef;
			tp->name = np;
			tp->factor = lp->factor;
			for(c=0; c<NDIM; c++)
				tp->dim[c] = lp->dim[c];
			i++;
			goto l0;
		}
	}
	*cp++ = 0;
	lp = hash(np);
	if(lp->name)
		goto redef;
	convr((struct unit *)lp);
	lp->name = np;
	f = 0;
	i++;
	if(lp->factor != 1.0)
		goto l0;
	for(c=0; c<NDIM; c++) {
		t = lp->dim[c];
		if(t>1 || (f>0 && t!=0))
			goto l0;
		if(f==0 && t==1) {
			if(unames[c])
				goto l0;
			f = c+1;
		}
	}
	if(f>0)
		unames[f-1] = np;
	goto l0;

redef:
	printf(gettext("redefinition %s\n"), np);
	goto l0;
}

double
getflt(void)
{
	int c, i, dp;
	double d, e;
	int f;

	d = 0.;
	dp = 0;
	do
		c = get();
	while(c == ' ' || c == '\t');

l1:
	if(c >= '0' && c <= '9') {
		d = d*10. + c-'0';
		if(dp)
			dp++;
		c = get();
		goto l1;
	}
	if(c == '.') {
		dp++;
		c = get();
		goto l1;
	}
	if(dp)
		dp--;
	if(c == '+' || c == '-') {
		f = 0;
		if(c == '-')
			f++;
		i = 0;
		c = get();
		while(c >= '0' && c <= '9') {
			i = i*10 + c-'0';
			c = get();
		}
		if(f)
			i = -i;
		dp -= i;
	}
	e = 1.;
	i = dp;
	if(i < 0)
		i = -i;
	while(i--)
		e *= 10.;
	if(dp < 0)
		d *= e; else
		d /= e;
	if(c == '|')
		return(d/getflt());
	peekc = c;
	return(d);
}

int
get(void)
{
	int c;

	if(c=peekc) {
		peekc = 0;
		return(c);
	}
	c = getc(inp);
	if (c == EOF) {
		if (inp == stdin) {
			printf("\n");
			exit(0);
		}
		return(0);
	}
	return(c);
}

struct table *
hash(char *name)
{
	struct table *tp;
	char *np;
	unsigned int h;

	h = 0;
	np = name;
	while(*np)
		h = h*57 + *np++ - '0';
	if( ((int)h)<0) h= -(int)h;
	h %= NTAB;
	tp = &table[h];
l0:
	if(tp->name == 0)
		return(tp);
	if(equal(name, tp->name))
		return(tp);
	tp++;
	if(tp >= &table[NTAB])
		tp = table;
	goto l0;
}

void
fperr(int sig)
{

	signal(8, fperr);
	fperrc++;
}