/*
- * "$Id: options.c 6943 2007-09-10 23:00:33Z mike $"
+ * "$Id: options.c 7589 2008-05-19 00:13:23Z mike $"
*
* Option routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
*
* 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.
- * debug_marked() - Output the marked array to stdout...
- * ppd_mark_choices() - Mark one or more option choices from a string.
+ * cupsAddOption() - Add an option to an option array.
+ * cupsFreeOptions() - Free all memory used by options.
+ * cupsGetOption() - Get an option value.
+ * cupsParseOptions() - Parse options from a command-line argument.
+ * cupsRemoveOption() - Remove an option from an option array.
*/
/*
#include "debug.h"
-/*
- * Local functions...
- */
-
-#ifdef DEBUG
-static void debug_marked(ppd_file_t *ppd, const char *title);
-#else
-# define debug_marked(ppd,title)
-#endif /* DEBUG */
-static int ppd_mark_choices(ppd_file_t *ppd, const char *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 */
- if (name == NULL || !name[0] || value == NULL ||
- options == NULL || num_options < 0)
+ DEBUG_printf(("cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, "
+ "options=%p)\n", name, value, num_options, options));
+
+ if (!name || !name[0] || !value || !options || num_options < 0)
+ {
+ DEBUG_printf(("cupsAddOption: Returning %d\n", num_options));
return (num_options);
+ }
/*
* Look for an existing option with the same name...
* No matching option name...
*/
+ DEBUG_puts("cupsAddOption: New option...");
+
if (num_options == 0)
temp = (cups_option_t *)malloc(sizeof(cups_option_t));
else
(num_options + 1));
if (temp == NULL)
+ {
+ DEBUG_puts("cupsAddOption: Unable to expand option array, returning 0");
return (0);
+ }
*options = temp;
temp += num_options;
* Match found; free the old value...
*/
+ DEBUG_puts("cupsAddOption: Option already exists...");
_cupsStrFree(temp->value);
}
temp->value = _cupsStrAlloc(value);
+ DEBUG_printf(("cupsAddOption: Returning %d\n", num_options));
+
return (num_options);
}
int i; /* Looping var */
- if (num_options <= 0 || options == NULL)
+ DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)\n", num_options,
+ options));
+
+ if (num_options <= 0 || !options)
return;
for (i = 0; i < num_options; i ++)
* 'cupsGetOption()' - Get an option value.
*/
-const char * /* O - Option value or NULL */
+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; /* Looping var */
- if (name == NULL || num_options <= 0 || options == NULL)
+ DEBUG_printf(("cupsGetOption(name=\"%s\", num_options=%d, options=%p)\n",
+ name, num_options, options));
+
+ if (!name || num_options <= 0 || !options)
+ {
+ DEBUG_puts("cupsGetOption: Returning NULL");
return (NULL);
+ }
for (i = 0; i < num_options; i ++)
- if (strcasecmp(options[i].name, name) == 0)
- return (options[i].value);
-
- return (NULL);
-}
-
-
-/*
- * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
- */
-
-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 */
-{
- 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);
-
- debug_marked(ppd, "Before...");
-
- /*
- * 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;
-
- 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)) /* EFI */
- conflict = 1;
-
- 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;
-
- /*
- * Apply "*Option Choice" settings from the attribute value...
- */
-
- if (ppd_mark_choices(ppd, attr->value))
- conflict = 1;
- }
- }
- else if (!strcasecmp(optptr->name, "mirror"))
+ if (!strcasecmp(options[i].name, name))
{
- if (ppdMarkOption(ppd, "MirrorPrint", optptr->value))
- conflict = 1;
+ DEBUG_printf(("cupsGetOption: Returning \"%s\"\n", options[i].value));
+ return (options[i].value);
}
- else if (ppdMarkOption(ppd, optptr->name, optptr->value))
- conflict = 1;
-
- debug_marked(ppd, "After...");
- return (conflict);
+ DEBUG_puts("cupsGetOption: Returning NULL");
+ return (NULL);
}
* 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 */
char *copyarg, /* Copy of input string */
*ptr, /* Pointer into string */
*name, /* Pointer to name */
- *value; /* Pointer to value */
+ *value, /* Pointer to value */
+ quote; /* Quote character */
- if (arg == NULL || options == NULL || num_options < 0)
+ DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)\n",
+ arg, num_options, options));
+
+ /*
+ * Range check input...
+ */
+
+ if (!arg)
+ {
+ DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
+ return (num_options);
+ }
+
+ if (!options || num_options < 0)
+ {
+ DEBUG_puts("cupsParseOptions: 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("cupsParseOptions: Unable to copy arg string");
+ DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
+ return (num_options);
+ }
+
+ ptr = copyarg;
/*
* Skip leading spaces...
*/
name = ptr;
- while (!isspace(*ptr & 255) && *ptr != '=' && *ptr != '\0')
+ while (!isspace(*ptr & 255) && *ptr != '=' && *ptr)
ptr ++;
/*
while (isspace(*ptr & 255))
*ptr++ = '\0';
+ DEBUG_printf(("cupsParseOptions: name=\"%s\"\n", name));
+
if (*ptr != '=')
{
/*
- * Start of another option...
+ * Boolean option...
*/
- if (strncasecmp(name, "no", 2) == 0)
+ if (!strncasecmp(name, "no", 2))
num_options = cupsAddOption(name + 2, "false", num_options,
options);
else
*/
*ptr++ = '\0';
+ value = ptr;
- if (*ptr == '\'')
+ while (*ptr && !isspace(*ptr & 255))
{
- /*
- * 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 (!isspace(*ptr & 255) && *ptr)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+
+ ptr ++;
+ }
}
}
+ if (*ptr != '\0')
+ *ptr++ = '\0';
+
+ DEBUG_printf(("cupsParseOptions: value=\"%s\"\n", value));
+
/*
* Skip trailing whitespace...
*/
while (isspace(*ptr & 255))
- *ptr++ = '\0';
+ ptr ++;
/*
* Add the string value...
free(copyarg);
+ DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options));
+
return (num_options);
}
cups_option_t *option; /* Current option */
+ DEBUG_printf(("cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)\n",
+ name, num_options, options));
+
/*
* Range check input...
*/
if (!name || num_options < 1 || !options)
+ {
+ DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
return (num_options);
+ }
/*
* Loop for the option...
* Remove this option from the array...
*/
+ DEBUG_puts("cupsRemoveOption: Found option, removing it...");
+
num_options --;
i --;
* Return the new number of options...
*/
+ DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options));
return (num_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_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...
- */
-
- while (*options)
- {
- /*
- * 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++;
-
- if (ptr == option)
- break;
-
- *ptr = '\0';
-
- /*
- * Get the choice...
- */
-
- while (isspace(*options & 255))
- options ++;
-
- if (!*options)
- break;
-
- ptr = choice;
- while (*options && !isspace(*options & 255) &&
- ptr < (choice + sizeof(choice) - 1))
- *ptr++ = *options++;
-
- *ptr = '\0';
-
- /*
- * Mark the option...
- */
-
- if (ppdMarkOption(ppd, option, choice))
- conflict = 1;
- }
-
- /*
- * Return whether we had any conflicts...
- */
-
- return (conflict);
-}
-
-
/*
- * End of "$Id: options.c 6943 2007-09-10 23:00:33Z mike $".
+ * End of "$Id: options.c 7589 2008-05-19 00:13:23Z mike $".
*/