summaryrefslogtreecommitdiff
path: root/cups/pwg-media.c
diff options
context:
space:
mode:
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>2013-05-23 19:57:17 +0000
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>2013-05-23 19:57:17 +0000
commit4fcfa0cf96808fcf7893cb89350105fc821eaf5d (patch)
tree5e9d862d4ae4c82ad633f1aa1d4ff3d2569e8072 /cups/pwg-media.c
parentee8d237de0d3e4eb9fc67460c3f400e6859ee1fa (diff)
downloadcups-4fcfa0cf96808fcf7893cb89350105fc821eaf5d.tar.gz
<rdar://problem/13493241> APVT3.0 checks a custom size using a 1/100mm smaller size
Don't use floating point at all. Go old-school and do integer math to convert to 100ths of millimeters... git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@10988 a1ca3aef-8c08-0410-bb20-df032aa958be
Diffstat (limited to 'cups/pwg-media.c')
-rw-r--r--cups/pwg-media.c201
1 files changed, 141 insertions, 60 deletions
diff --git a/cups/pwg-media.c b/cups/pwg-media.c
index 1272e7617..3a4cb9709 100644
--- a/cups/pwg-media.c
+++ b/cups/pwg-media.c
@@ -29,6 +29,7 @@
* pwg_compare_pwg() - Compare two sizes using the PWG names.
* pwg_format_inches() - Convert and format PWG units as inches.
* pwg_format_millimeters() - Convert and format PWG units as millimeters.
+ * pwg_scan_measurement() - Scan a measurement in inches or millimeters.
*/
/*
@@ -56,6 +57,8 @@ static int pwg_compare_pwg(pwg_media_t *a, pwg_media_t *b);
static int pwg_compare_ppd(pwg_media_t *a, pwg_media_t *b);
static char *pwg_format_inches(char *buf, size_t bufsize, int val);
static char *pwg_format_millimeters(char *buf, size_t bufsize, int val);
+static int pwg_scan_measurement(const char *buf, char **bufptr, int numer,
+ int denom);
/*
@@ -706,72 +709,96 @@ pwgMediaForPPD(const char *ppd) /* I - PPD size name */
* [Custom.]WIDTHxLENGTHpt[.FullBleed] - Size in points [borderless]
*/
- double w, l, /* Width and length of page */
- factor; /* Unit scaling factor */
+ int w, l, /* Width and length of page */
+ numer, /* Unit scaling factor */
+ denom; /* ... */
char *ptr; /* Pointer into name */
- struct lconv *loc; /* Locale data */
+ const char *units; /* Pointer to units */
int custom; /* Custom page size? */
+
if (!_cups_strncasecmp(ppd, "Custom.", 7))
{
custom = 1;
- factor = 2540.0 / 72.0;
+ numer = 2540;
+ denom = 72;
ptr = (char *)ppd + 7;
}
else
{
custom = 0;
- factor = 2540.0;
+ numer = 2540;
+ denom = 1;
ptr = (char *)ppd;
}
- loc = localeconv();
- w = _cupsStrScand(ptr, &ptr, loc);
+ /*
+ * Find any units in the size...
+ */
- if (ptr && ptr > ppd && *ptr == 'x')
+ units = strchr(ptr, '.');
+ while (units && isdigit(units[1] & 255))
+ units = strchr(units + 1, '.');
+
+ if (units)
+ units -= 2;
+ else
+ units = ptr + strlen(ptr) - 2;
+
+ if (units > ptr)
{
- l = _cupsStrScand(ptr + 1, &ptr, loc);
-
- if (ptr &&
- (!*ptr ||
- !_cups_strcasecmp(ptr, "FullBleed") ||
- !_cups_strcasecmp(ptr, ".FullBleed") ||
- !_cups_strcasecmp(ptr, "cm") ||
- !_cups_strcasecmp(ptr, "cm.FullBleed") ||
- !_cups_strcasecmp(ptr, "ft") ||
- !_cups_strcasecmp(ptr, "ft.FullBleed") ||
- !_cups_strcasecmp(ptr, "in") ||
- !_cups_strcasecmp(ptr, "in.FullBleed") ||
- !_cups_strcasecmp(ptr, "m") ||
- !_cups_strcasecmp(ptr, "m.FullBleed") ||
- !_cups_strcasecmp(ptr, "mm") ||
- !_cups_strcasecmp(ptr, "mm.FullBleed") ||
- !_cups_strcasecmp(ptr, "pt") ||
- !_cups_strcasecmp(ptr, "pt.FullBleed")))
+ if (isdigit(*units & 255) || *units == '.')
+ units ++;
+
+ if (!_cups_strncasecmp(units, "cm", 2))
+ {
+ numer = 1000;
+ denom = 1;
+ }
+ else if (!_cups_strncasecmp(units, "ft", 2))
+ {
+ numer = 2540 * 12;
+ denom = 1;
+ }
+ else if (!_cups_strncasecmp(units, "in", 2))
+ {
+ numer = 2540;
+ denom = 1;
+ }
+ else if (!_cups_strncasecmp(units, "mm", 2))
+ {
+ numer = 100;
+ denom = 1;
+ }
+ else if (*units == 'm' || *units == 'M')
{
- size = &(cg->pwg_media);
-
- if (!_cups_strncasecmp(ptr, "cm", 2))
- factor = 1000.0;
- else if (!_cups_strncasecmp(ptr, "ft", 2))
- factor = 2540.0 * 12.0;
- else if (!_cups_strncasecmp(ptr, "in", 2))
- factor = 2540.0;
- else if (!_cups_strncasecmp(ptr, "mm", 2))
- factor = 100.0;
- else if (*ptr == 'm' || *ptr == 'M')
- factor = 100000.0;
- else if (!_cups_strncasecmp(ptr, "pt", 2))
- factor = 2540.0 / 72.0;
+ numer = 100000;
+ denom = 1;
+ }
+ else if (!_cups_strncasecmp(units, "pt", 2))
+ {
+ numer = 2540;
+ denom = 72;
+ }
+ }
+
+ w = pwg_scan_measurement(ptr, &ptr, numer, denom);
+
+ if (ptr && ptr > ppd && *ptr == 'x')
+ {
+ l = pwg_scan_measurement(ptr + 1, &ptr, numer, denom);
+ if (ptr)
+ {
/*
* Not a standard size; convert it to a PWG custom name of the form:
*
* [oe|om]_WIDTHxHEIGHTuu_WIDTHxHEIGHTuu
*/
- size->width = (int)(w * factor);
- size->length = (int)(l * factor);
+ size = &(cg->pwg_media);
+ size->width = w;
+ size->length = l;
size->pwg = cg->pwg_name;
pwgFormatSizeName(cg->pwg_name, sizeof(cg->pwg_name),
@@ -851,31 +878,29 @@ pwgMediaForPWG(const char *pwg) /* I - PWG size name */
* class_name_WWWxHHHmm
*/
- double w, l; /* Width and length of page */
- struct lconv *loc; /* Locale data */
+ int w, l; /* Width and length of page */
+ int numer; /* Scale factor for units */
+ const char *units = ptr + strlen(ptr) - 2;
+ /* Units from size */
ptr ++;
- loc = localeconv();
- w = _cupsStrScand(ptr, &ptr, loc);
+
+ if (units >= ptr && !strcmp(units, "in"))
+ numer = 2540;
+ else
+ numer = 100;
+
+ w = pwg_scan_measurement(ptr, &ptr, numer, 1);
if (ptr && *ptr == 'x')
{
- l = _cupsStrScand(ptr + 1, &ptr, loc);
+ l = pwg_scan_measurement(ptr + 1, &ptr, numer, 1);
- if (ptr && (!strcmp(ptr, "in") || !strcmp(ptr, "mm")))
+ if (ptr)
{
- size = &(cg->pwg_media);
-
- if (!strcmp(ptr, "mm"))
- {
- size->width = (int)(w * 100 + 0.5);
- size->length = (int)(l * 100 + 0.5);
- }
- else
- {
- size->width = (int)(w * 2540 + 0.5);
- size->length = (int)(l * 2540 + 0.5);
- }
+ size = &(cg->pwg_media);
+ size->width = w;
+ size->length = l;
strlcpy(cg->pwg_name, pwg, sizeof(cg->pwg_name));
size->pwg = cg->pwg_name;
@@ -1092,5 +1117,61 @@ pwg_format_millimeters(char *buf, /* I - Buffer */
/*
+ * 'pwg_scan_measurement()' - Scan a measurement in inches or millimeters.
+ *
+ * The "factor" argument specifies the scale factor for the units to convert to
+ * hundredths of millimeters. The returned value is NOT rounded but is an
+ * exact conversion of the fraction value (no floating point is used).
+ */
+
+static int /* O - Hundredths of millimeters */
+pwg_scan_measurement(
+ const char *buf, /* I - Number string */
+ char **bufptr, /* O - First byte after the number */
+ int numer, /* I - Numerator from units */
+ int denom) /* I - Denominator from units */
+{
+ int value = 0, /* Measurement value */
+ divisor = 1, /* Fractional divisor */
+ digits = 10 * numer * denom; /* Maximum fractional value to read */
+
+
+ /*
+ * Scan integer portion...
+ */
+
+ while (*buf >= '0' && *buf <= '9')
+ value = value * 10 + (*buf++) - '0';
+
+ if (*buf == '.')
+ {
+ /*
+ * Scan fractional portion...
+ */
+
+ buf ++;
+
+ while (divisor < digits && *buf >= '0' && *buf <= '9')
+ {
+ value = value * 10 + (*buf++) - '0';
+ divisor *= 10;
+ }
+
+ /*
+ * Skip trailing digits that won't contribute...
+ */
+
+ while (*buf >= '0' && *buf <= '9')
+ buf ++;
+ }
+
+ if (bufptr)
+ *bufptr = (char *)buf;
+
+ return (value * numer / denom / divisor);
+}
+
+
+/*
* End of "$Id$".
*/