X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=cups%2Foptions.c;h=9aa20f8954ec5fe0acdb0acd0ed38317ac44c77a;hp=cd38c185bc585972f2479a5f04be805c34b0516e;hb=98d88c8d4796d2adc7b0afeb99ae8f34eae42e63;hpb=bc44d92092094935265183305a38196ce2822756 diff --git a/cups/options.c b/cups/options.c index cd38c185b..9aa20f895 100644 --- a/cups/options.c +++ b/cups/options.c @@ -1,92 +1,134 @@ /* - * "$Id: options.c 6649 2007-07-11 21:46:42Z mike $" + * Option routines for CUPS. * - * Option routines for the Common UNIX Printing System (CUPS). + * Copyright 2007-2017 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products. * - * Copyright 2007 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products. + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * missing or damaged, see the license at "http://www.cups.org/". * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - * cupsAddOption() - Add an option to an option array. - * cupsFreeOptions() - Free all memory used by options. - * cupsGetOption() - Get an option value. - * cupsMarkOptions() - Mark command-line options in a PPD file. - * cupsParseOptions() - Parse options from a command-line argument. - * cupsRemoveOptions() - Remove an option from an option array. - * ppd_mark_choices() - Mark one or more option choices from a string. + * This file is subject to the Apple OS-Developed Software exception. */ /* * Include necessary headers... */ -#include "cups.h" -#include -#include -#include "string.h" -#include "debug.h" +#include "cups-private.h" /* * Local functions... */ -static int ppd_mark_choices(ppd_file_t *ppd, const char *options); +static int cups_compare_options(cups_option_t *a, cups_option_t *b); +static int cups_find_option(const char *name, int num_options, + cups_option_t *option, int prev, int *rdiff); + + +/* + * 'cupsAddIntegerOption()' - Add an integer option to an option array. + * + * New option arrays can be initialized simply by passing 0 for the + * "num_options" parameter. + * + * @since CUPS 2.2.4/macOS 10.13@ + */ + +int /* O - Number of options */ +cupsAddIntegerOption( + const char *name, /* I - Name of option */ + int value, /* I - Value of option */ + int num_options, /* I - Number of options */ + cups_option_t **options) /* IO - Pointer to options */ +{ + char strvalue[32]; /* String value */ + + + snprintf(strvalue, sizeof(strvalue), "%d", value); + + return (cupsAddOption(name, strvalue, num_options, options)); +} /* * 'cupsAddOption()' - Add an option to an option array. + * + * New option arrays can be initialized simply by passing 0 for the + * "num_options" parameter. */ -int /* O - Number of options */ -cupsAddOption(const char *name, /* I - Name of option */ - const char *value, /* I - Value of option */ - int num_options,/* I - Number of options */ +int /* O - Number of options */ +cupsAddOption(const char *name, /* I - Name of option */ + const char *value, /* I - Value of option */ + int num_options,/* I - Number of options */ cups_option_t **options) /* IO - Pointer to options */ { - int i; /* Looping var */ cups_option_t *temp; /* Pointer to new option */ + int insert, /* Insertion point */ + diff; /* Result of search */ + + DEBUG_printf(("2cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, options=%p)", name, value, num_options, (void *)options)); - if (name == NULL || !name[0] || value == NULL || - options == NULL || num_options < 0) + if (!name || !name[0] || !value || !options || num_options < 0) + { + DEBUG_printf(("3cupsAddOption: Returning %d", num_options)); return (num_options); + } /* * Look for an existing option with the same name... */ - for (i = 0, temp = *options; i < num_options; i ++, temp ++) - if (strcasecmp(temp->name, name) == 0) - break; + if (num_options == 0) + { + insert = 0; + diff = 1; + } + else + { + insert = cups_find_option(name, num_options, *options, num_options - 1, + &diff); + + if (diff > 0) + insert ++; + } - if (i >= num_options) + if (diff) { /* * No matching option name... */ + DEBUG_printf(("4cupsAddOption: New option inserted at index %d...", + insert)); + if (num_options == 0) temp = (cups_option_t *)malloc(sizeof(cups_option_t)); else - temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) * - (num_options + 1)); + temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) * (size_t)(num_options + 1)); - if (temp == NULL) + if (!temp) + { + DEBUG_puts("3cupsAddOption: Unable to expand option array, returning 0"); return (0); + } + + *options = temp; - *options = temp; - temp += num_options; - temp->name = strdup(name); + if (insert < num_options) + { + DEBUG_printf(("4cupsAddOption: Shifting %d options...", + (int)(num_options - insert))); + memmove(temp + insert + 1, temp + insert, (size_t)(num_options - insert) * sizeof(cups_option_t)); + } + + temp += insert; + temp->name = _cupsStrAlloc(name); num_options ++; } else @@ -95,10 +137,16 @@ cupsAddOption(const char *name, /* I - Name of option */ * Match found; free the old value... */ - free(temp->value); + DEBUG_printf(("4cupsAddOption: Option already exists at index %d...", + insert)); + + temp = *options + insert; + _cupsStrFree(temp->value); } - temp->value = strdup(value); + temp->value = _cupsStrAlloc(value); + + DEBUG_printf(("3cupsAddOption: Returning %d", num_options)); return (num_options); } @@ -116,13 +164,15 @@ cupsFreeOptions( int i; /* Looping var */ - if (num_options <= 0 || options == NULL) + DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)", num_options, (void *)options)); + + if (num_options <= 0 || !options) return; for (i = 0; i < num_options; i ++) { - free(options[i].name); - free(options[i].value); + _cupsStrFree(options[i].name); + _cupsStrFree(options[i].value); } free(options); @@ -130,312 +180,68 @@ cupsFreeOptions( /* - * 'cupsGetOption()' - Get an option value. + * 'cupsGetIntegerOption()' - Get an integer option value. + * + * INT_MIN is returned when the option does not exist, is not an integer, or + * exceeds the range of values for the "int" type. + * + * @since CUPS 2.2.4/macOS 10.13@ */ -const char * /* O - Option value or NULL */ -cupsGetOption(const char *name, /* I - Name of option */ - int num_options,/* I - Number of options */ - cups_option_t *options) /* I - Options */ +int /* O - Option value or @code INT_MIN@ */ +cupsGetIntegerOption( + const char *name, /* I - Name of option */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ { - int i; /* Looping var */ + const char *value = cupsGetOption(name, num_options, options); + /* String value of option */ + char *ptr; /* Pointer into string value */ + long intvalue; /* Integer value */ - if (name == NULL || num_options <= 0 || options == NULL) - return (NULL); + if (!value || !*value) + return (INT_MIN); - for (i = 0; i < num_options; i ++) - if (strcasecmp(options[i].name, name) == 0) - return (options[i].value); + intvalue = strtol(value, &ptr, 10); + if (intvalue < INT_MIN || intvalue > INT_MAX || *ptr) + return (INT_MIN); - return (NULL); + return ((int)intvalue); } /* - * 'cupsMarkOptions()' - Mark command-line options in a PPD file. + * 'cupsGetOption()' - Get an option value. */ -int /* O - 1 if conflicting */ -cupsMarkOptions( - ppd_file_t *ppd, /* I - PPD file */ - int num_options, /* I - Number of options */ - cups_option_t *options) /* I - Options */ +const char * /* O - Option value or @code NULL@ */ +cupsGetOption(const char *name, /* I - Name of option */ + int num_options,/* I - Number of options */ + cups_option_t *options) /* I - Options */ { - int i, j, k; /* Looping vars */ - int conflict; /* Option conflicts */ - char *val, /* Pointer into value */ - *ptr, /* Pointer into string */ - s[255]; /* Temporary string */ - const char *page_size; /* PageSize option */ - cups_option_t *optptr; /* Current option */ - ppd_option_t *option; /* PPD option */ - ppd_attr_t *attr; /* PPD attribute */ - static const char * const duplex_options[] = - { /* Duplex option names */ - "Duplex", /* Adobe */ - "EFDuplex", /* EFI */ - "EFDuplexing", /* EFI */ - "KD03Duplex", /* Kodak */ - "JCLDuplex" /* Samsung */ - }; - static const char * const duplex_one[] = - { /* one-sided names */ - "None", - "False" - }; - static const char * const duplex_two_long[] = - { /* two-sided-long-edge names */ - "DuplexNoTumble", /* Adobe */ - "LongEdge", /* EFI */ - "Top" /* EFI */ - }; - static const char * const duplex_two_short[] = - { /* two-sided-long-edge names */ - "DuplexTumble", /* Adobe */ - "ShortEdge", /* EFI */ - "Bottom" /* EFI */ - }; - - - /* - * Check arguments... - */ - - if (ppd == NULL || num_options <= 0 || options == NULL) - return (0); - - /* - * Mark options... - */ - - conflict = 0; - - for (i = num_options, optptr = options; i > 0; i --, optptr ++) - if (!strcasecmp(optptr->name, "media")) - { - /* - * Loop through the option string, separating it at commas and - * marking each individual option as long as the corresponding - * PPD option (PageSize, InputSlot, etc.) is not also set. - * - * For PageSize, we also check for an empty option value since - * some versions of MacOS X use it to specify auto-selection - * of the media based solely on the size. - */ - - page_size = cupsGetOption("PageSize", num_options, options); - - for (val = optptr->value; *val;) - { - /* - * Extract the sub-option from the string... - */ - - for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);) - *ptr++ = *val++; - *ptr++ = '\0'; - - if (*val == ',') - val ++; - - /* - * Mark it... - */ - - if (!page_size || !page_size[0]) - if (ppdMarkOption(ppd, "PageSize", s)) - conflict = 1; - - if (cupsGetOption("InputSlot", num_options, options) == NULL) - if (ppdMarkOption(ppd, "InputSlot", s)) - conflict = 1; + int diff, /* Result of comparison */ + match; /* Matching index */ - if (cupsGetOption("MediaType", num_options, options) == NULL) - if (ppdMarkOption(ppd, "MediaType", s)) - conflict = 1; - if (cupsGetOption("EFMediaType", num_options, options) == NULL) - if (ppdMarkOption(ppd, "EFMediaType", s)) - conflict = 1; + DEBUG_printf(("2cupsGetOption(name=\"%s\", num_options=%d, options=%p)", name, num_options, (void *)options)); - if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL) - if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */ - conflict = 1; - - if (strcasecmp(s, "manual") == 0 && - cupsGetOption("ManualFeed", num_options, options) == NULL) - if (ppdMarkOption(ppd, "ManualFeed", "True")) - conflict = 1; - } - } - else if (!strcasecmp(optptr->name, "sides")) - { - for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) - if (cupsGetOption(duplex_options[j], num_options, options) != NULL) - break; - - if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) - { - /* - * Don't override the PPD option with the IPP attribute... - */ - - continue; - } - - if (!strcasecmp(optptr->value, "one-sided")) - { - /* - * Mark the appropriate duplex option for one-sided output... - */ - - for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) - if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) - break; - - if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) - { - for (k = 0; k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); k ++) - if (ppdFindChoice(option, duplex_one[k])) - { - if (ppdMarkOption(ppd, duplex_options[j], duplex_one[k])) - conflict = 1; - - break; - } - } - } - else if (!strcasecmp(optptr->value, "two-sided-long-edge")) - { - /* - * Mark the appropriate duplex option for two-sided-long-edge output... - */ - - for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) - if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) - break; - - if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) - { - for (k = 0; k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); k ++) - if (ppdFindChoice(option, duplex_two_long[k])) - { - if (ppdMarkOption(ppd, duplex_options[j], duplex_two_long[k])) - conflict = 1; - - break; - } - } - } - else if (!strcasecmp(optptr->value, "two-sided-short-edge")) - { - /* - * Mark the appropriate duplex option for two-sided-short-edge output... - */ - - for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) - if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) - break; - - if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) - { - for (k = 0; k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); k ++) - if (ppdFindChoice(option, duplex_two_short[k])) - { - if (ppdMarkOption(ppd, duplex_options[j], duplex_two_short[k])) - conflict = 1; - - break; - } - } - } - } - else if (!strcasecmp(optptr->name, "resolution") || - !strcasecmp(optptr->name, "printer-resolution")) - { - if (ppdMarkOption(ppd, "Resolution", optptr->value)) - conflict = 1; - if (ppdMarkOption(ppd, "SetResolution", optptr->value)) - /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */ - conflict = 1; - if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */ - conflict = 1; - if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */ - conflict = 1; - } - else if (!strcasecmp(optptr->name, "output-bin")) - { - if (!cupsGetOption("OutputBin", num_options, options)) - if (ppdMarkOption(ppd, "OutputBin", optptr->value)) - conflict = 1; - } - else if (!strcasecmp(optptr->name, "multiple-document-handling")) - { - if (!cupsGetOption("Collate", num_options, options) && - ppdFindOption(ppd, "Collate")) - { - if (strcasecmp(optptr->value, "separate-documents-uncollated-copies")) - { - if (ppdMarkOption(ppd, "Collate", "True")) - conflict = 1; - } - else - { - if (ppdMarkOption(ppd, "Collate", "False")) - conflict = 1; - } - } - } - else if (!strcasecmp(optptr->name, "finishings")) - { - /* - * Lookup cupsIPPFinishings attributes for each value... - */ - - for (ptr = optptr->value; *ptr;) - { - /* - * Get the next finishings number... - */ - - if (!isdigit(*ptr & 255)) - break; - - if ((j = strtol(ptr, &ptr, 10)) < 3) - break; - - /* - * Skip separator as needed... - */ - - if (*ptr == ',') - ptr ++; - - /* - * Look it up in the PPD file... - */ - - sprintf(s, "%d", j); - - if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL) - continue; + if (!name || num_options <= 0 || !options) + { + DEBUG_puts("3cupsGetOption: Returning NULL"); + return (NULL); + } - /* - * Apply "*Option Choice" settings from the attribute value... - */ + match = cups_find_option(name, num_options, options, -1, &diff); - if (ppd_mark_choices(ppd, attr->value)) - conflict = 1; - } - } - else if (!strcasecmp(optptr->name, "mirror") && - ppdMarkOption(ppd, "MirrorPrint", optptr->value)) - conflict = 1; - else if (ppdMarkOption(ppd, optptr->name, optptr->value)) - conflict = 1; + if (!diff) + { + DEBUG_printf(("3cupsGetOption: Returning \"%s\"", options[match].value)); + return (options[match].value); + } - return (conflict); + DEBUG_puts("3cupsGetOption: Returning NULL"); + return (NULL); } @@ -445,8 +251,8 @@ cupsMarkOptions( * This function converts space-delimited name/value pairs according * to the PAPI text option ABNF specification. Collection values * ("name={a=... b=... c=...}") are stored with the curley brackets - * intact - use cupsParseOptions() on the value to extract the collection - * attributes. + * intact - use @code cupsParseOptions@ on the value to extract the + * collection attributes. */ int /* O - Number of options found */ @@ -458,24 +264,62 @@ cupsParseOptions( char *copyarg, /* Copy of input string */ *ptr, /* Pointer into string */ *name, /* Pointer to name */ - *value; /* Pointer to value */ + *value, /* Pointer to value */ + sep, /* Separator character */ + quote; /* Quote character */ - if (arg == NULL || options == NULL || num_options < 0) + DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)", arg, num_options, (void *)options)); + + /* + * Range check input... + */ + + if (!arg) + { + DEBUG_printf(("1cupsParseOptions: Returning %d", num_options)); + return (num_options); + } + + if (!options || num_options < 0) + { + DEBUG_puts("1cupsParseOptions: Returning 0"); return (0); + } /* * Make a copy of the argument string and then divide it up... */ - copyarg = strdup(arg); - ptr = copyarg; + if ((copyarg = strdup(arg)) == NULL) + { + DEBUG_puts("1cupsParseOptions: Unable to copy arg string"); + DEBUG_printf(("1cupsParseOptions: Returning %d", num_options)); + return (num_options); + } + + if (*copyarg == '{') + { + /* + * Remove surrounding {} so we can parse "{name=value ... name=value}"... + */ + + if ((ptr = copyarg + strlen(copyarg) - 1) > copyarg && *ptr == '}') + { + *ptr = '\0'; + ptr = copyarg + 1; + } + else + ptr = copyarg; + } + else + ptr = copyarg; /* * Skip leading spaces... */ - while (isspace(*ptr & 255)) + while (_cups_isspace(*ptr)) ptr ++; /* @@ -489,7 +333,7 @@ cupsParseOptions( */ name = ptr; - while (!isspace(*ptr & 255) && *ptr != '=' && *ptr != '\0') + while (!strchr("\f\n\r\t\v =", *ptr) && *ptr) ptr ++; /* @@ -503,16 +347,21 @@ cupsParseOptions( * Skip trailing spaces... */ - while (isspace(*ptr & 255)) + while (_cups_isspace(*ptr)) + *ptr++ = '\0'; + + if ((sep = *ptr) == '=') *ptr++ = '\0'; - if (*ptr != '=') + DEBUG_printf(("2cupsParseOptions: name=\"%s\"", name)); + + if (sep != '=') { /* - * Start of another option... + * Boolean option... */ - if (strncasecmp(name, "no", 2) == 0) + if (!_cups_strncasecmp(name, "no", 2)) num_options = cupsAddOption(name + 2, "false", num_options, options); else @@ -525,101 +374,84 @@ cupsParseOptions( * Remove = and parse the value... */ - *ptr++ = '\0'; + value = ptr; - if (*ptr == '\'') + while (*ptr && !_cups_isspace(*ptr)) { - /* - * Quoted string constant... - */ - - ptr ++; - value = ptr; - - while (*ptr != '\'' && *ptr != '\0') + if (*ptr == ',') + ptr ++; + else if (*ptr == '\'' || *ptr == '\"') { - if (*ptr == '\\') - _cups_strcpy(ptr, ptr + 1); + /* + * Quoted string constant... + */ - ptr ++; - } + quote = *ptr; + _cups_strcpy(ptr, ptr + 1); - if (*ptr != '\0') - *ptr++ = '\0'; - } - else if (*ptr == '\"') - { - /* - * Double-quoted string constant... - */ + while (*ptr != quote && *ptr) + { + if (*ptr == '\\' && ptr[1]) + _cups_strcpy(ptr, ptr + 1); - ptr ++; - value = ptr; + ptr ++; + } - while (*ptr != '\"' && *ptr != '\0') - { - if (*ptr == '\\') + if (*ptr) _cups_strcpy(ptr, ptr + 1); - - ptr ++; } + else if (*ptr == '{') + { + /* + * Collection value... + */ - if (*ptr != '\0') - *ptr++ = '\0'; - } - else if (*ptr == '{') - { - /* - * Collection value... - */ - - int depth; - - value = ptr; + int depth; - for (depth = 1; *ptr; ptr ++) - if (*ptr == '{') - depth ++; - else if (*ptr == '}') + for (depth = 0; *ptr; ptr ++) { - depth --; - if (!depth) + if (*ptr == '{') + depth ++; + else if (*ptr == '}') { - ptr ++; - - if (*ptr != ',') + depth --; + if (!depth) + { + ptr ++; break; + } } - } - else if (*ptr == '\\') - _cups_strcpy(ptr, ptr + 1); - - if (*ptr != '\0') - *ptr++ = '\0'; - } - else - { - /* - * Normal space-delimited string... - */ - - value = ptr; - - while (!isspace(*ptr & 255) && *ptr != '\0') + else if (*ptr == '\\' && ptr[1]) + _cups_strcpy(ptr, ptr + 1); + } + } + else { - if (*ptr == '\\') - _cups_strcpy(ptr, ptr + 1); + /* + * Normal space-delimited string... + */ - ptr ++; + while (*ptr && !_cups_isspace(*ptr)) + { + if (*ptr == '\\' && ptr[1]) + _cups_strcpy(ptr, ptr + 1); + + ptr ++; + } } } + if (*ptr != '\0') + *ptr++ = '\0'; + + DEBUG_printf(("2cupsParseOptions: value=\"%s\"", value)); + /* * Skip trailing whitespace... */ - while (isspace(*ptr & 255)) - *ptr++ = '\0'; + while (_cups_isspace(*ptr)) + ptr ++; /* * Add the string value... @@ -635,6 +467,8 @@ cupsParseOptions( free(copyarg); + DEBUG_printf(("1cupsParseOptions: Returning %d", num_options)); + return (num_options); } @@ -642,7 +476,7 @@ cupsParseOptions( /* * 'cupsRemoveOption()' - Remove an option from an option array. * - * @since CUPS 1.2@ + * @since CUPS 1.2/macOS 10.5@ */ int /* O - New number of options */ @@ -655,19 +489,24 @@ cupsRemoveOption( cups_option_t *option; /* Current option */ + DEBUG_printf(("2cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)", name, num_options, (void *)options)); + /* * Range check input... */ if (!name || num_options < 1 || !options) + { + DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options)); return (num_options); + } /* * Loop for the option... */ for (i = num_options, option = *options; i > 0; i --, option ++) - if (!strcasecmp(name, option->name)) + if (!_cups_strcasecmp(name, option->name)) break; if (i) @@ -676,107 +515,227 @@ cupsRemoveOption( * Remove this option from the array... */ + DEBUG_puts("4cupsRemoveOption: Found option, removing it..."); + num_options --; i --; - free(option->name); - if (option->value) - free(option->value); + _cupsStrFree(option->name); + _cupsStrFree(option->value); if (i > 0) - memmove(option, option + 1, i * sizeof(cups_option_t)); + memmove(option, option + 1, (size_t)i * sizeof(cups_option_t)); } /* * Return the new number of options... */ + DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options)); return (num_options); } /* - * 'ppd_mark_choices()' - Mark one or more option choices from a string. + * '_cupsGet1284Values()' - Get 1284 device ID keys and values. + * + * The returned dictionary is a CUPS option array that can be queried with + * cupsGetOption and freed with cupsFreeOptions. */ -static int /* O - 1 if there are conflicts, 0 otherwise */ -ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */ - const char *options) /* I - "*Option Choice ..." string */ +int /* O - Number of key/value pairs */ +_cupsGet1284Values( + const char *device_id, /* I - IEEE-1284 device ID string */ + cups_option_t **values) /* O - Array of key/value pairs */ { - char option[PPD_MAX_NAME], /* Current option */ - choice[PPD_MAX_NAME], /* Current choice */ - *ptr; /* Pointer into option or choice */ - int conflict = 0; /* Do we have a conflict? */ + int num_values; /* Number of values */ + char key[256], /* Key string */ + value[256], /* Value string */ + *ptr; /* Pointer into key/value */ + + /* + * Range check input... + */ - if (!options) + if (values) + *values = NULL; + + if (!device_id || !values) return (0); /* - * Read all of the "*Option Choice" pairs from the string, marking PPD - * options as we go... + * Parse the 1284 device ID value into keys and values. The format is + * repeating sequences of: + * + * [whitespace]key:value[whitespace]; */ - while (*options) + num_values = 0; + while (*device_id) { - /* - * Skip leading whitespace... - */ + while (_cups_isspace(*device_id)) + device_id ++; + + if (!*device_id) + break; - while (isspace(*options & 255)) - options ++; + for (ptr = key; *device_id && *device_id != ':'; device_id ++) + if (ptr < (key + sizeof(key) - 1)) + *ptr++ = *device_id; - if (*options != '*') + if (!*device_id) break; - /* - * Get the option name... - */ + while (ptr > key && _cups_isspace(ptr[-1])) + ptr --; - options ++; - ptr = option; - while (*options && !isspace(*options & 255) && - ptr < (option + sizeof(option) - 1)) - *ptr++ = *options++; + *ptr = '\0'; + device_id ++; - if (ptr == option) + while (_cups_isspace(*device_id)) + device_id ++; + + if (!*device_id) break; + for (ptr = value; *device_id && *device_id != ';'; device_id ++) + if (ptr < (value + sizeof(value) - 1)) + *ptr++ = *device_id; + + if (!*device_id) + break; + + while (ptr > value && _cups_isspace(ptr[-1])) + ptr --; + *ptr = '\0'; + device_id ++; + + num_values = cupsAddOption(key, value, num_values, values); + } + + return (num_values); +} + + +/* + * 'cups_compare_options()' - Compare two options. + */ + +static int /* O - Result of comparison */ +cups_compare_options(cups_option_t *a, /* I - First option */ + cups_option_t *b) /* I - Second option */ +{ + return (_cups_strcasecmp(a->name, b->name)); +} + +/* + * 'cups_find_option()' - Find an option using a binary search. + */ + +static int /* O - Index of match */ +cups_find_option( + const char *name, /* I - Option name */ + int num_options, /* I - Number of options */ + cups_option_t *options, /* I - Options */ + int prev, /* I - Previous index */ + int *rdiff) /* O - Difference of match */ +{ + int left, /* Low mark for binary search */ + right, /* High mark for binary search */ + current, /* Current index */ + diff; /* Result of comparison */ + cups_option_t key; /* Search key */ + + + DEBUG_printf(("7cups_find_option(name=\"%s\", num_options=%d, options=%p, prev=%d, rdiff=%p)", name, num_options, (void *)options, prev, (void *)rdiff)); + +#ifdef DEBUG + for (left = 0; left < num_options; left ++) + DEBUG_printf(("9cups_find_option: options[%d].name=\"%s\", .value=\"%s\"", + left, options[left].name, options[left].value)); +#endif /* DEBUG */ + + key.name = (char *)name; + + if (prev >= 0) + { /* - * Get the choice... + * Start search on either side of previous... */ - while (isspace(*options & 255)) - options ++; + if ((diff = cups_compare_options(&key, options + prev)) == 0 || + (diff < 0 && prev == 0) || + (diff > 0 && prev == (num_options - 1))) + { + *rdiff = diff; + return (prev); + } + else if (diff < 0) + { + /* + * Start with previous on right side... + */ + + left = 0; + right = prev; + } + else + { + /* + * Start wih previous on left side... + */ - if (!*options) - break; + left = prev; + right = num_options - 1; + } + } + else + { + /* + * Start search in the middle... + */ + + left = 0; + right = num_options - 1; + } - ptr = choice; - while (*options && !isspace(*options & 255) && - ptr < (choice + sizeof(choice) - 1)) - *ptr++ = *options++; + do + { + current = (left + right) / 2; + diff = cups_compare_options(&key, options + current); - *ptr = '\0'; + if (diff == 0) + break; + else if (diff < 0) + right = current; + else + left = current; + } + while ((right - left) > 1); + if (diff != 0) + { /* - * Mark the option... + * Check the last 1 or 2 elements... */ - if (ppdMarkOption(ppd, option, choice)) - conflict = 1; + if ((diff = cups_compare_options(&key, options + left)) <= 0) + current = left; + else + { + diff = cups_compare_options(&key, options + right); + current = right; + } } /* - * Return whether we had any conflicts... + * Return the closest destination and the difference... */ - return (conflict); -} - + *rdiff = diff; -/* - * End of "$Id: options.c 6649 2007-07-11 21:46:42Z mike $". - */ + return (current); +}