Index: cups/emit.c =================================================================== --- cups/emit.c (revision 5237) +++ cups/emit.c (working copy) @@ -32,10 +32,12 @@ * ppdCollect2() - Collect all marked options that reside in the * specified section and minimum order. * ppdEmit() - Emit code for marked options to a file. - * ppdEmitAfterOrder() - Emit a subset of the code for marked options to a file. + * ppdEmitAfterOrder() - Emit a subset of the code for marked options to a + * file. * ppdEmitFd() - Emit code for marked options to a file. * ppdEmitJCL() - Emit code for JCL options to a file. * ppdEmitJCLEnd() - Emit JCLEnd code to a file. + * ppdEmitString() - Get a string containing the code for marked options. * ppd_handle_media() - Handle media selection... * ppd_sort() - Sort options by ordering numbers... */ @@ -47,6 +49,7 @@ #include "ppd.h" #include #include "string.h" +#include #if defined(WIN32) || defined(__EMX__) # include @@ -200,268 +203,40 @@ ppd_file_t *ppd, /* I - PPD file record */ FILE *fp, /* I - File to write to */ ppd_section_t section, /* I - Section to write */ - int limit, /* I - Non-zero to use min_order, 0 to include all */ - float min_order) /* I - Lowest order dependency to include */ + int limit, /* I - Non-zero to use min_order */ + float min_order) /* I - Lowest OrderDependency */ { - int i, /* Looping var */ - count; /* Number of choices */ - ppd_choice_t **choices; /* Choices */ - ppd_size_t *size; /* Custom page size */ + char *buffer; /* Option code */ + int status; /* Return status */ /* - * Use PageSize or PageRegion as required... + * Range check input... */ - ppd_handle_media(ppd); + if (!ppd || !fp) + return (-1); /* - * Collect the options we need to emit and emit them! + * Get the string... */ - if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0) - return (0); + buffer = ppdEmitString(ppd, section, min_order); - for (i = 0; i < count; i ++) - if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL) - { - /* - * Send wrapper commands to prevent printer errors for unsupported - * options... - */ + /* + * Write it as needed and return... + */ - if (fputs("[{\n", fp) < 0) - { - free(choices); - return (-1); - } + if (buffer) + { + status = fputs(buffer, fp) < 0 ? -1 : 0; - /* - * Send DSC comments with option... - */ + free(buffer); + } + else + status = 0; - if ((!strcasecmp(choices[i]->option->keyword, "PageSize") || - !strcasecmp(choices[i]->option->keyword, "PageRegion")) && - !strcasecmp(choices[i]->choice, "Custom")) - { - /* - * Variable size; write out standard size options, using the - * parameter positions defined in the PPD file... - */ - - ppd_attr_t *attr; /* PPD attribute */ - int pos, /* Position of custom value */ - orientation; /* Orientation to use */ - float values[5]; /* Values for custom command */ - int isfloat[5]; /* Whether each value is float or int */ - - fputs("%%BeginFeature: *CustomPageSize True\n", fp); - - size = ppdPageSize(ppd, "Custom"); - - memset(values, 0, sizeof(values)); - memset(isfloat, 0, sizeof(isfloat)); - - if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL) - { - pos = atoi(attr->value) - 1; - - if (pos < 0 || pos > 4) - pos = 0; - } - else - pos = 0; - - values[pos] = size->width; - isfloat[pos] = 1; - - if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL) - { - pos = atoi(attr->value) - 1; - - if (pos < 0 || pos > 4) - pos = 1; - } - else - pos = 1; - - values[pos] = size->length; - isfloat[pos] = 1; - - /* - * According to the Adobe PPD specification, an orientation of 1 - * will produce a print that comes out upside-down with the X - * axis perpendicular to the direction of feed, which is exactly - * what we want to be consistent with non-PS printers. - * - * We could also use an orientation of 3 to produce output that - * comes out rightside-up (this is the default for many large format - * printer PPDs), however for consistency we will stick with the - * value 1. - * - * If we wanted to get fancy, we could use orientations of 0 or - * 2 and swap the width and length, however we don't want to get - * fancy, we just want it to work consistently. - * - * The orientation value is range limited by the Orientation - * parameter definition, so certain non-PS printer drivers that - * only support an Orientation of 0 will get the value 0 as - * expected. - */ - - orientation = 1; - - if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", - "Orientation")) != NULL) - { - int min_orient, max_orient; /* Minimum and maximum orientations */ - - - if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient, - &max_orient) != 3) - pos = 4; - else - { - pos --; - - if (pos < 0 || pos > 4) - pos = 4; - - if (orientation > max_orient) - orientation = max_orient; - else if (orientation < min_orient) - orientation = min_orient; - } - } - else - pos = 4; - - values[pos] = orientation; - - for (pos = 0; pos < 5; pos ++) - if (isfloat[pos]) - fprintf(fp, "%.2f\n", values[pos]); - else - fprintf(fp, "%.0f\n", values[pos]); - - if (choices[i]->code == NULL) - { - /* - * This can happen with certain buggy PPD files that don't include - * a CustomPageSize command sequence... We just use a generic - * Level 2 command sequence... - */ - - fputs(ppd_custom_code, fp); - } - } - else if (!strcasecmp(choices[i]->choice, "Custom")) - { - /* - * Custom option... - */ - - ppd_coption_t *coption; /* Custom option */ - ppd_cparam_t *cparam; /* Custom parameter */ - const char *s; /* Pointer into string value */ - - - /* - * TODO: Support custom options with more than 1 parameter... - */ - - if ((coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) - != NULL && - (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) != NULL) - { - if (fprintf(fp, "%%%%BeginFeature: *Custom%s True\n", - coption->keyword) < 0) - { - free(choices); - return (-1); - } - - switch (cparam->type) - { - case PPD_CUSTOM_CURVE : - case PPD_CUSTOM_INVCURVE : - case PPD_CUSTOM_POINTS : - case PPD_CUSTOM_REAL : - if (fprintf(fp, "%f\n", cparam->current.custom_real) < 0) - { - free(choices); - return (-1); - } - break; - - case PPD_CUSTOM_INT : - if (fprintf(fp, "%d\n", cparam->current.custom_int) < 0) - { - free(choices); - return (-1); - } - break; - - case PPD_CUSTOM_PASSCODE : - case PPD_CUSTOM_PASSWORD : - case PPD_CUSTOM_STRING : - putc('(', fp); - - for (s = cparam->current.custom_string; *s; s ++) - if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127) - fprintf(fp, "\\%03o", *s & 255); - else - putc(*s, fp); - - if (fputs(")\n", fp) < 0) - { - free(choices); - return (-1); - } - break; - } - } - } - else if (fprintf(fp, "%%%%BeginFeature: *%s %s\n", - choices[i]->option->keyword, - choices[i]->choice) < 0) - { - free(choices); - return (-1); - } - - if (choices[i]->code != NULL && choices[i]->code[0] != '\0') - { - if (fputs(choices[i]->code, fp) < 0) - { - free(choices); - return (-1); - } - - if (choices[i]->code[strlen(choices[i]->code) - 1] != '\n') - putc('\n', fp); - } - - if (fputs("%%EndFeature\n", fp) < 0) - { - free(choices); - return (-1); - } - - if (fputs("} stopped cleartomark\n", fp) < 0) - { - free(choices); - return (-1); - } - } - else if (fputs(choices[i]->code, fp) < 0) - { - free(choices); - return (-1); - } - - free(choices); - return (0); + return (status); } @@ -474,194 +249,58 @@ int fd, /* I - File to write to */ ppd_section_t section) /* I - Section to write */ { - int i, /* Looping var */ - count, /* Number of choices */ - custom_size; /* Non-zero if this option is a custom size */ - ppd_choice_t **choices; /* Choices */ - ppd_size_t *size; /* Custom page size */ - char buf[1024]; /* Output buffer for feature */ + char *buffer, /* Option code */ + *bufptr; /* Pointer into code */ + size_t buflength; /* Length of option code */ + ssize_t bytes; /* Bytes written */ + int status; /* Return status */ /* - * Use PageSize or PageRegion as required... + * Range check input... */ - ppd_handle_media(ppd); + if (!ppd || fd < 0) + return (-1); /* - * Collect the options we need to emit and emit them! + * Get the string... */ - if ((count = ppdCollect(ppd, section, &choices)) == 0) - return (0); + buffer = ppdEmitString(ppd, section, 0.0); - for (i = 0; i < count; i ++) - if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL) - { - /* - * Send wrapper commands to prevent printer errors for unsupported - * options... - */ + /* + * Write it as needed and return... + */ - if (write(fd, "[{\n", 3) < 1) - { - free(choices); - return (-1); - } + if (buffer) + { + buflength = strlen(buffer); + bufptr = buffer; + bytes = 0; - /* - * Send DSC comments with option... - */ - - if ((!strcasecmp(choices[i]->option->keyword, "PageSize") || - !strcasecmp(choices[i]->option->keyword, "PageRegion")) && - !strcasecmp(choices[i]->choice, "Custom")) + while (buflength > 0) + { + if ((bytes = write(fd, bufptr, buflength)) < 0) { - custom_size = 1; + if (errno == EAGAIN || errno == EINTR) + continue; - strcpy(buf, "%%BeginFeature: *CustomPageSize True\n"); + break; } - else - { - custom_size = 0; - snprintf(buf, sizeof(buf), "%%%%BeginFeature: *%s %s\n", - choices[i]->option->keyword, choices[i]->choice); - } + buflength -= bytes; + bufptr += bytes; + } - if (write(fd, buf, strlen(buf)) < 1) - { - free(choices); - return (-1); - } + status = bytes < 0 ? -1 : 0; - if (custom_size) - { - /* - * Variable size; write out standard size options, using the - * parameter positions defined in the PPD file... - */ + free(buffer); + } + else + status = 0; - ppd_attr_t *attr; /* PPD attribute */ - int pos, /* Position of custom value */ - values[5], /* Values for custom command */ - orientation; /* Orientation to use */ - - - size = ppdPageSize(ppd, "Custom"); - - memset(values, 0, sizeof(values)); - - if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL) - { - pos = atoi(attr->value) - 1; - - if (pos < 0 || pos > 4) - pos = 0; - } - else - pos = 0; - - values[pos] = (int)size->width; - - if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL) - { - pos = atoi(attr->value) - 1; - - if (pos < 0 || pos > 4) - pos = 1; - } - else - pos = 1; - - values[pos] = (int)size->length; - - if (size->width < size->length) - orientation = 1; - else - orientation = 0; - - if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", - "Orientation")) != NULL) - { - int min_orient, max_orient; /* Minimum and maximum orientations */ - - - if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient, - &max_orient) != 3) - pos = 4; - else - { - pos --; - - if (pos < 0 || pos > 4) - pos = 4; - - if (orientation > max_orient) - orientation = max_orient; - else if (orientation < min_orient) - orientation = min_orient; - } - } - else - pos = 4; - - values[pos] = orientation; - - snprintf(buf, sizeof(buf), "%d %d %d %d %d\n", values[0], values[1], - values[2], values[3], values[4]); - - if (write(fd, buf, strlen(buf)) < 1) - { - free(choices); - return (-1); - } - - if (choices[i]->code == NULL) - { - /* - * This can happen with certain buggy PPD files that don't include - * a CustomPageSize command sequence... We just use a generic - * Level 2 command sequence... - */ - - if (write(fd, ppd_custom_code, strlen(ppd_custom_code)) < 1) - { - free(choices); - return (-1); - } - } - } - - if (choices[i]->code != NULL && choices[i]->code[0] != '\0') - { - if (write(fd, choices[i]->code, strlen(choices[i]->code)) < 1) - { - free(choices); - return (-1); - } - } - - if (write(fd, "%%EndFeature\n", 13) < 1) - { - free(choices); - return (-1); - } - - if (write(fd, "} stopped cleartomark\n", 22) < 1) - { - free(choices); - return (-1); - } - } - else if (write(fd, choices[i]->code, strlen(choices[i]->code)) < 1) - { - free(choices); - return (-1); - } - - free(choices); - return (0); + return (status); } @@ -684,7 +323,7 @@ * Range check the input... */ - if (ppd == NULL || ppd->jcl_begin == NULL || ppd->jcl_ps == NULL) + if (!ppd || !ppd->jcl_begin || !ppd->jcl_ps) return (0); /* @@ -780,25 +419,18 @@ ppdEmitJCLEnd(ppd_file_t *ppd, /* I - PPD file record */ FILE *fp) /* I - File to write to */ { - ppd_attr_t *attr; /* PPD attributes */ - - /* * Range check the input... */ - if (ppd == NULL) + if (!ppd) return (0); - if (ppd->jcl_end == NULL) + if (!ppd->jcl_end) { if (ppd->num_filters == 0) - fputc(0x04, fp); + putc(0x04, fp); - if ((attr = ppdFindAttr(ppd, "cupsProtocol", NULL)) != NULL && - attr->value != NULL && !strcasecmp(attr->value, "TBCP")) - fputs("\033%-12345X", stdout); - return (0); } @@ -829,6 +461,365 @@ /* + * 'ppdEmitString()' - Get a string containing the code for marked options. + * + * When "min_order" is greater than zero, this function only includes options + * whose OrderDependency value is greater than or equal to "min_order". + * Otherwise, all options in the specified section are included in the + * returned string. + * + * The return string is allocated on the heap and should be freed using + * free() when you are done with it. + * + * @since CUPS 1.2@ + */ + +char * /* O - String containing option code */ +ppdEmitString(ppd_file_t *ppd, /* I - PPD file record */ + ppd_section_t section, /* I - Section to write */ + float min_order) /* I - Lowest OrderDependency */ +{ + int i, j, /* Looping vars */ + count; /* Number of choices */ + ppd_choice_t **choices; /* Choices */ + ppd_size_t *size; /* Custom page size */ + ppd_coption_t *coption; /* Custom option */ + ppd_cparam_t *cparam; /* Custom parameter */ + size_t bufsize; /* Size of string buffer needed */ + char *buffer, /* String buffer */ + *bufptr, /* Pointer into buffer */ + *bufend; /* End of buffer */ + struct lconv *loc; /* Locale data */ + + + /* + * Range check input... + */ + + if (!ppd) + return (NULL); + + /* + * Use PageSize or PageRegion as required... + */ + + ppd_handle_media(ppd); + + /* + * Collect the options we need to emit... + */ + + if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0) + return (NULL); + + /* + * Count the number of bytes that are required to hold all of the + * option code... + */ + + for (i = 0, bufsize = 1; i < count; i ++) + { + if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL) + { + bufsize += 3; /* [{\n */ + + if ((!strcasecmp(choices[i]->option->keyword, "PageSize") || + !strcasecmp(choices[i]->option->keyword, "PageRegion")) && + !strcasecmp(choices[i]->choice, "Custom")) + { + bufsize += 37; /* %%BeginFeature: *CustomPageSize True */ + bufsize += 50; /* Five 9-digit numbers + newline */ + } + else if (!strcasecmp(choices[i]->choice, "Custom") && + (coption = ppdFindCustomOption(ppd, + choices[i]->option->keyword)) + != NULL) + { + bufsize += 23 + strlen(choices[i]->option->keyword); + /* %%BeginFeature: *keyword True */ + + + for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); + cparam; + cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) + { + switch (cparam->type) + { + case PPD_CUSTOM_CURVE : + case PPD_CUSTOM_INVCURVE : + case PPD_CUSTOM_POINTS : + case PPD_CUSTOM_REAL : + case PPD_CUSTOM_INT : + bufsize += 10; + break; + + case PPD_CUSTOM_PASSCODE : + case PPD_CUSTOM_PASSWORD : + case PPD_CUSTOM_STRING : + bufsize += 3 + 4 * strlen(cparam->current.custom_string); + break; + } + } + } + else + bufsize += 19 + strlen(choices[i]->option->keyword) + + strlen(choices[i]->choice); + /* %%BeginFeature: *keyword choice */ + + bufsize += 13; /* %%EndFeature\n */ + bufsize += 22; /* } stopped cleartomark\n */ + } + + if (choices[i]->code) + bufsize += strlen(choices[i]->code); + else + bufsize += strlen(ppd_custom_code); + } + + /* + * Allocate memory... + */ + + if ((buffer = calloc(1, bufsize)) == NULL) + { + free(choices); + return (NULL); + } + + bufend = buffer + bufsize - 1; + loc = localeconv(); + + /* + * Copy the option code to the buffer... + */ + + for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr)) + if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL) + { + /* + * Add wrapper commands to prevent printer errors for unsupported + * options... + */ + + strlcpy(bufptr, "[{\n", bufend - bufptr + 1); + bufptr += 3; + + /* + * Send DSC comments with option... + */ + + if ((!strcasecmp(choices[i]->option->keyword, "PageSize") || + !strcasecmp(choices[i]->option->keyword, "PageRegion")) && + !strcasecmp(choices[i]->choice, "Custom")) + { + /* + * Variable size; write out standard size options, using the + * parameter positions defined in the PPD file... + */ + + ppd_attr_t *attr; /* PPD attribute */ + int pos, /* Position of custom value */ + orientation; /* Orientation to use */ + float values[5]; /* Values for custom command */ + + + strlcpy(bufptr, "%%BeginFeature: *CustomPageSize True\n", + bufend - bufptr + 1); + bufptr += 37; + + size = ppdPageSize(ppd, "Custom"); + + memset(values, 0, sizeof(values)); + + if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL) + { + pos = atoi(attr->value) - 1; + + if (pos < 0 || pos > 4) + pos = 0; + } + else + pos = 0; + + values[pos] = size->width; + + if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL) + { + pos = atoi(attr->value) - 1; + + if (pos < 0 || pos > 4) + pos = 1; + } + else + pos = 1; + + values[pos] = size->length; + + /* + * According to the Adobe PPD specification, an orientation of 1 + * will produce a print that comes out upside-down with the X + * axis perpendicular to the direction of feed, which is exactly + * what we want to be consistent with non-PS printers. + * + * We could also use an orientation of 3 to produce output that + * comes out rightside-up (this is the default for many large format + * printer PPDs), however for consistency we will stick with the + * value 1. + * + * If we wanted to get fancy, we could use orientations of 0 or + * 2 and swap the width and length, however we don't want to get + * fancy, we just want it to work consistently. + * + * The orientation value is range limited by the Orientation + * parameter definition, so certain non-PS printer drivers that + * only support an Orientation of 0 will get the value 0 as + * expected. + */ + + orientation = 1; + + if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", + "Orientation")) != NULL) + { + int min_orient, max_orient; /* Minimum and maximum orientations */ + + + if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient, + &max_orient) != 3) + pos = 4; + else + { + pos --; + + if (pos < 0 || pos > 4) + pos = 4; + + if (orientation > max_orient) + orientation = max_orient; + else if (orientation < min_orient) + orientation = min_orient; + } + } + else + pos = 4; + + values[pos] = orientation; + + for (pos = 0; pos < 5; pos ++) + { + bufptr = _cupsStrFormatd(bufptr, bufend, values[pos], loc); + *bufptr++ = '\n'; + } + + if (!choices[i]->code) + { + /* + * This can happen with certain buggy PPD files that don't include + * a CustomPageSize command sequence... We just use a generic + * Level 2 command sequence... + */ + + strlcpy(bufptr, ppd_custom_code, bufend - bufptr + 1); + bufptr += strlen(bufptr); + } + } + else if (!strcasecmp(choices[i]->choice, "Custom") && + (coption = ppdFindCustomOption(ppd, + choices[i]->option->keyword)) + != NULL) + { + /* + * Custom option... + */ + + const char *s; /* Pointer into string value */ + + + snprintf(bufptr, bufend - bufptr + 1, + "%%%%BeginFeature: *Custom%s True\n", coption->keyword); + bufptr += strlen(bufptr); + + for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); + cparam; + cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) + { + switch (cparam->type) + { + case PPD_CUSTOM_CURVE : + case PPD_CUSTOM_INVCURVE : + case PPD_CUSTOM_POINTS : + case PPD_CUSTOM_REAL : + bufptr = _cupsStrFormatd(bufptr, bufend, + cparam->current.custom_real, loc); + *bufptr++ = '\n'; + break; + + case PPD_CUSTOM_INT : + snprintf(bufptr, bufend - bufptr + 1, "%d\n", + cparam->current.custom_int); + bufptr += strlen(bufptr); + break; + + case PPD_CUSTOM_PASSCODE : + case PPD_CUSTOM_PASSWORD : + case PPD_CUSTOM_STRING : + *bufptr++ = '('; + + for (s = cparam->current.custom_string; *s; s ++) + if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127) + { + snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *s & 255); + bufptr += strlen(bufptr); + } + else + *bufptr++ = *s; + + *bufptr++ = ')'; + *bufptr++ = '\n'; + break; + } + } + } + else + { + snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *%s %s\n", + choices[i]->option->keyword, choices[i]->choice); + bufptr += strlen(bufptr); + } + + if (choices[i]->code && choices[i]->code[0]) + { + j = strlen(choices[i]->code); + memcpy(bufptr, choices[i]->code, j); + bufptr += j; + + if (choices[i]->code[j - 1] != '\n') + *bufptr++ = '\n'; + } + + strlcpy(bufptr, "%%EndFeature\n" + "} stopped cleartomark\n", bufend - bufptr + 1); + bufptr += strlen(bufptr); + } + else + { + strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1); + bufptr += strlen(bufptr); + } + + /* + * Nul-terminate, free, and return... + */ + + *bufptr = '\0'; + + free(choices); + + return (buffer); +} + + +/* * 'ppd_handle_media()' - Handle media selection... */ Index: cups/ppd.c =================================================================== --- cups/ppd.c (revision 5237) +++ cups/ppd.c (working copy) @@ -393,7 +393,6 @@ ppd_file_t * /* O - PPD file record */ ppdOpen2(cups_file_t *fp) /* I - File to read from */ { - char *oldlocale; /* Old locale settings */ int i, j, k; /* Looping vars */ int count; /* Temporary count */ ppd_file_t *ppd; /* PPD file record */ @@ -420,6 +419,7 @@ ppd_profile_t *profile; /* Pointer to color profile */ char **filter; /* Pointer to filter */ cups_lang_t *language; /* Default language */ + struct lconv *loc; /* Locale data */ int ui_keyword; /* Is this line a UI keyword? */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ @@ -554,13 +554,8 @@ */ language = cupsLangDefault(); + loc = localeconv(); -#ifdef LC_NUMERIC - oldlocale = _cupsSaveLocale(LC_NUMERIC, "C"); -#else - oldlocale = _cupsSaveLocale(LC_ALL, "C"); -#endif /* LC_NUMERIC */ - /* * Read lines from the PPD file and add them to the file record... */ @@ -772,13 +767,18 @@ memset(profile, 0, sizeof(ppd_profile_t)); strlcpy(profile->resolution, name, sizeof(profile->resolution)); strlcpy(profile->media_type, text, sizeof(profile->media_type)); - sscanf(string, "%f%f%f%f%f%f%f%f%f%f%f", &(profile->density), - &(profile->gamma), - profile->matrix[0] + 0, profile->matrix[0] + 1, - profile->matrix[0] + 2, profile->matrix[1] + 0, - profile->matrix[1] + 1, profile->matrix[1] + 2, - profile->matrix[2] + 0, profile->matrix[2] + 1, - profile->matrix[2] + 2); + + profile->density = _cupsStrScand(string, &sptr, loc); + profile->gamma = _cupsStrScand(sptr, &sptr, loc); + profile->matrix[0][0] = _cupsStrScand(sptr, &sptr, loc); + profile->matrix[0][1] = _cupsStrScand(sptr, &sptr, loc); + profile->matrix[0][2] = _cupsStrScand(sptr, &sptr, loc); + profile->matrix[1][0] = _cupsStrScand(sptr, &sptr, loc); + profile->matrix[1][1] = _cupsStrScand(sptr, &sptr, loc); + profile->matrix[1][2] = _cupsStrScand(sptr, &sptr, loc); + profile->matrix[2][0] = _cupsStrScand(sptr, &sptr, loc); + profile->matrix[2][1] = _cupsStrScand(sptr, &sptr, loc); + profile->matrix[2][2] = _cupsStrScand(sptr, &sptr, loc); } else if (!strcmp(keyword, "cupsFilter")) { @@ -877,8 +877,8 @@ if (!strcmp(ctype, "curve")) { cparam->type = PPD_CUSTOM_CURVE; - cparam->minimum.custom_curve = atof(cminimum); - cparam->maximum.custom_curve = atof(cmaximum); + cparam->minimum.custom_curve = _cupsStrScand(cminimum, NULL, loc); + cparam->maximum.custom_curve = _cupsStrScand(cmaximum, NULL, loc); } else if (!strcmp(ctype, "int")) { @@ -889,8 +889,8 @@ else if (!strcmp(ctype, "invcurve")) { cparam->type = PPD_CUSTOM_INVCURVE; - cparam->minimum.custom_invcurve = atof(cminimum); - cparam->maximum.custom_invcurve = atof(cmaximum); + cparam->minimum.custom_invcurve = _cupsStrScand(cminimum, NULL, loc); + cparam->maximum.custom_invcurve = _cupsStrScand(cmaximum, NULL, loc); } else if (!strcmp(ctype, "passcode")) { @@ -907,14 +907,14 @@ else if (!strcmp(ctype, "points")) { cparam->type = PPD_CUSTOM_POINTS; - cparam->minimum.custom_points = atof(cminimum); - cparam->maximum.custom_points = atof(cmaximum); + cparam->minimum.custom_points = _cupsStrScand(cminimum, NULL, loc); + cparam->maximum.custom_points = _cupsStrScand(cmaximum, NULL, loc); } else if (!strcmp(ctype, "real")) { cparam->type = PPD_CUSTOM_REAL; - cparam->minimum.custom_real = atof(cminimum); - cparam->maximum.custom_real = atof(cmaximum); + cparam->minimum.custom_real = _cupsStrScand(cminimum, NULL, loc); + cparam->maximum.custom_real = _cupsStrScand(cmaximum, NULL, loc); } else if (!strcmp(ctype, "string")) { @@ -948,9 +948,10 @@ } } else if (!strcmp(keyword, "HWMargins")) - sscanf(string, "%f%f%f%f", ppd->custom_margins + 0, - ppd->custom_margins + 1, ppd->custom_margins + 2, - ppd->custom_margins + 3); + { + for (i = 0, sptr = string; i < 4; i ++) + ppd->custom_margins[i] = _cupsStrScand(sptr, &sptr, loc); + } else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True")) { ppd_coption_t *coption; /* Custom option */ @@ -1344,7 +1345,9 @@ else if (!strcmp(keyword, "OrderDependency") || !strcmp(keyword, "NonUIOrderDependency")) { - if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3) + order = _cupsStrScand(string, &sptr, loc); + + if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2) { cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY; @@ -1560,7 +1563,8 @@ goto error; } - sscanf(string, "%f%f", &(size->width), &(size->length)); + size->width = _cupsStrScand(string, &sptr, loc); + size->length = _cupsStrScand(sptr, NULL, loc); ppd_free(string); string = NULL; @@ -1581,8 +1585,10 @@ goto error; } - sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom), - &(size->right), &(size->top)); + size->left = _cupsStrScand(string, &sptr, loc); + size->bottom = _cupsStrScand(sptr, &sptr, loc); + size->right = _cupsStrScand(sptr, &sptr, loc); + size->top = _cupsStrScand(sptr, NULL, loc); ppd_free(string); string = NULL; @@ -1643,12 +1649,6 @@ cupsLangFree(language); -#ifdef LC_NUMERIC - _cupsRestoreLocale(LC_NUMERIC, oldlocale); -#else - _cupsRestoreLocale(LC_ALL, oldlocale); -#endif /* LC_NUMERIC */ - #ifdef DEBUG if (!feof(fp)) printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp)); @@ -1711,12 +1711,6 @@ cupsLangFree(language); -#ifdef LC_NUMERIC - _cupsRestoreLocale(LC_NUMERIC, oldlocale); -#else - _cupsRestoreLocale(LC_ALL, oldlocale); -#endif /* LC_NUMERIC */ - return (NULL); } Index: cups/language.c =================================================================== --- cups/language.c (revision 5237) +++ cups/language.c (working copy) @@ -38,8 +38,6 @@ * _cupsMessageFree() - Free a messages array. * _cupsMessageLoad() - Load a .po file into a messages array. * _cupsMessageLookup() - Lookup a message string. - * _cupsRestoreLocale() - Restore the original locale... - * _cupsSaveLocale() - Set the locale and save a copy of the old locale... * appleLangDefault() - Get the default locale string. * cups_cache_lookup() - Lookup a language in the cache... * cups_message_compare() - Compare two messages. @@ -271,15 +269,12 @@ langname[16], /* Requested language name */ country[16], /* Country code */ charset[16], /* Character set */ -#ifdef CODESET *csptr, /* Pointer to CODESET string */ -#endif /* CODESET */ *ptr, /* Pointer into language/charset */ real[48], /* Real language name */ filename[1024]; /* Filename for language locale file */ cups_encoding_t encoding; /* Encoding to use */ cups_lang_t *lang; /* Current language... */ - char *oldlocale; /* Old locale name */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ static const char * const locale_encodings[] = @@ -328,18 +323,37 @@ #ifdef __APPLE__ /* + * Set the character set to UTF-8... + */ + + strcpy(charset, "UTF8"); + + /* * Apple's setlocale doesn't give us the user's localization * preference so we have to look it up this way... */ - if (language == NULL) + if (!language) language = appleLangDefault(); + #else - if (language == NULL) + /* + * Set the charset to "unknown"... + */ + + charset[0] = '\0'; + + /* + * Use setlocale() to determine the currently set locale, and then + * fallback to environment variables to avoid setting the locale, + * since setlocale() is not thread-safe! + */ + + if (!language) { /* * First see if the locale has been set; if it is still "C" or - * "POSIX", set the locale to the default... + * "POSIX", use the environment to get the default... */ # ifdef LC_MESSAGES @@ -352,14 +366,46 @@ ptr ? ptr : "(null)")); if (!ptr || !strcmp(ptr, "C") || !strcmp(ptr, "POSIX")) -# ifdef LC_MESSAGES { - ptr = setlocale(LC_MESSAGES, ""); - setlocale(LC_CTYPE, ""); + /* + * Get the character set from the LC_CTYPE locale setting... + */ + + if ((ptr = getenv("LC_CTYPE")) == NULL) + if ((ptr = getenv("LC_ALL")) == NULL) + if ((ptr = getenv("LANG")) == NULL) + ptr = "en_US"; + + if ((csptr = strchr(ptr, '.')) != NULL) + { + /* + * Extract the character set from the environment... + */ + + for (ptr = charset, csptr ++; *csptr; csptr ++) + if (ptr < (charset + sizeof(charset) - 1) && isalnum(*csptr & 255)) + *ptr++ = *csptr; + + *ptr = '\0'; + } + else + { + /* + * Default to UTF-8... + */ + + strcpy(charset, "UTF8"); + } + + /* + * Get the locale for messages from the LC_MESSAGES locale setting... + */ + + if ((ptr = getenv("LC_MESSAGES")) == NULL) + if ((ptr = getenv("LC_ALL")) == NULL) + if ((ptr = getenv("LANG")) == NULL) + ptr = "en_US"; } -# else - ptr = setlocale(LC_ALL, ""); -# endif /* LC_MESSAGES */ if (ptr) { @@ -380,27 +426,19 @@ if (!language) { /* - * Switch to the value of the "LANG" environment variable, and if - * that is NULL as well, use "C". + * Switch to the POSIX ("C") locale... */ - if ((language = getenv("LANG")) == NULL) - language = "C"; + language = "C"; } - /* - * Set the charset to "unknown"... - */ - - charset[0] = '\0'; - #ifdef CODESET /* * On systems that support the nl_langinfo(CODESET) call, use * this value as the character set... */ - if ((csptr = nl_langinfo(CODESET)) != NULL) + if (!charset[0] && (csptr = nl_langinfo(CODESET)) != NULL) { /* * Copy all of the letters and numbers in the CODESET string... @@ -418,22 +456,6 @@ #endif /* CODESET */ /* - * Set the locale back to POSIX while we do string ops, since - * apparently some buggy C libraries break ctype() for non-I18N - * chars... - */ - -#if defined(__APPLE__) - /* The ctype bug isn't in Apple's libc */ - (void)locale; /* anti-compiler-warning-code */ - (void)oldlocale; /* anti-compiler-warning-code */ -#elif !defined(LC_CTYPE) - oldlocale = _cupsSaveLocale(LC_ALL, "C"); -#else - oldlocale = _cupsSaveLocale(LC_CTYPE, "C"); -#endif /* __APPLE__ */ - - /* * Parse the language string passed in to a locale string. "C" is the * standard POSIX locale and is copied unchanged. Otherwise the * language string is converted from ll-cc[.charset] (language-country) @@ -501,18 +523,6 @@ } } - /* - * Restore the locale... - */ - -#if defined(__APPLE__) - /* The ctype bug isn't in Apple's libc */ -#elif !defined(LC_CTYPE) - _cupsRestoreLocale(LC_ALL, oldlocale); -#else - _cupsRestoreLocale(LC_CTYPE, oldlocale); -#endif /* __APPLE__ */ - DEBUG_printf(("cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"\n", langname, country, charset)); @@ -900,66 +910,6 @@ } -/* - * '_cupsRestoreLocale()' - Restore the original locale... - */ - -void -_cupsRestoreLocale(int category, /* I - Category */ - char *oldlocale) /* I - Old locale or NULL */ -{ - DEBUG_printf(("_cupsRestoreLocale(category=%d, oldlocale=\"%s\")\n", - category, oldlocale)); - - if (oldlocale) - { - /* - * Reset the locale and free the locale string... - */ - - setlocale(category, oldlocale); - free(oldlocale); - } -} - - -/* - * '_cupsSaveLocale()' - Set the locale and save a copy of the old locale... - */ - -char * /* O - Old locale or NULL */ -_cupsSaveLocale(int category, /* I - Category */ - const char *locale) /* I - New locale or NULL */ -{ - char *oldlocale; /* Old locale */ - - - DEBUG_printf(("_cupsSaveLocale(category=%d, locale=\"%s\")\n", - category, locale)); - - /* - * Get the old locale and copy it... - */ - - if ((oldlocale = setlocale(category, NULL)) != NULL) - oldlocale = strdup(oldlocale); - - DEBUG_printf((" oldlocale=\"%s\"\n", oldlocale ? oldlocale : "(null)")); - - /* - * Set the new locale... - */ - - setlocale(category, locale); - - /* - * Return a copy of the old locale... - */ - - return (oldlocale); -} - - #ifdef __APPLE__ /* * Code & data to translate OSX's language names to their ISO 639-1 locale. Index: cups/ppd.h =================================================================== --- cups/ppd.h (revision 5237) +++ cups/ppd.h (working copy) @@ -381,6 +381,8 @@ ppd_section_t section, int limit, float min_order); extern int ppdEmitJCLEnd(ppd_file_t *ppd, FILE *fp); +extern char *ppdEmitString(ppd_file_t *ppd, ppd_section_t section, + float min_order); extern ppd_coption_t *ppdFindCustomOption(ppd_file_t *ppd, const char *keyword); extern ppd_cparam_t *ppdFindCustomParam(ppd_coption_t *opt, Index: cups/mark.c =================================================================== --- cups/mark.c (revision 5237) +++ cups/mark.c (working copy) @@ -323,6 +323,7 @@ int i, j; /* Looping vars */ ppd_option_t *o; /* Option pointer */ ppd_choice_t *c; /* Choice pointer */ + struct lconv *loc; /* Locale data */ DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n", @@ -354,6 +355,7 @@ if ((o = ppdFindOption(ppd, option)) == NULL) return (0); + loc = localeconv(); if (!strncasecmp(choice, "Custom.", 7)) { @@ -380,7 +382,7 @@ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ - char units[33]; /* Custom points units */ + char *units; /* Custom points units */ if ((coption = ppdFindCustomOption(ppd, option)) != NULL) { @@ -392,24 +394,27 @@ case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_REAL : - cparam->current.custom_real = atof(choice + 7); + cparam->current.custom_real = _cupsStrScand(choice + 7, NULL, + loc); break; case PPD_CUSTOM_POINTS : - if (sscanf(choice + 7, "%f%s", &(cparam->current.custom_points), - units) < 2) - strcpy(units, "pt"); + cparam->current.custom_points = _cupsStrScand(choice + 7, + &units, loc); - if (!strcasecmp(units, "cm")) - cparam->current.custom_points *= 72.0 / 2.54; - else if (!strcasecmp(units, "mm")) - cparam->current.custom_points *= 72.0 / 25.4; - else if (!strcasecmp(units, "m")) - cparam->current.custom_points *= 72.0 / 0.0254; - else if (!strcasecmp(units, "in")) - cparam->current.custom_points *= 72.0; - else if (!strcasecmp(units, "ft")) - cparam->current.custom_points *= 12 * 72.0; + if (units) + { + if (!strcasecmp(units, "cm")) + cparam->current.custom_points *= 72.0 / 2.54; + else if (!strcasecmp(units, "mm")) + cparam->current.custom_points *= 72.0 / 25.4; + else if (!strcasecmp(units, "m")) + cparam->current.custom_points *= 72.0 / 0.0254; + else if (!strcasecmp(units, "in")) + cparam->current.custom_points *= 72.0; + else if (!strcasecmp(units, "ft")) + cparam->current.custom_points *= 12 * 72.0; + } break; case PPD_CUSTOM_INT : @@ -436,7 +441,7 @@ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ - char units[33]; /* Custom points units */ + char *units; /* Custom points units */ int num_vals; /* Number of values */ cups_option_t *vals, /* Values */ *val; /* Value */ @@ -459,24 +464,27 @@ case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_REAL : - cparam->current.custom_real = atof(val->value); + cparam->current.custom_real = _cupsStrScand(val->value, NULL, + loc); break; case PPD_CUSTOM_POINTS : - if (sscanf(val->value, "%f%s", &(cparam->current.custom_points), - units) < 2) - strcpy(units, "pt"); + cparam->current.custom_points = _cupsStrScand(val->value, &units, + loc); - if (!strcasecmp(units, "cm")) - cparam->current.custom_points *= 72.0 / 2.54; - else if (!strcasecmp(units, "mm")) - cparam->current.custom_points *= 72.0 / 25.4; - else if (!strcasecmp(units, "m")) - cparam->current.custom_points *= 72.0 / 0.0254; - else if (!strcasecmp(units, "in")) - cparam->current.custom_points *= 72.0; - else if (!strcasecmp(units, "ft")) - cparam->current.custom_points *= 12 * 72.0; + if (units) + { + if (!strcasecmp(units, "cm")) + cparam->current.custom_points *= 72.0 / 2.54; + else if (!strcasecmp(units, "mm")) + cparam->current.custom_points *= 72.0 / 25.4; + else if (!strcasecmp(units, "m")) + cparam->current.custom_points *= 72.0 / 0.0254; + else if (!strcasecmp(units, "in")) + cparam->current.custom_points *= 72.0; + else if (!strcasecmp(units, "ft")) + cparam->current.custom_points *= 12 * 72.0; + } break; case PPD_CUSTOM_INT : Index: cups/libcups_s.exp =================================================================== --- cups/libcups_s.exp (revision 5237) +++ cups/libcups_s.exp (working copy) @@ -15,8 +15,6 @@ _cupsMessageLoad _cupsMessageLookup _cupsNormalizeMapsFlush -_cupsRestoreLocale -_cupsSaveLocale _cupsSetError _cupsStrAlloc _cups_strcpy Index: cups/i18n.h =================================================================== --- cups/i18n.h (revision 5237) +++ cups/i18n.h (working copy) @@ -60,10 +60,6 @@ * Prototypes... */ -/**** New in CUPS 1.1.20 ****/ -extern void _cupsRestoreLocale(int category, char *oldlocale); -extern char *_cupsSaveLocale(int category, const char *locale); - /**** New in CUPS 1.2 ****/ extern const char *_cupsEncodingName(cups_encoding_t encoding); extern int _cupsLangPrintf(FILE *fp, const char *message, ...) Index: cups/string.c =================================================================== --- cups/string.c (revision 5237) +++ cups/string.c (working copy) @@ -27,7 +27,9 @@ * * _cupsStrAlloc() - Allocate/reference a string. * _cupsStrFlush() - Flush the string pool... + * _cupsStrFormatd() - Format a floating-point number. * _cupsStrFree() - Free/dereference a string. + * _cupsStrScand() - Scan a string for a floating-point number. * _cupsStrStatistics() - Return allocation statistics for string pool. * _cups_strcpy() - Copy a string allowing for overlapping strings. * _cups_strdup() - Duplicate a string. @@ -154,6 +156,86 @@ /* + * '_cupsStrFormatd()' - Format a floating-point number. + */ + +char * /* O - Pointer to end of string */ +_cupsStrFormatd(char *buf, /* I - String */ + char *bufend, /* I - End of string buffer */ + double number, /* I - Number to format */ + struct lconv *loc) /* I - Locale data */ +{ + char *bufptr, /* Pointer into buffer */ + temp[1024], /* Temporary string */ + *tempdec, /* Pointer to decimal point */ + *tempptr; /* Pointer into temporary string */ + const char *dec; /* Decimal point */ + int declen; /* Length of decimal point */ + + + /* + * Format the number using the "%.12f" format and then eliminate + * unnecessary trailing 0's. + */ + + snprintf(temp, sizeof(temp), "%.12f", number); + for (tempptr = temp + strlen(temp) - 1; + tempptr > temp && *tempptr == '0'; + *tempptr-- = '\0'); + + /* + * Next, find the decimal point... + */ + + if (loc && loc->decimal_point) + { + dec = loc->decimal_point; + declen = strlen(dec); + } + else + { + dec = "."; + declen = 1; + } + + if (declen == 1) + tempdec = strchr(temp, *dec); + else + tempdec = strstr(temp, dec); + + /* + * Copy everything up to the decimal point... + */ + + if (tempdec) + { + for (tempptr = temp, bufptr = buf; + tempptr < tempdec && bufptr < bufend; + *bufptr++ = *tempptr++); + + tempdec += declen; + + if (*tempdec && bufptr < bufend) + { + *bufptr++ = '.'; + + while (*tempptr && bufptr < bufend) + *bufptr++ = *tempptr++; + } + + *bufptr = '\0'; + } + else + { + strlcpy(buf, temp, bufend - buf + 1); + bufptr = buf + strlen(buf); + } + + return (bufptr); +} + + +/* * '_cupsStrFree()' - Free/dereference a string. */ @@ -211,6 +293,97 @@ /* + * '_cupsStrScand()' - Scan a string for a floating-point number. + * + * This function handles the locale-specific BS so that a decimal + * point is always the period (".")... + */ + +double /* O - Number */ +_cupsStrScand(const char *buf, /* I - Pointer to number */ + char **bufptr, /* O - New pointer or NULL on error */ + struct lconv *loc) /* I - Locale data */ +{ + char temp[1024], /* Temporary buffer */ + *tempptr; /* Pointer into temporary buffer */ + + + /* + * Range check input... + */ + + if (!buf) + return (0.0); + + /* + * Skip leading whitespace... + */ + + while (isspace(*buf & 255)) + buf ++; + + /* + * Copy leading sign, numbers, period, and then numbers... + */ + + tempptr = temp; + if (*buf == '-' || *buf == '+') + *tempptr++ = *buf++; + + while (isdigit(*buf & 255)) + if (tempptr < (temp + sizeof(temp) - 1)) + *tempptr++ = *buf++; + else + { + if (bufptr) + *bufptr = NULL; + + return (0.0); + } + + if (*buf == '.') + { + if (loc && loc->decimal_point) + { + strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (tempptr - temp)); + tempptr += strlen(tempptr); + } + else if (tempptr < (temp + sizeof(temp) - 1)) + *tempptr++ = '.'; + else + { + if (bufptr) + *bufptr = NULL; + + return (0.0); + } + + while (isdigit(*buf & 255)) + if (tempptr < (temp + sizeof(temp) - 1)) + *tempptr++ = *buf++; + else + { + if (bufptr) + *bufptr = NULL; + + return (0.0); + } + } + + /* + * Nul-terminate the temporary string and return the value... + */ + + if (bufptr) + *bufptr = (char *)buf; + + *tempptr = '\0'; + + return (strtod(temp, NULL)); +} + + +/* * '_cupsStrStatistics()' - Return allocation statistics for string pool. */ Index: cups/string.h =================================================================== --- cups/string.h (revision 5237) +++ cups/string.h (working copy) @@ -36,6 +36,7 @@ # include # include # include +# include # ifdef HAVE_STRING_H # include @@ -135,6 +136,16 @@ /* + * Floating point number functions... + */ + +extern char *_cupsStrFormatd(char *buf, char *bufend, double number, + struct lconv *loc); +extern double _cupsStrScand(const char *buf, char **bufptr, + struct lconv *loc); + + +/* * C++ magic... */ Index: cups/page.c =================================================================== --- cups/page.c (revision 5237) +++ cups/page.c (working copy) @@ -45,28 +45,29 @@ * 'ppdPageSize()' - Get the page size record for the given size. */ -ppd_size_t * /* O - Size record for page or NULL */ -ppdPageSize(ppd_file_t *ppd, /* I - PPD file record */ - const char *name) /* I - Size name */ +ppd_size_t * /* O - Size record for page or NULL */ +ppdPageSize(ppd_file_t *ppd, /* I - PPD file record */ + const char *name) /* I - Size name */ { - int i; /* Looping var */ - float w, l; /* Width and length of page */ - char units[255]; /* Page size units... */ + int i; /* Looping var */ + float w, l; /* Width and length of page */ + char *nameptr; /* Pointer into name */ + struct lconv *loc; /* Locale data */ - if (ppd == NULL) + if (!ppd) return (NULL); - if (name != NULL) + if (name) { - if (strncmp(name, "Custom.", 7) == 0 && ppd->variable_sizes) + if (!strncmp(name, "Custom.", 7) && ppd->variable_sizes) { /* * Find the custom page size... */ for (i = 0; i < ppd->num_sizes; i ++) - if (strcmp("Custom", ppd->sizes[i].name) == 0) + if (!strcmp("Custom", ppd->sizes[i].name)) break; if (i == ppd->num_sizes) @@ -81,11 +82,16 @@ * Custom.WIDTHxLENGTH[pt] - Size in points */ - units[0] = '\0'; - if (sscanf(name + 7, "%fx%f%254s", &w, &l, units) < 2) + loc = localeconv(); + w = _cupsStrScand(name + 7, &nameptr, loc); + if (!nameptr || *nameptr != 'x') return (NULL); - if (strcasecmp(units, "in") == 0) + l = _cupsStrScand(nameptr, &nameptr, loc); + if (!nameptr) + return (NULL); + + if (!strcasecmp(nameptr, "in")) { ppd->sizes[i].width = w * 72.0f; ppd->sizes[i].length = l * 72.0f; @@ -94,7 +100,7 @@ ppd->sizes[i].right = w * 72.0f - ppd->custom_margins[2]; ppd->sizes[i].top = l * 72.0f - ppd->custom_margins[3]; } - else if (strcasecmp(units, "cm") == 0) + else if (!strcasecmp(nameptr, "cm")) { ppd->sizes[i].width = w / 2.54f * 72.0f; ppd->sizes[i].length = l / 2.54f * 72.0f; @@ -103,7 +109,7 @@ ppd->sizes[i].right = w / 2.54f * 72.0f - ppd->custom_margins[2]; ppd->sizes[i].top = l / 2.54f * 72.0f - ppd->custom_margins[3]; } - else if (strcasecmp(units, "mm") == 0) + else if (!strcasecmp(nameptr, "mm")) { ppd->sizes[i].width = w / 25.4f * 72.0f; ppd->sizes[i].length = l / 25.4f * 72.0f; @@ -131,7 +137,7 @@ */ for (i = 0; i < ppd->num_sizes; i ++) - if (strcmp(name, ppd->sizes[i].name) == 0) + if (!strcasecmp(name, ppd->sizes[i].name)) return (ppd->sizes + i); } }