/*
- * "$Id: mark.c 7278 2008-01-31 01:23:09Z mike $"
+ * "$Id: mark.c 8210 2009-01-09 02:30:26Z mike $"
*
- * Option marking routines for the Common UNIX Printing System (CUPS).
+ * Option marking routines for CUPS.
*
- * Copyright 2007-2008 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* Contents:
*
* cupsMarkOptions() - Mark command-line options in a PPD file.
- * ppdConflicts() - Check to see if there are any conflicts among the
- * marked option choices.
* ppdFindChoice() - Return a pointer to an option choice.
* ppdFindMarkedChoice() - Return the marked choice for the specified option.
* ppdFindOption() - Return a pointer to the specified option.
* ppdIsMarked() - Check to see if an option is marked.
* ppdMarkDefaults() - Mark all default options in the PPD file.
- * ppdMarkOption() - Mark an option in a PPD file.
+ * ppdMarkOption() - Mark an option in a PPD file and return the number
+ * of conflicts.
* ppdFirstOption() - Return the first option in the PPD file.
* ppdNextOption() - Return the next option in the PPD file.
- * debug_marked() - Output the marked array to stdout...
+ * _ppdParseOptions() - Parse options from a PPD file.
+ * ppd_debug_marked() - Output the marked array to stdout...
* ppd_defaults() - Set the defaults for this group and all sub-groups.
* ppd_mark_choices() - Mark one or more option choices from a string.
+ * ppd_mark_option() - Quickly mark an option without checking for
+ * conflicts.
*/
/*
#include "cups.h"
#include "string.h"
#include "debug.h"
+#include "pwg-private.h"
/*
*/
#ifdef DEBUG
-static void debug_marked(ppd_file_t *ppd, const char *title);
+static void ppd_debug_marked(ppd_file_t *ppd, const char *title);
#else
-# define debug_marked(ppd,title)
+# define ppd_debug_marked(ppd,title)
#endif /* DEBUG */
static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g);
-static int ppd_mark_choices(ppd_file_t *ppd, const char *options);
+static void ppd_mark_choices(ppd_file_t *ppd, const char *s);
+static void ppd_mark_option(ppd_file_t *ppd, const char *option,
+ const char *choice);
/*
* "sides" attributes to their corresponding PPD options and choices.
*/
-int /* O - 1 if conflicting */
+int /* O - 1 if conflicts exist, 0 otherwise */
cupsMarkOptions(
ppd_file_t *ppd, /* I - PPD file */
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 */
+ char *ptr, /* Pointer into string */
s[255]; /* Temporary string */
- const char *page_size; /* PageSize option */
+ const char *val, /* Pointer into value */
+ *media, /* media option */
+ *page_size, /* PageSize option */
+ *ppd_keyword; /* PPD keyword */
cups_option_t *optptr; /* Current option */
ppd_option_t *option; /* PPD option */
ppd_attr_t *attr; /* PPD attribute */
if (!ppd || num_options <= 0 || !options)
return (0);
- debug_marked(ppd, "Before...");
+ ppd_debug_marked(ppd, "Before...");
/*
- * Mark options...
+ * Do special handling for media and PageSize...
*/
- conflict = 0;
+ media = cupsGetOption("media", num_options, options);
+ page_size = cupsGetOption("PageSize", num_options, options);
- 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.
- */
+ if (media)
+ {
+ /*
+ * Load PWG mapping data as needed...
+ */
- page_size = cupsGetOption("PageSize", num_options, options);
+ if (!ppd->pwg)
+ ppd->pwg = _pwgCreateWithPPD(ppd);
- for (val = optptr->value; *val;)
- {
- /*
- * Extract the sub-option from the string...
- */
+ /*
+ * 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.
+ */
- for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
- *ptr++ = *val++;
- *ptr++ = '\0';
+ for (val = media; *val;)
+ {
+ /*
+ * Extract the sub-option from the string...
+ */
- if (*val == ',')
- val ++;
+ for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
+ *ptr++ = *val++;
+ *ptr++ = '\0';
- /*
- * Mark it...
- */
+ if (*val == ',')
+ val ++;
- if (!page_size || !page_size[0])
- if (ppdMarkOption(ppd, "PageSize", s))
- conflict = 1;
+ /*
+ * Mark it...
+ */
- if (cupsGetOption("InputSlot", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "InputSlot", s))
- conflict = 1;
+ if ((!page_size || !page_size[0]) &&
+ (ppd_keyword = _pwgGetPageSize((_pwg_t *)ppd->pwg, NULL, s,
+ NULL)) != NULL)
+ ppd_mark_option(ppd, "PageSize", ppd_keyword);
- if (cupsGetOption("MediaType", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "MediaType", s))
- conflict = 1;
+ if (!cupsGetOption("InputSlot", num_options, options) &&
+ (ppd_keyword = _pwgGetInputSlot((_pwg_t *)ppd->pwg, NULL, s)) != NULL)
+ ppd_mark_option(ppd, "InputSlot", ppd_keyword);
- if (cupsGetOption("EFMediaType", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "EFMediaType", s)) /* EFI */
- conflict = 1;
+ if (!cupsGetOption("MediaType", num_options, options) &&
+ (ppd_keyword = _pwgGetMediaType((_pwg_t *)ppd->pwg, NULL, s)) != NULL)
+ ppd_mark_option(ppd, "MediaType", ppd_keyword);
+ }
+ }
- if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */
- conflict = 1;
+ /*
+ * Mark other options...
+ */
- if (strcasecmp(s, "manual") == 0 &&
- cupsGetOption("ManualFeed", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "ManualFeed", "True"))
- conflict = 1;
- }
- }
+ for (i = num_options, optptr = options; i > 0; i --, optptr ++)
+ if (!strcasecmp(optptr->name, "media"))
+ continue;
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)
+ for (j = 0;
+ j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]));
+ j ++)
+ if (cupsGetOption(duplex_options[j], num_options, options))
break;
if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
* Mark the appropriate duplex option for one-sided output...
*/
- for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
+ 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 ++)
+ 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;
-
+ ppd_mark_option(ppd, duplex_options[j], duplex_one[k]);
break;
}
}
* Mark the appropriate duplex option for two-sided-long-edge output...
*/
- for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
+ 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 ++)
+ 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;
-
+ ppd_mark_option(ppd, duplex_options[j], duplex_two_long[k]);
break;
}
}
* Mark the appropriate duplex option for two-sided-short-edge output...
*/
- for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
+ 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 ++)
+ 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;
-
+ ppd_mark_option(ppd, duplex_options[j], duplex_two_short[k]);
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))
+ ppd_mark_option(ppd, "Resolution", optptr->value);
+ ppd_mark_option(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;
+ ppd_mark_option(ppd, "JCLResolution", optptr->value);
+ /* HP */
+ ppd_mark_option(ppd, "CNRes_PGP", optptr->value);
+ /* Canon */
}
else if (!strcasecmp(optptr->name, "output-bin"))
{
if (!cupsGetOption("OutputBin", num_options, options))
- if (ppdMarkOption(ppd, "OutputBin", optptr->value))
- conflict = 1;
+ ppd_mark_option(ppd, "OutputBin", optptr->value);
}
else if (!strcasecmp(optptr->name, "multiple-document-handling"))
{
ppdFindOption(ppd, "Collate"))
{
if (strcasecmp(optptr->value, "separate-documents-uncollated-copies"))
- {
- if (ppdMarkOption(ppd, "Collate", "True"))
- conflict = 1;
- }
+ ppd_mark_option(ppd, "Collate", "True");
else
- {
- if (ppdMarkOption(ppd, "Collate", "False"))
- conflict = 1;
- }
+ ppd_mark_option(ppd, "Collate", "False");
}
}
else if (!strcasecmp(optptr->name, "finishings"))
* Apply "*Option Choice" settings from the attribute value...
*/
- if (ppd_mark_choices(ppd, attr->value))
- conflict = 1;
+ ppd_mark_choices(ppd, attr->value);
}
}
- else if (!strcasecmp(optptr->name, "mirror"))
- {
- if (ppdMarkOption(ppd, "MirrorPrint", optptr->value))
- conflict = 1;
- }
- else if (ppdMarkOption(ppd, optptr->name, optptr->value))
- conflict = 1;
-
- debug_marked(ppd, "After...");
-
- return (conflict);
-}
-
-
-/*
- * 'ppdConflicts()' - Check to see if there are any conflicts among the
- * marked option choices.
- *
- * The returned value is the same as returned by @link ppdMarkOption@.
- */
-
-int /* O - Number of conflicts found */
-ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
-{
- int i, /* Looping variable */
- conflicts; /* Number of conflicts */
- ppd_const_t *c; /* Current constraint */
- ppd_option_t *o1, *o2; /* Options */
- ppd_choice_t *c1, *c2; /* Choices */
- ppd_choice_t key; /* Search key */
-
-
- if (!ppd)
- return (0);
-
- /*
- * Clear all conflicts...
- */
-
- conflicts = 0;
-
- for (o1 = ppdFirstOption(ppd); o1; o1 = ppdNextOption(ppd))
- o1->conflicted = 0;
-
- cupsArraySave(ppd->marked);
-
- /*
- * Loop through all of the UI constraints and flag any options
- * that conflict...
- */
-
- for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL;
- i > 0;
- i --, c ++)
- {
- /*
- * Grab pointers to the first option...
- */
-
- if (!o1 || strcmp(c->option1, o1->keyword))
- {
- o1 = ppdFindOption(ppd, c->option1);
- c1 = NULL;
- }
-
- if (!o1)
- continue;
- else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice)))
- {
- /*
- * This constraint maps to a specific choice.
- */
-
- key.option = o1;
-
- if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
- (!c1->marked || strcmp(c->choice1, c1->choice)))
- c1 = NULL;
- }
- else if (!c1)
+ else if (!strcasecmp(optptr->name, "print-quality"))
{
- /*
- * This constraint applies to any choice for this option.
- */
+ ppd_option_t *output_mode = ppdFindOption(ppd, "OutputMode");
+ /* OutputMode option */
- key.option = o1;
-
- if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
- (!strcasecmp(c1->choice, "None") || !strcasecmp(c1->choice, "Off") ||
- !strcasecmp(c1->choice, "False")))
- c1 = NULL;
- }
+ if (!strcmp(optptr->value, "3"))
+ {
+ /*
+ * Draft quality...
+ */
- /*
- * Grab pointers to the second option...
- */
+ if (ppdFindChoice(output_mode, "Draft"))
+ ppd_mark_option(ppd, "OutputMode", "Draft");
+ else if (ppdFindChoice(output_mode, "Fast"))
+ ppd_mark_option(ppd, "OutputMode", "Fast");
- if (!o2 || strcmp(c->option2, o2->keyword))
- {
- o2 = ppdFindOption(ppd, c->option2);
- c2 = NULL;
- }
+ if ((attr = ppdFindAttr(ppd, "APPrinterPreset",
+ "DraftGray_with_Paper_Auto-Detect")) != NULL)
+ ppd_mark_choices(ppd, attr->value);
+ }
+ else if (!strcmp(optptr->value, "4"))
+ {
+ /*
+ * Normal quality...
+ */
- if (!o2)
- continue;
- else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
- {
- /*
- * This constraint maps to a specific choice.
- */
+ if (ppdFindChoice(output_mode, "Normal"))
+ ppd_mark_option(ppd, "OutputMode", "Normal");
+ else if (ppdFindChoice(output_mode, "Good"))
+ ppd_mark_option(ppd, "OutputMode", "Good");
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterPreset",
+ "Color_with_Paper_Auto-Detect")) != NULL)
+ ppd_mark_choices(ppd, attr->value);
+ else if ((attr = ppdFindAttr(ppd, "APPrinterPreset",
+ "Gray_with_Paper_Auto-Detect")) != NULL)
+ ppd_mark_choices(ppd, attr->value);
+ }
+ else if (!strcmp(optptr->value, "5"))
+ {
+ /*
+ * High/best/photo quality...
+ */
- key.option = o2;
+ if (ppdFindChoice(output_mode, "Best"))
+ ppd_mark_option(ppd, "OutputMode", "Best");
+ else if (ppdFindChoice(output_mode, "High"))
+ ppd_mark_option(ppd, "OutputMode", "High");
- if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
- (!c2->marked || strcmp(c->choice2, c2->choice)))
- c2 = NULL;
+ if ((attr = ppdFindAttr(ppd, "APPrinterPreset",
+ "Photo_on_Photo_Paper")) != NULL)
+ ppd_mark_choices(ppd, attr->value);
+ }
}
- else if (!c2)
+ else if (!strcasecmp(optptr->name, "APPrinterPreset"))
{
/*
- * This constraint applies to any choice for this option.
+ * Lookup APPrinterPreset value...
*/
- key.option = o2;
-
- if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
- (!strcasecmp(c2->choice, "None") || !strcasecmp(c2->choice, "Off") ||
- !strcasecmp(c2->choice, "False")))
- c2 = NULL;
- }
-
- /*
- * If both options are marked then there is a conflict...
- */
+ if ((attr = ppdFindAttr(ppd, "APPrinterPreset", optptr->value)) != NULL)
+ {
+ /*
+ * Apply "*Option Choice" settings from the attribute value...
+ */
- if (c1 && c1->marked && c2 && c2->marked)
- {
- DEBUG_printf(("%s->%s conflicts with %s->%s (%s %s %s %s)\n",
- o1->keyword, c1->choice, o2->keyword, c2->choice,
- c->option1, c->choice1, c->option2, c->choice2));
- conflicts ++;
- o1->conflicted = 1;
- o2->conflicted = 1;
+ ppd_mark_choices(ppd, attr->value);
+ }
}
- }
+ else if (!strcasecmp(optptr->name, "mirror"))
+ ppd_mark_option(ppd, "MirrorPrint", optptr->value);
+ else
+ ppd_mark_option(ppd, optptr->name, optptr->value);
- cupsArrayRestore(ppd->marked);
+ ppd_debug_marked(ppd, "After...");
- /*
- * Return the number of conflicts found...
- */
-
- return (conflicts);
+ return (ppdConflicts(ppd) > 0);
}
ppd_choice_t *c; /* Current choice */
- if (o == NULL || choice == NULL)
+ if (!o || !choice)
return (NULL);
+ if (choice[0] == '{' || !strncasecmp(choice, "Custom.", 7))
+ choice = "Custom";
+
for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
- if (strcasecmp(c->choice, choice) == 0)
+ if (!strcasecmp(c->choice, choice))
return (c);
return (NULL);
ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
const char *option) /* I - Keyword/option name */
{
- ppd_choice_t key; /* Search key for choice */
+ ppd_choice_t key, /* Search key for choice */
+ *marked; /* Marked choice */
+
+ DEBUG_printf(("2ppdFindMarkedChoice(ppd=%p, option=\"%s\")", ppd, option));
if ((key.option = ppdFindOption(ppd, option)) == NULL)
+ {
+ DEBUG_puts("3ppdFindMarkedChoice: Option not found, returning NULL");
return (NULL);
+ }
- return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
+ marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key);
+
+ DEBUG_printf(("3ppdFindMarkedChoice: Returning %p(%s)...", marked,
+ marked ? marked->choice : "NULL"));
+
+ return (marked);
}
/*
- * 'ppdMarkOption()' - Mark an option in a PPD file.
+ * 'ppdMarkOption()' - Mark an option in a PPD file and return the number of
+ * conflicts.
*/
int /* O - Number of conflicts */
ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
const char *option, /* I - Keyword */
const char *choice) /* I - Option name */
+{
+ DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")",
+ ppd, option, choice));
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !option || !choice)
+ return (0);
+
+ /*
+ * Mark the option...
+ */
+
+ ppd_mark_option(ppd, option, choice);
+
+ /*
+ * Return the number of conflicts...
+ */
+
+ return (ppdConflicts(ppd));
+}
+
+
+/*
+ * 'ppdFirstOption()' - Return the first option in the PPD file.
+ *
+ * Options are returned from all groups in ascending alphanumeric order.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ppd_option_t * /* O - First option or @code NULL@ */
+ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
+{
+ if (!ppd)
+ return (NULL);
+ else
+ return ((ppd_option_t *)cupsArrayFirst(ppd->options));
+}
+
+
+/*
+ * 'ppdNextOption()' - Return the next option in the PPD file.
+ *
+ * Options are returned from all groups in ascending alphanumeric order.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ppd_option_t * /* O - Next option or @code NULL@ */
+ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
+{
+ if (!ppd)
+ return (NULL);
+ else
+ return ((ppd_option_t *)cupsArrayNext(ppd->options));
+}
+
+
+/*
+ * '_ppdParseOptions()' - Parse options from a PPD file.
+ *
+ * This function looks for strings of the form:
+ *
+ * *option choice ... *optionN choiceN
+ *
+ * It stops when it finds a string that doesn't match this format.
+ */
+
+int /* O - Number of options */
+_ppdParseOptions(
+ const char *s, /* I - String to parse */
+ int num_options, /* I - Number of options */
+ cups_option_t **options) /* IO - Options */
+{
+ char option[PPD_MAX_NAME], /* Current option */
+ choice[PPD_MAX_NAME], /* Current choice */
+ *ptr; /* Pointer into option or choice */
+
+
+ if (!s)
+ return (num_options);
+
+ /*
+ * Read all of the "*Option Choice" pairs from the string, marking PPD
+ * options as we go...
+ */
+
+ while (*s)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*s & 255))
+ s ++;
+
+ if (*s != '*')
+ break;
+
+ /*
+ * Get the option name...
+ */
+
+ s ++;
+ ptr = option;
+ while (*s && !isspace(*s & 255) && ptr < (option + sizeof(option) - 1))
+ *ptr++ = *s++;
+
+ if (ptr == s)
+ break;
+
+ *ptr = '\0';
+
+ /*
+ * Get the choice...
+ */
+
+ while (isspace(*s & 255))
+ s ++;
+
+ if (!*s)
+ break;
+
+ ptr = choice;
+ while (*s && !isspace(*s & 255) && ptr < (choice + sizeof(choice) - 1))
+ *ptr++ = *s++;
+
+ *ptr = '\0';
+
+ /*
+ * Add it to the options array...
+ */
+
+ num_options = cupsAddOption(option, choice, num_options, options);
+ }
+
+ return (num_options);
+}
+
+
+#ifdef DEBUG
+/*
+ * 'ppd_debug_marked()' - Output the marked array to stdout...
+ */
+
+static void
+ppd_debug_marked(ppd_file_t *ppd, /* I - PPD file data */
+ const char *title) /* I - Title for list */
+{
+ ppd_choice_t *c; /* Current choice */
+
+
+ DEBUG_printf(("2cupsMarkOptions: %s", title));
+
+ for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
+ c;
+ c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
+ DEBUG_printf(("2cupsMarkOptions: %s=%s", c->option->keyword, c->choice));
+}
+#endif /* DEBUG */
+
+
+/*
+ * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
+ */
+
+static void
+ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
+ ppd_group_t *g) /* I - Group to default */
+{
+ int i; /* Looping var */
+ ppd_option_t *o; /* Current option */
+ ppd_group_t *sg; /* Current sub-group */
+
+
+ for (i = g->num_options, o = g->options; i > 0; i --, o ++)
+ if (strcasecmp(o->keyword, "PageRegion") != 0)
+ ppdMarkOption(ppd, o->keyword, o->defchoice);
+
+ for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
+ ppd_defaults(ppd, sg);
+}
+
+
+/*
+ * 'ppd_mark_choices()' - Mark one or more option choices from a string.
+ */
+
+static void
+ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */
+ const char *s) /* I - "*Option Choice ..." string */
+{
+ int i, /* Looping var */
+ num_options; /* Number of options */
+ cups_option_t *options, /* Options */
+ *option; /* Current option */
+
+
+ if (!s)
+ return;
+
+ options = NULL;
+ num_options = _ppdParseOptions(s, 0, &options);
+
+ for (i = num_options, option = options; i > 0; i --, option ++)
+ ppd_mark_option(ppd, option->name, option->value);
+
+ cupsFreeOptions(num_options, options);
+}
+
+
+/*
+ * 'ppd_mark_option()' - Quick mark an option without checking for conflicts.
+ */
+
+static void
+ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */
+ const char *option, /* I - Option name */
+ const char *choice) /* I - Choice name */
{
int i, j; /* Looping vars */
ppd_option_t *o; /* Option pointer */
struct lconv *loc; /* Locale data */
- DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n",
+ DEBUG_printf(("7ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")",
ppd, option, choice));
- /*
- * Range check input...
- */
-
- if (!ppd || !option || !choice)
- return (0);
-
/*
* AP_D_InputSlot is the "default input slot" on MacOS X, and setting
* it clears the regular InputSlot choices...
if (!strcasecmp(option, "AP_D_InputSlot"))
{
+ cupsArraySave(ppd->options);
+
if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
{
key.option = o;
cupsArrayRemove(ppd->marked, oldc);
}
}
+
+ cupsArrayRestore(ppd->options);
}
/*
* Check for custom options...
*/
- if ((o = ppdFindOption(ppd, option)) == NULL)
- return (0);
+ cupsArraySave(ppd->options);
+
+ o = ppdFindOption(ppd, option);
+
+ cupsArrayRestore(ppd->options);
+
+ if (!o)
+ return;
loc = localeconv();
*/
if ((c = ppdFindChoice(o, "Custom")) == NULL)
- return (0);
+ return;
if (!strcasecmp(option, "PageSize"))
{
if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
{
if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
- return (0);
+ return;
switch (cparam->type)
{
if (units)
{
if (!strcasecmp(units, "cm"))
- cparam->current.custom_points *= 72.0f / 2.54f;
+ cparam->current.custom_points *= 72.0f / 2.54f;
else if (!strcasecmp(units, "mm"))
- cparam->current.custom_points *= 72.0f / 25.4f;
+ cparam->current.custom_points *= 72.0f / 25.4f;
else if (!strcasecmp(units, "m"))
- cparam->current.custom_points *= 72.0f / 0.0254f;
+ cparam->current.custom_points *= 72.0f / 0.0254f;
else if (!strcasecmp(units, "in"))
- cparam->current.custom_points *= 72.0f;
+ cparam->current.custom_points *= 72.0f;
else if (!strcasecmp(units, "ft"))
- cparam->current.custom_points *= 12.0f * 72.0f;
+ cparam->current.custom_points *= 12.0f * 72.0f;
}
break;
if ((c = ppdFindChoice(o, "Custom")) == NULL)
- return (0);
+ return;
if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
{
- num_vals = cupsParseOptions(choice + 1, 0, &vals);
+ num_vals = cupsParseOptions(choice, 0, &vals);
for (i = 0, val = vals; i < num_vals; i ++, val ++)
{
if (cparam->current.custom_string)
_cupsStrFree(cparam->current.custom_string);
- cparam->current.custom_string = _cupsStrAlloc(val->value);
+ cparam->current.custom_string = _cupsStrRetain(val->value);
break;
}
}
break;
if (!i)
- return (0);
+ return;
}
/*
* appropriate...
*/
+ cupsArraySave(ppd->options);
+
if (!strcasecmp(option, "PageSize"))
{
if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
}
}
}
+
+ cupsArrayRestore(ppd->options);
}
else if (!strcasecmp(option, "InputSlot"))
{
* Unmark ManualFeed option...
*/
+ cupsArraySave(ppd->options);
+
if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
{
key.option = o;
cupsArrayRemove(ppd->marked, oldc);
}
}
+
+ cupsArrayRestore(ppd->options);
}
else if (!strcasecmp(option, "ManualFeed") &&
!strcasecmp(choice, "True"))
* Unmark InputSlot option...
*/
+ cupsArraySave(ppd->options);
+
if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
{
key.option = o;
cupsArrayRemove(ppd->marked, oldc);
}
}
+
+ cupsArrayRestore(ppd->options);
}
}
c->marked = 1;
cupsArrayAdd(ppd->marked, c);
-
- /*
- * Return the number of conflicts...
- */
-
- return (ppdConflicts(ppd));
}
/*
- * 'ppdFirstOption()' - Return the first option in the PPD file.
- *
- * Options are returned from all groups in ascending alphanumeric order.
+ * 'ppd_mark_size()' - Quickly mark a page size without checking for conflicts.
*
- * @since CUPS 1.2@
- */
-
-ppd_option_t * /* O - First option or @code NULL@ */
-ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
-{
- if (!ppd)
- return (NULL);
- else
- return ((ppd_option_t *)cupsArrayFirst(ppd->options));
-}
-
-
-/*
- * 'ppdNextOption()' - Return the next option in the PPD file.
- *
- * Options are returned from all groups in ascending alphanumeric order.
- *
- * @since CUPS 1.2@
- */
-
-ppd_option_t * /* O - Next option or @code NULL@ */
-ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
-{
- if (!ppd)
- return (NULL);
- else
- return ((ppd_option_t *)cupsArrayNext(ppd->options));
-}
-
-
-#ifdef DEBUG
-/*
- * 'debug_marked()' - Output the marked array to stdout...
- */
-
-static void
-debug_marked(ppd_file_t *ppd, /* I - PPD file data */
- const char *title) /* I - Title for list */
-{
- ppd_choice_t *c; /* Current choice */
-
-
- printf("cupsMarkOptions: %s\n", title);
-
- for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
- c;
- c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
- printf("cupsMarkOptions: %s=%s\n", c->option->keyword, c->choice);
-}
-#endif /* DEBUG */
-
-
-/*
- * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
+ * This function is also responsible for mapping PWG/ISO/IPP size names to the
+ * PPD file...
*/
static void
-ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
- ppd_group_t *g) /* I - Group to default */
+ppd_mark_size(ppd_file_t *ppd, /* I - PPD file */
+ const char *size) /* I - Size name */
{
- int i; /* Looping var */
- ppd_option_t *o; /* Current option */
- ppd_group_t *sg; /* Current sub-group */
-
-
- for (i = g->num_options, o = g->options; i > 0; i --, o ++)
- if (strcasecmp(o->keyword, "PageRegion") != 0)
- ppdMarkOption(ppd, o->keyword, o->defchoice);
-
- for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
- ppd_defaults(ppd, sg);
-}
+ int i; /* Looping var */
+ _cups_pwg_media_t *pwgmedia; /* PWG media information */
+ ppd_size_t *ppdsize; /* Current PPD size */
+ double dw, dl; /* Difference in width and height */
+ double width, /* Width to find */
+ length; /* Length to find */
+ char width_str[256], /* Width in size name */
+ length_str[256],/* Length in size name */
+ units[256], /* Units in size name */
+ custom[256]; /* Custom size */
+ struct lconv *loc; /* Localization data */
-/*
- * 'ppd_mark_choices()' - Mark one or more option choices from a string.
- */
-
-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 */
-{
- 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? */
-
-
- if (!options)
- return (0);
-
/*
- * Read all of the "*Option Choice" pairs from the string, marking PPD
- * options as we go...
+ * See if this is a PPD size...
*/
- while (*options)
+ if (!strncasecmp(size, "Custom.", 7) || ppdPageSize(ppd, size))
{
- /*
- * Skip leading whitespace...
- */
-
- while (isspace(*options & 255))
- options ++;
-
- if (*options != '*')
- break;
-
- /*
- * Get the option name...
- */
-
- options ++;
- ptr = option;
- while (*options && !isspace(*options & 255) &&
- ptr < (option + sizeof(option) - 1))
- *ptr++ = *options++;
+ ppd_mark_option(ppd, "PageSize", size);
+ return;
+ }
- if (ptr == option)
- break;
+ /*
+ * Nope, try looking up the PWG or legacy (IPP/ISO) size name...
+ */
- *ptr = '\0';
+ if ((pwgmedia = _cupsPWGMediaByName(size)) == NULL)
+ pwgmedia = _cupsPWGMediaByLegacy(size);
+ if (pwgmedia)
+ {
+ width = pwgmedia->width;
+ length = pwgmedia->length;
+ }
+ else if (sscanf(size, "%*[^_]_%*[^_]_%255[0-9.]x%255[0-9.]%s", width_str,
+ length_str, units) == 3)
+ {
/*
- * Get the choice...
+ * Got a "self-describing" name that isn't in our table...
*/
- while (isspace(*options & 255))
- options ++;
-
- if (!*options)
- break;
+ loc = localeconv();
+ width = _cupsStrScand(width_str, NULL, loc);
+ length = _cupsStrScand(length_str, NULL, loc);
- ptr = choice;
- while (*options && !isspace(*options & 255) &&
- ptr < (choice + sizeof(choice) - 1))
- *ptr++ = *options++;
+ if (!strcmp(units, "in"))
+ {
+ width *= 72.0;
+ length *= 72.0;
+ }
+ else if (!strcmp(units, "mm"))
+ {
+ width *= 25.4 / 72.0;
+ length *= 25.4 / 72.0;
+ }
+ else
+ return;
+ }
+ else
+ return;
- *ptr = '\0';
+ /*
+ * Search the PPD file for a matching size...
+ */
- /*
- * Mark the option...
- */
+ for (i = ppd->num_sizes, ppdsize = ppd->sizes; i > 0; i --, ppdsize ++)
+ {
+ dw = ppdsize->width - width;
+ dl = ppdsize->length - length;
- if (ppdMarkOption(ppd, option, choice))
- conflict = 1;
+ if (dw > -5.0 && dw < 5.0 && dl > -5.0 && dl < 5.0)
+ {
+ ppd_mark_option(ppd, "PageSize", ppdsize->name);
+ return;
+ }
}
/*
- * Return whether we had any conflicts...
+ * No match found; if custom sizes are supported, set a custom size...
*/
- return (conflict);
+ if (ppd->variable_sizes)
+ {
+ snprintf(custom, sizeof(custom), "Custom.%dx%d", (int)width, (int)length);
+ ppd_mark_option(ppd, "PageSize", custom);
+ }
}
/*
- * End of "$Id: mark.c 7278 2008-01-31 01:23:09Z mike $".
+ * End of "$Id: mark.c 8210 2009-01-09 02:30:26Z mike $".
*/