/*
* Copyright (c) 2009-2011 Hypertriton, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include
#include
#include
#include
#include
#include
#include
struct drillsize {
const char *name;
double v;
};
#include "drills_letter.h"
#include "drills_wireno.h"
int Rflag = 0;
int Pflag = 0;
int Pangle = 0;
double inches = 0.0;
const int maxFrac = 64;
int undersize = 0;
int oversize = 0;
static void
printusage(void)
{
extern char *__progname;
printf("Usage: %s [-ouR] [-p angle] "
"[-i inches] | [-l letter] | [-m mm] | [-w wireno]\n",
__progname);
exit(1);
}
static char *
lookuptbl(double in, const struct drillsize *tbl, int n)
{
const struct drillsize *ds, *dsNear;
char *s;
int i;
if ((s = malloc(64)) == NULL) {
return (NULL);
}
s[0] = '-';
s[1] = '\0';
if (undersize) {
for (i = 0; i < n; i++) {
ds = &tbl[i];
if (i > 0 && ds->v >= in) {
dsNear = &tbl[i-1];
snprintf(s, 64, "%s (%.04f) -%.04f (undersize)",
dsNear->name, dsNear->v,
fabs(in - dsNear->v));
break;
}
}
} else if (oversize) {
for (i = n-1; i > 0; i--) {
ds = &tbl[i];
if (i < n-1 && ds->v <= in) {
dsNear = &tbl[i+1];
snprintf(s, 64, "%s (%.04f) +%.04f (oversize)",
dsNear->name, dsNear->v,
fabs(dsNear->v - in));
break;
}
}
} else {
for (i = 0; i < n; i++) {
ds = &tbl[i];
if (fabs(ds->v - in) < 0.001) {
strlcpy(s, ds->name, 64);
break;
}
}
}
return (s);
}
static double
lookup_wireno(const char *s)
{
int i;
for (i = 0; i < ndrills_wireno; i++) {
const struct drillsize *ds = &drills_wireno[i];
if (strcasecmp(ds->name, s) == 0)
return (ds->v);
}
return (0.0);
}
static double
lookup_letter(const char *s)
{
int i;
for (i = 0; i < ndrills_letter; i++) {
const struct drillsize *ds = &drills_letter[i];
if (strcasecmp(ds->name, s) == 0)
return (ds->v);
}
return (0.0);
}
static char *
nearest_fractional(double inches)
{
int ths = 2, thsNearest = 999, iNearest = 999, i;
double errNearest = HUGE_VAL;
double nearest = HUGE_VAL;
double d;
char *s;
if (inches == 1.0) {
return strdup("1");
}
if ((s = malloc(64)) == NULL) {
return (NULL);
}
s[0] = '\0';
for (ths = 2; ths <= maxFrac; ths *= 2) {
for (i = 1; i < ths; i++) {
d = (double)i/(double)ths;
if (fabs(inches - d) < errNearest) {
errNearest = fabs(inches - d);
nearest = d;
iNearest = i;
thsNearest = ths;
}
}
}
if (errNearest < 0.0001) {
snprintf(s, 64, "%d/%d (%.04f)", iNearest, thsNearest,
nearest);
} else if (nearest > inches) {
snprintf(s, 64, "%d/%d (%.04f) -%.04f",
iNearest, thsNearest, nearest, errNearest);
} else {
snprintf(s, 64, "%d/%d (%.04f) +%.04f",
iNearest, thsNearest, nearest, errNearest);
}
return (s);
}
static double
parse_inches(const char *in)
{
char *s, *ep;
double v;
if ((s = strchr(in, '/')) != NULL) {
int num = atoi(in);
int den = atoi(s+1);
if (s == '\0' || den == 0)
errx(1, "-i: invalid fraction");
v = (double)num/(double)den;
} else {
v = strtod(in, &ep);
if (in[0] == '\0' || *ep != '\0')
errx(1, "-i: invalid value");
}
return (v);
}
int
main(int argc, char *argv[])
{
char *ep, *s, c, ch;
const char *err;
char *letter = NULL, *wireno = NULL;
int pt, i;
while ((ch = getopt(argc, argv, "ouRp:i:l:m:w:?h")) != -1) {
switch (ch) {
case 'u':
undersize = 1;
break;
case 'o':
if (undersize) {
errx(1, "-u and -o are mutually exclusive");
}
oversize = 1;
break;
case 'R':
Rflag = 1;
break;
case 'p':
Pflag = 1;
Pangle = (int)strtonum(optarg, 1, 180, &err);
if (err != NULL) { errx(1, "-p: %s", err); }
break;
case 'i':
inches = parse_inches(optarg);
break;
case 'l':
if ((c = optarg[0]) != '\0' && optarg[1] == '\0' &&
toupper(c) >= 65 && toupper(c) <= 90) {
letter = strdup(optarg);
} else {
errx(1, "-l: invalid letter drill size");
}
break;
case 'w':
wireno = strdup(optarg);
break;
case 'm':
inches = strtod(optarg,&ep)/25.4;
if (optarg[0] == '\0' || *ep != '\0') {
errx(1, "-i: invalid value");
}
break;
default:
printusage();
}
}
argc -= optind;
argv += optind;
if (argc > 0)
inches = parse_inches(argv[0]);
if (wireno) {
inches = lookup_wireno(wireno);
} else if (letter) {
inches = lookup_letter(letter);
} else {
if (inches == 0.0)
printusage();
}
printf("Inches: %.4f\n", inches);
printf("Fractional: %s\n", nearest_fractional(inches));
printf("Wire no.: %s\n", lookuptbl(inches, drills_wireno, ndrills_wireno));
printf("Letter: %s\n", lookuptbl(inches, drills_letter, ndrills_letter));
printf("Metric: %.02f mm\n", inches*25.4);
return (0);
}