version 1.8, 2003/06/10 22:20:53 |
version 1.9, 2003/07/02 01:57:15 |
|
|
int unitcount; |
int unitcount; |
int prefixcount; |
int prefixcount; |
|
|
|
char *dupstr(char *); |
|
void readerror(int); |
|
void readunits(char *); |
|
void initializeunit(struct unittype *); |
|
int addsubunit(char *[], char *); |
|
void showunit(struct unittype *); |
|
void zeroerror(void); |
|
int addunit(struct unittype *, char *, int); |
|
int compare(const void *, const void *); |
|
void sortunit(struct unittype *); |
|
void cancelunit(struct unittype *); |
|
char *lookupunit(char *); |
|
int reduceproduct(struct unittype *, int); |
|
int reduceunit(struct unittype *); |
|
int compareproducts(char **, char **); |
|
int compareunits(struct unittype *, struct unittype *); |
|
int completereduce(struct unittype *); |
|
void showanswer(struct unittype *, struct unittype *); |
|
void usage(void); |
|
|
char * |
char * |
dupstr(char *str) |
dupstr(char *str) |
|
|
} |
} |
|
|
|
|
void |
void |
readerror(int linenum) |
readerror(int linenum) |
{ |
{ |
fprintf(stderr, "Error in units file '%s' line %d\n", UNITSFILE, |
fprintf(stderr, "Error in units file '%s' line %d\n", UNITSFILE, |
|
|
} |
} |
|
|
|
|
void |
void |
readunits(char *userfile) |
readunits(char *userfile) |
{ |
{ |
FILE *unitfile; |
|
char line[80], *lineptr; |
char line[80], *lineptr; |
int len, linenum, i; |
int len, linenum, i; |
|
FILE *unitfile; |
|
|
unitcount = 0; |
unitcount = 0; |
linenum = 0; |
linenum = 0; |
|
|
} else { |
} else { |
unitfile = fopen(UNITSFILE, "rt"); |
unitfile = fopen(UNITSFILE, "rt"); |
if (!unitfile) { |
if (!unitfile) { |
|
char filename[1000], separator[2] = SEPERATOR; |
char *direc, *env; |
char *direc, *env; |
char filename[1000]; |
|
char separator[2] = SEPERATOR; |
|
|
|
env = getenv("PATH"); |
env = getenv("PATH"); |
if (env) { |
if (env) { |
|
|
len = strcspn(lineptr, "\n\t"); |
len = strcspn(lineptr, "\n\t"); |
lineptr[len] = 0; |
lineptr[len] = 0; |
prefixtable[prefixcount++].prefixval = dupstr(lineptr); |
prefixtable[prefixcount++].prefixval = dupstr(lineptr); |
} |
} else { /* it's not a prefix */ |
else { /* it's not a prefix */ |
|
if (unitcount == MAXUNITS) { |
if (unitcount == MAXUNITS) { |
fprintf(stderr, |
fprintf(stderr, |
"Memory for units exceeded in line %d\n", |
"Memory for units exceeded in line %d\n", |
|
|
fclose(unitfile); |
fclose(unitfile); |
} |
} |
|
|
void |
void |
initializeunit(struct unittype * theunit) |
initializeunit(struct unittype *theunit) |
{ |
{ |
theunit->factor = 1.0; |
theunit->factor = 1.0; |
theunit->numerator[0] = theunit->denominator[0] = NULL; |
theunit->numerator[0] = theunit->denominator[0] = NULL; |
} |
} |
|
|
|
|
int |
int |
addsubunit(char *product[], char *toadd) |
addsubunit(char *product[], char *toadd) |
{ |
{ |
char **ptr; |
char **ptr; |
|
|
} |
} |
|
|
|
|
void |
void |
showunit(struct unittype * theunit) |
showunit(struct unittype *theunit) |
{ |
{ |
char **ptr; |
char **ptr; |
int printedslash; |
int printedslash; |
|
|
} |
} |
|
|
|
|
void |
void |
zeroerror(void) |
zeroerror(void) |
{ |
{ |
fprintf(stderr, "Unit reduces to zero\n"); |
fprintf(stderr, "Unit reduces to zero\n"); |
|
|
Returns 0 for successful addition, nonzero on error. |
Returns 0 for successful addition, nonzero on error. |
*/ |
*/ |
|
|
int |
int |
addunit(struct unittype * theunit, char *toadd, int flip) |
addunit(struct unittype *theunit, char *toadd, int flip) |
{ |
{ |
char *scratch, *savescr; |
char *scratch, *savescr; |
char *item; |
char *item; |
|
|
theunit->factor /= num; |
theunit->factor /= num; |
else |
else |
theunit->factor *= num; |
theunit->factor *= num; |
} |
} else { |
else { |
|
num = atof(item); |
num = atof(item); |
if (!num) { |
if (!num) { |
zeroerror(); |
zeroerror(); |
|
|
theunit->factor /= num; |
theunit->factor /= num; |
|
|
} |
} |
} |
} else { /* item is not a number */ |
else { /* item is not a number */ |
|
int repeat = 1; |
int repeat = 1; |
|
|
if (strchr("23456789", |
if (strchr("23456789", |
|
|
doingtop--; |
doingtop--; |
if (slash) { |
if (slash) { |
scratch = slash + 1; |
scratch = slash + 1; |
} |
} else |
else |
|
doingtop--; |
doingtop--; |
} while (doingtop >= 0); |
} while (doingtop >= 0); |
free(savescr); |
free(savescr); |
|
|
} |
} |
|
|
|
|
int |
int |
compare(const void *item1, const void *item2) |
compare(const void *item1, const void *item2) |
{ |
{ |
return strcmp(*(char **) item1, *(char **) item2); |
return strcmp(*(char **) item1, *(char **) item2); |
} |
} |
|
|
|
|
void |
void |
sortunit(struct unittype * theunit) |
sortunit(struct unittype *theunit) |
{ |
{ |
char **ptr; |
char **ptr; |
int count; |
int count; |
|
|
} |
} |
|
|
|
|
void |
void |
cancelunit(struct unittype * theunit) |
cancelunit(struct unittype *theunit) |
{ |
{ |
char **den, **num; |
char **den, **num; |
int comp; |
int comp; |
|
|
while (*num && *den) { |
while (*num && *den) { |
comp = strcmp(*den, *num); |
comp = strcmp(*den, *num); |
if (!comp) { |
if (!comp) { |
/* if (*den!=NULLUNIT) free(*den); |
#if 0 |
if (*num!=NULLUNIT) free(*num);*/ |
if (*den!=NULLUNIT) |
|
free(*den); |
|
if (*num!=NULLUNIT) |
|
free(*num); |
|
#endif |
*den++ = NULLUNIT; |
*den++ = NULLUNIT; |
*num++ = NULLUNIT; |
*num++ = NULLUNIT; |
} |
} else if (comp < 0) |
else if (comp < 0) |
|
den++; |
den++; |
else |
else |
num++; |
num++; |
|
|
|
|
#define ERROR 4 |
#define ERROR 4 |
|
|
int |
int |
reduceproduct(struct unittype * theunit, int flip) |
reduceproduct(struct unittype *theunit, int flip) |
{ |
{ |
|
char *toadd, **product; |
char *toadd; |
|
char **product; |
|
int didsomething = 2; |
int didsomething = 2; |
|
|
if (flip) |
if (flip) |
|
|
Returns 0 on success, or 1 on unknown unit error. |
Returns 0 on success, or 1 on unknown unit error. |
*/ |
*/ |
|
|
int |
int |
reduceunit(struct unittype * theunit) |
reduceunit(struct unittype *theunit) |
{ |
{ |
int ret; |
int ret; |
|
|
|
|
} |
} |
|
|
|
|
int |
int |
compareproducts(char **one, char **two) |
compareproducts(char **one, char **two) |
{ |
{ |
while (*one || *two) { |
while (*one || *two) { |
|
|
|
|
/* Return zero if units are compatible, nonzero otherwise */ |
/* Return zero if units are compatible, nonzero otherwise */ |
|
|
int |
int |
compareunits(struct unittype * first, struct unittype * second) |
compareunits(struct unittype *first, struct unittype *second) |
{ |
{ |
return |
return compareproducts(first->numerator, second->numerator) || |
compareproducts(first->numerator, second->numerator) || |
compareproducts(first->denominator, second->denominator); |
compareproducts(first->denominator, second->denominator); |
|
} |
} |
|
|
|
|
int |
int |
completereduce(struct unittype * unit) |
completereduce(struct unittype *unit) |
{ |
{ |
if (reduceunit(unit)) |
if (reduceunit(unit)) |
return 1; |
return 1; |
|
|
} |
} |
|
|
|
|
void |
void |
showanswer(struct unittype * have, struct unittype * want) |
showanswer(struct unittype *have, struct unittype *want) |
{ |
{ |
if (compareunits(have, want)) { |
if (compareunits(have, want)) { |
printf("conformability error\n"); |
printf("conformability error\n"); |
showunit(have); |
showunit(have); |
showunit(want); |
showunit(want); |
} |
} else |
else |
|
printf("\t* %.8g\n\t/ %.8g\n", have->factor / want->factor, |
printf("\t* %.8g\n\t/ %.8g\n", have->factor / want->factor, |
want->factor / have->factor); |
want->factor / have->factor); |
} |
} |
|
|
|
|
void |
void |
usage(void) |
usage(void) |
{ |
{ |
fprintf(stderr, "units [-f unitsfile] [-q] [-v] [from-unit to-unit]\n"); |
fprintf(stderr, "units [-f unitsfile] [-q] [-v] [from-unit to-unit]\n"); |
|
|
addunit(&want, wantstr, 0); |
addunit(&want, wantstr, 0); |
completereduce(&want); |
completereduce(&want); |
showanswer(&have, &want); |
showanswer(&have, &want); |
} |
} else { |
else { |
|
if (!quiet) |
if (!quiet) |
printf("%d units, %d prefixes\n", unitcount, |
printf("%d units, %d prefixes\n", unitcount, |
prefixcount); |
prefixcount); |