-CHANGES.txt - 2008-07-14
+CHANGES.txt - 2008-07-18
------------------------
CHANGES IN CUPS V1.4b1
+ - Added support for new cupsUIConstraints and cupsUIResolver
+ attributes for better option conflict detection and
+ resolution.
+ - Increased the maximum size of 1284 device ID strings to
+ 256 bytes (STR #2877)
- Added an AccessLogLevel directive to cupsd.conf to control
what is logged to the access_log file.
- The default LogLevel is now "warn" instead of "info" to reduce
backend.o: backend.h versioning.h globals.h string.h ../config.h
backend.o: http-private.h http.h md5.h ipp-private.h ipp.h cups.h ppd.h
backend.o: array.h file.h language.h i18n.h transcode.h
+conflicts.o: ppd-private.h cups.h ipp.h http.h versioning.h ppd.h array.h
+conflicts.o: file.h language.h string.h ../config.h debug.h
custom.o: globals.h string.h ../config.h http-private.h http.h versioning.h
custom.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
custom.o: i18n.h transcode.h debug.h
request.o: globals.h string.h ../config.h http-private.h http.h versioning.h
request.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
request.o: i18n.h transcode.h debug.h
-sidechannel.o: sidechannel.h versioning.h string.h ../config.h
+sidechannel.o: sidechannel.h versioning.h string.h ../config.h debug.h
snmp.o: globals.h string.h ../config.h http-private.h http.h versioning.h
snmp.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
snmp.o: i18n.h transcode.h debug.h snmp-private.h
testarray.o: debug.h
testcups.o: cups.h ipp.h http.h versioning.h ppd.h array.h file.h language.h
testfile.o: string.h ../config.h file.h versioning.h debug.h
-testhttp.o: http.h versioning.h string.h ../config.h
+testhttp.o: http-private.h ../config.h http.h versioning.h md5.h
+testhttp.o: ipp-private.h ipp.h string.h
testi18n.o: i18n.h transcode.h language.h array.h versioning.h string.h
testi18n.o: ../config.h
testipp.o: ../cups/string.h ../config.h string.h ipp-private.h ipp.h http.h
testoptions.o: array.h file.h language.h
testlang.o: i18n.h transcode.h language.h array.h versioning.h string.h
testlang.o: ../config.h
-testppd.o: ../cups/string.h ../config.h string.h ppd.h array.h versioning.h
-testppd.o: file.h
+testppd.o: ../cups/string.h ../config.h string.h cups.h ipp.h http.h
+testppd.o: versioning.h ppd.h array.h file.h language.h
testsnmp.o: string.h ../config.h snmp-private.h http.h versioning.h
# DO NOT DELETE
backend.32.o: backend.c backend.h versioning.h globals.h string.h ../config.h
backend.32.o: backend.c http-private.h http.h md5.h ipp-private.h ipp.h cups.h ppd.h
backend.32.o: backend.c array.h file.h language.h i18n.h transcode.h
+conflicts.32.o: conflicts.c ppd-private.h cups.h ipp.h http.h versioning.h ppd.h array.h
+conflicts.32.o: conflicts.c file.h language.h string.h ../config.h debug.h
custom.32.o: custom.c globals.h string.h ../config.h http-private.h http.h versioning.h
custom.32.o: custom.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
custom.32.o: custom.c i18n.h transcode.h debug.h
request.32.o: request.c globals.h string.h ../config.h http-private.h http.h versioning.h
request.32.o: request.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
request.32.o: request.c i18n.h transcode.h debug.h
-sidechannel.32.o: sidechannel.c sidechannel.h versioning.h string.h ../config.h
+sidechannel.32.o: sidechannel.c sidechannel.h versioning.h string.h ../config.h debug.h
snmp.32.o: snmp.c globals.h string.h ../config.h http-private.h http.h versioning.h
snmp.32.o: snmp.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
snmp.32.o: snmp.c i18n.h transcode.h debug.h snmp-private.h
testarray.32.o: testarray.c debug.h
testcups.32.o: testcups.c cups.h ipp.h http.h versioning.h ppd.h array.h file.h language.h
testfile.32.o: testfile.c string.h ../config.h file.h versioning.h debug.h
-testhttp.32.o: testhttp.c http.h versioning.h string.h ../config.h
+testhttp.32.o: testhttp.c http-private.h ../config.h http.h versioning.h md5.h
+testhttp.32.o: testhttp.c ipp-private.h ipp.h string.h
testi18n.32.o: testi18n.c i18n.h transcode.h language.h array.h versioning.h string.h
testi18n.32.o: testi18n.c ../config.h
testipp.32.o: testipp.c ../cups/string.h ../config.h string.h ipp-private.h ipp.h http.h
testoptions.32.o: testoptions.c array.h file.h language.h
testlang.32.o: testlang.c i18n.h transcode.h language.h array.h versioning.h string.h
testlang.32.o: testlang.c ../config.h
-testppd.32.o: testppd.c ../cups/string.h ../config.h string.h ppd.h array.h versioning.h
-testppd.32.o: testppd.c file.h
+testppd.32.o: testppd.c ../cups/string.h ../config.h string.h cups.h ipp.h http.h
+testppd.32.o: testppd.c versioning.h ppd.h array.h file.h language.h
testsnmp.32.o: testsnmp.c string.h ../config.h snmp-private.h http.h versioning.h
# DO NOT DELETE
backend.64.o: backend.c backend.h versioning.h globals.h string.h ../config.h
backend.64.o: backend.c http-private.h http.h md5.h ipp-private.h ipp.h cups.h ppd.h
backend.64.o: backend.c array.h file.h language.h i18n.h transcode.h
+conflicts.64.o: conflicts.c ppd-private.h cups.h ipp.h http.h versioning.h ppd.h array.h
+conflicts.64.o: conflicts.c file.h language.h string.h ../config.h debug.h
custom.64.o: custom.c globals.h string.h ../config.h http-private.h http.h versioning.h
custom.64.o: custom.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
custom.64.o: custom.c i18n.h transcode.h debug.h
request.64.o: request.c globals.h string.h ../config.h http-private.h http.h versioning.h
request.64.o: request.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
request.64.o: request.c i18n.h transcode.h debug.h
-sidechannel.64.o: sidechannel.c sidechannel.h versioning.h string.h ../config.h
+sidechannel.64.o: sidechannel.c sidechannel.h versioning.h string.h ../config.h debug.h
snmp.64.o: snmp.c globals.h string.h ../config.h http-private.h http.h versioning.h
snmp.64.o: snmp.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
snmp.64.o: snmp.c i18n.h transcode.h debug.h snmp-private.h
testarray.64.o: testarray.c debug.h
testcups.64.o: testcups.c cups.h ipp.h http.h versioning.h ppd.h array.h file.h language.h
testfile.64.o: testfile.c string.h ../config.h file.h versioning.h debug.h
-testhttp.64.o: testhttp.c http.h versioning.h string.h ../config.h
+testhttp.64.o: testhttp.c http-private.h ../config.h http.h versioning.h md5.h
+testhttp.64.o: testhttp.c ipp-private.h ipp.h string.h
testi18n.64.o: testi18n.c i18n.h transcode.h language.h array.h versioning.h string.h
testi18n.64.o: testi18n.c ../config.h
testipp.64.o: testipp.c ../cups/string.h ../config.h string.h ipp-private.h ipp.h http.h
testoptions.64.o: testoptions.c array.h file.h language.h
testlang.64.o: testlang.c i18n.h transcode.h language.h array.h versioning.h string.h
testlang.64.o: testlang.c ../config.h
-testppd.64.o: testppd.c ../cups/string.h ../config.h string.h ppd.h array.h versioning.h
-testppd.64.o: testppd.c file.h
+testppd.64.o: testppd.c ../cups/string.h ../config.h string.h cups.h ipp.h http.h
+testppd.64.o: testppd.c versioning.h ppd.h array.h file.h language.h
testsnmp.64.o: testsnmp.c string.h ../config.h snmp-private.h http.h versioning.h
auth.o \
backchannel.o \
backend.o \
+ conflicts.o \
custom.o \
debug.o \
dest.o \
mxmldoc --section "Programming" --title "PPD API" \
--css ../doc/cups-printable.css \
--header api-ppd.header --intro api-ppd.shtml \
- ppd.h attr.c custom.c emit.c localize.c mark.c page.c \
+ ppd.h attr.c conflicts.c custom.c emit.c localize.c mark.c page.c \
ppd.c >../doc/help/api-ppd.html
mxmldoc --section "Programming" --title "HTTP and IPP APIs" \
--css ../doc/cups-printable.css \
--section "Programming" --title "PPD API" \
--css ../doc/cups-printable.css \
--header api-ppd.header --intro api-ppd.shtml \
- ppd.h attr.c custom.c emit.c localize.c mark.c page.c \
- ppd.c
+ ppd.h attr.c conflicts.c custom.c emit.c localize.c mark.c \
+ page.c ppd.c
mxmldoc --framed api-httpipp \
--section "Programming" --title "HTTP and IPP APIs" \
--css ../doc/cups-printable.css \
const char *resource) _CUPS_API_1_4;
extern ssize_t cupsReadResponseData(http_t *http, char *buffer,
size_t length) _CUPS_API_1_4;
+extern int cupsResolveConflicts(ppd_file_t *ppd, const char *option,
+ const char *choice,
+ int *num_options,
+ cups_option_t **options);
extern http_status_t cupsSendRequest(http_t *http, ipp_t *request,
const char *resource,
size_t length) _CUPS_API_1_4;
__ppdHashName
__ppdLocalizedAttr
__ppdNormalizeMakeAndModel
+__ppdParseOptions
_cupsAddDest
_cupsAddOption
_cupsAdminCreateWindowsPPD
_cupsReadResponseData
_cupsRemoveDest
_cupsRemoveOption
+_cupsResolveConflicts
_cupsSendRequest
_cupsServer
_cupsSetDefaultDest
_ppdFindOption
_ppdFirstCustomParam
_ppdFirstOption
+_ppdInstallableConflict
_ppdIsMarked
_ppdLastError
_ppdLocalize
_ppdHashName
_ppdLocalizedAttr
_ppdNormalizeMakeAndModel
+_ppdParseOptions
\ No newline at end of file
/*
- * "$Id: mark.c 7605 2008-05-21 00:36:25Z mike $"
+ * "$Id: mark.c 7757 2008-07-18 16:43:43Z mike $"
*
* Option marking routines for the Common UNIX Printing System (CUPS).
*
* 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.
+ * _ppdParseOptions() - Parse options from a PPD file.
* 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() - Quick mark an option without checking for
+ * conflicts.
*/
/*
#ifdef DEBUG
static void debug_marked(ppd_file_t *ppd, const char *title);
#else
-# define debug_marked(ppd,title)
+# define 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 */
s[255]; /* Temporary string */
* Mark options...
*/
- conflict = 0;
-
for (i = num_options, optptr = options; i > 0; i --, optptr ++)
if (!strcasecmp(optptr->name, "media"))
{
*/
if (!page_size || !page_size[0])
- if (ppdMarkOption(ppd, "PageSize", s))
- conflict = 1;
+ ppd_mark_option(ppd, "PageSize", s);
if (cupsGetOption("InputSlot", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "InputSlot", s))
- conflict = 1;
+ ppd_mark_option(ppd, "InputSlot", s);
if (cupsGetOption("MediaType", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "MediaType", s))
- conflict = 1;
+ ppd_mark_option(ppd, "MediaType", s);
if (cupsGetOption("EFMediaType", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "EFMediaType", s)) /* EFI */
- conflict = 1;
+ ppd_mark_option(ppd, "EFMediaType", s); /* EFI */
if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */
- conflict = 1;
+ ppd_mark_option(ppd, "EFMediaQualityMode", s); /* EFI */
- if (strcasecmp(s, "manual") == 0 &&
- cupsGetOption("ManualFeed", num_options, options) == NULL)
- if (ppdMarkOption(ppd, "ManualFeed", "True"))
- conflict = 1;
+ if (!strcasecmp(s, "manual") &&
+ !cupsGetOption("ManualFeed", num_options, options))
+ ppd_mark_option(ppd, "ManualFeed", "True");
}
}
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)))
+ else if (!strcasecmp(optptr->name, "APPrinterPreset"))
{
/*
- * This constraint maps to a specific choice.
+ * Lookup APPrinterPreset value...
*/
- 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)
- {
- /*
- * This constraint applies to any choice for this 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;
- }
-
- /*
- * Grab pointers to the second option...
- */
-
- if (!o2 || strcmp(c->option2, o2->keyword))
- {
- o2 = ppdFindOption(ppd, c->option2);
- c2 = NULL;
- }
-
- if (!o2)
- continue;
- else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
- {
- /*
- * This constraint maps to a specific choice.
- */
-
- key.option = o2;
-
- if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
- (!c2->marked || strcmp(c->choice2, c2->choice)))
- c2 = NULL;
- }
- else if (!c2)
- {
- /*
- * This constraint applies to any choice for this option.
- */
-
- 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);
+ }
}
- }
-
- cupsArrayRestore(ppd->marked);
+ else if (!strcasecmp(optptr->name, "mirror"))
+ ppd_mark_option(ppd, "MirrorPrint", optptr->value);
+ else
+ ppd_mark_option(ppd, optptr->name, optptr->value);
- /*
- * Return the number of conflicts found...
- */
+ debug_marked(ppd, "After...");
- return (conflicts);
+ return (ppdConflicts(ppd) > 0);
}
/*
- * '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 */
const char *option, /* I - Keyword */
const char *choice) /* I - Option name */
{
- int i, j; /* Looping vars */
- ppd_option_t *o; /* Option pointer */
- ppd_choice_t *c, /* Choice pointer */
- *oldc, /* Old choice pointer */
- key; /* Search key for choice */
- struct lconv *loc; /* Locale data */
-
-
DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n",
ppd, option, choice));
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@
+ */
+
+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));
+}
+
+
+/*
+ * '_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
+/*
+ * '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 */
+
+
+ DEBUG_printf(("cupsMarkOptions: %s\n", title));
+
+ for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
+ c;
+ c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
+ DEBUG_printf(("cupsMarkOptions: %s=%s\n", 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 (!options)
+ 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 */
+ ppd_choice_t *c, /* Choice pointer */
+ *oldc, /* Old choice pointer */
+ key; /* Search key for choice */
+ struct lconv *loc; /* Locale data */
+
+
+ DEBUG_printf(("ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")\n",
+ ppd, option, choice));
+
/*
* AP_D_InputSlot is the "default input slot" on MacOS X, and setting
* it clears the regular InputSlot choices...
*/
if ((o = ppdFindOption(ppd, option)) == NULL)
- return (0);
+ 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 ((c = ppdFindChoice(o, "Custom")) == NULL)
- return (0);
+ return;
if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
{
break;
if (!i)
- return (0);
+ return;
}
/*
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.
- *
- * @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 */
-
-
- DEBUG_printf(("cupsMarkOptions: %s\n", title));
-
- for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
- c;
- c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
- DEBUG_printf(("cupsMarkOptions: %s=%s\n", 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 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: mark.c 7605 2008-05-21 00:36:25Z mike $".
+ * End of "$Id: mark.c 7757 2008-07-18 16:43:43Z mike $".
*/
# endif /* __cplusplus */
+/*
+ * Structures...
+ */
+
+typedef struct _ppd_cups_uiconst_s /**** Constraint from cupsUIConstraints ****/
+{
+ ppd_option_t *option; /* Constrained option */
+ ppd_choice_t *choice; /* Constrained choice or @code NULL@ */
+ int installable; /* Installable option? */
+} _ppd_cups_uiconst_t;
+
+typedef struct _ppd_cups_uiconsts_s /**** cupsUIConstraints ****/
+{
+ char resolver[PPD_MAX_NAME]; /* Resolver name */
+ int installable, /* Constrained against any installable options? */
+ num_constraints; /* Number of constraints */
+ _ppd_cups_uiconst_t *constraints; /* Constraints */
+} _ppd_cups_uiconsts_t;
+
+
+/*
+ * Prototypes...
+ */
+
extern void _ppdFreeLanguages(cups_array_t *languages);
extern int _ppdGet1284Values(const char *device_id,
cups_option_t **values);
extern char *_ppdNormalizeMakeAndModel(const char *make_and_model,
char *buffer,
size_t bufsize);
+extern int _ppdParseOptions(const char *s, int num_options,
+ cups_option_t **options);
/*
* ppd_add_size() - Add a page size.
* ppd_compare_attrs() - Compare two attributes.
* ppd_compare_choices() - Compare two choices...
- * ppd_compare_consts() - Compare two constraints.
* ppd_compare_coptions() - Compare two custom options.
* ppd_compare_cparams() - Compare two custom parameters.
* ppd_compare_options() - Compare two options.
static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
-static int ppd_compare_consts(ppd_const_t *a, ppd_const_t *b);
static int ppd_compare_coptions(ppd_coption_t *a,
ppd_coption_t *b);
static int ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
break;
}
- /*
- * For CustomPageSize and InputSlot/ManualFeed, create a duplicate
- * constraint for PageRegion...
- */
-
- if (!strcasecmp(constraint->option1, "CustomPageSize") &&
- (!strcasecmp(constraint->option2, "InputSlot") ||
- !strcasecmp(constraint->option2, "ManualFeed")))
- {
- ppd->num_consts ++;
-
- strcpy(constraint[1].option1, "PageRegion");
- strcpy(constraint[1].choice1, "Custom");
- strcpy(constraint[1].option2, constraint->option2);
- strcpy(constraint[1].choice2, constraint->choice2);
- }
- else if (!strcasecmp(constraint->option2, "CustomPageSize") &&
- (!strcasecmp(constraint->option1, "InputSlot") ||
- !strcasecmp(constraint->option1, "ManualFeed")))
- {
- ppd->num_consts ++;
-
- strcpy(constraint[1].option1, constraint->option1);
- strcpy(constraint[1].choice1, constraint->choice1);
- strcpy(constraint[1].option2, "PageRegion");
- strcpy(constraint[1].choice2, "Custom");
- }
-
- /*
- * Handle CustomFoo option constraints...
- */
-
- if (!strncasecmp(constraint->option1, "Custom", 6) &&
- !strcasecmp(constraint->choice1, "True"))
- {
- _cups_strcpy(constraint->option1, constraint->option1 + 6);
- strcpy(constraint->choice1, "Custom");
- }
-
- if (!strncasecmp(constraint->option2, "Custom", 6) &&
- !strcasecmp(constraint->choice2, "True"))
- {
- _cups_strcpy(constraint->option2, constraint->option2 + 6);
- strcpy(constraint->choice2, "Custom");
- }
-
/*
* Don't add this one as an attribute...
*/
}
}
- /*
- * Sort the constraints...
- */
-
- if (ppd->num_consts > 1)
- qsort(ppd->consts, ppd->num_consts, sizeof(ppd_const_t),
- (int (*)(const void *, const void *))ppd_compare_consts);
-
/*
* Create an array to track the marked choices...
*/
}
-/*
- * 'ppd_compare_consts()' - Compare two constraints.
- */
-
-static int /* O - Result of comparison */
-ppd_compare_consts(ppd_const_t *a, /* I - First constraint */
- ppd_const_t *b) /* I - Second constraint */
-{
- int ret; /* Result of comparison */
-
-
- if ((ret = strcmp(a->option1, b->option1)) != 0)
- return (ret);
- else if ((ret = strcmp(a->choice1, b->choice1)) != 0)
- return (ret);
- else if ((ret = strcmp(a->option2, b->option2)) != 0)
- return (ret);
- else
- return (strcmp(a->choice2, b->choice2));
-}
-
-
/*
* 'ppd_compare_coptions()' - Compare two custom options.
*/
ppd_const_t *consts; /* UI/Non-UI constraints */
int num_fonts; /* Number of pre-loaded fonts */
char **fonts; /* Pre-loaded fonts */
- int num_profiles; /* Number of sRGB color profiles */
- ppd_profile_t *profiles; /* sRGB color profiles */
+ int num_profiles; /* Number of sRGB color profiles @deprecated@ */
+ ppd_profile_t *profiles; /* sRGB color profiles @deprecated@ */
int num_filters; /* Number of filters */
char **filters; /* Filter strings... */
/**** New in CUPS 1.3 ****/
cups_array_t *marked; /* Marked choices @since CUPS 1.3@ @private@ */
+
+ /**** New in CUPS 1.4 ****/
+ cups_array_t *cups_uiconstraints; /* cupsUIConstraints @since CUPS 1.4@ @private@ */
} ppd_file_t;
size_t bufsize) _CUPS_API_1_3;
/**** New in CUPS 1.4 ****/
+extern int ppdInstallableConflict(ppd_file_t *ppd,
+ const char *option,
+ const char *choice);
extern ppd_attr_t *ppdLocalizeAttr(ppd_file_t *ppd, const char *keyword,
const char *spec);
extern const char *ppdLocalizeMarkerName(ppd_file_t *ppd,
*% used with any known printers. Look at the PPD files in the "ppd"
*% subdirectory as well as the CUPS web site for working PPD files.
*%
-*% If you are a PPD file developer, consider using the CUPS DDK to
-*% create your PPD files - not only will it save you time, it produces
+*% If you are a PPD file developer, consider using the PPD compiler (ppdc)
+*% to create your PPD files - not only will it save you time, it produces
*% consistently high-quality files.
*%
-*% Copyright 2007 by Apple Inc.
+*% Copyright 2007-2008 by Apple Inc.
*% Copyright 2002-2006 by Easy Software Products.
*%
*% These coded instructions, statements, and computer programs are the
*LanguageEncoding: ISOLatin1
*PCFileName: "TEST.PPD"
*Manufacturer: "ESP"
-*Product: "(ESP Ghostscript)"
-*cupsVersion: 1.2
-*cupsManualCopies: True
-*cupsFilter: "application/vnd.cups-raster 0 rastertotest"
-*cupsModelNumber: 1
+*Product: "(Test)"
+*cupsVersion: 1.4
*ModelName: "Test"
*ShortNickName: "Test"
-*NickName: "Test for CUPS v1.3"
-*PSVersion: "(3010.000) 81501"
+*NickName: "Test for CUPS"
+*PSVersion: "(3010.000) 0"
*LanguageLevel: "3"
*ColorDevice: True
*DefaultColorSpace: RGB
*LandscapeOrientation: Plus90
*TTRasterizer: Type42
-*% These constraints are used to test ppdConflicts()
+*% These constraints are used to test ppdConflicts() and ppdResolveConflicts()
*UIConstraints: *PageSize Letter *InputSlot Envelope
*UIConstraints: *InputSlot Envelope *PageSize Letter
+*UIConstraints: *PageRegion Letter *InputSlot Envelope
+*UIConstraints: *InputSlot Envelope *PageRegion Letter
+
+*% These constraints are used to test ppdInstallableConflict()
+*UIConstraints: "*Duplex *InstalledDuplexer False"
+*UIConstraints: "*InstalledDuplexer False *Duplex"
*% For PageSize, we have put all of the translations in-line...
*OpenUI *PageSize/Page Size: PickOne
*InputSlot Envelope/Envelope Feed: "InputSlot=Envelope"
*CloseUI: *InputSlot
+*OpenUI *Duplex/2-Sided Printing: PickOne
+*OrderDependency: 10 DocumentSetup *Duplex
+*DefaultDuplex: None
+*Duplex None/Off: "Duplex=None"
+*Duplex DuplexNoTumble/Long Edge: "Duplex=DuplexNoTumble"
+*Duplex DuplexTumble/Short Edge: "Duplex=DuplexTumble"
+*CloseUI: *Duplex
+
+*% Installable option...
+*OpenGroup: InstallableOptions/Installable Options
+*OpenUI InstalledDuplexer/Duplexer Installed: Boolean
+*DefaultInstalledDuplexer: False
+*InstalledDuplexer False: ""
+*InstalledDuplexer True: ""
+*CloseUI: *InstalledDuplexer
+*CloseGroup: InstallableOptions
+
*% Custom options...
*OpenGroup: Extended/Extended Options
printf("_httpResolveURI(%s): ", argv[1]);
fflush(stdout);
- if (!_httpResolveURI(argv[1], resolved, sizeof(resolved)))
+ if (!_httpResolveURI(argv[1], resolved, sizeof(resolved), 0))
{
puts("FAIL");
return (1);
*
* PPD test program for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
*/
static const char *default_code =
+ "[{\n"
+ "%%BeginFeature: *InstalledDuplexer False\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
"[{\n"
"%%BeginFeature: *PageRegion Letter\n"
"PageRegion=Letter\n"
"} stopped cleartomark\n";
static const char *custom_code =
+ "[{\n"
+ "%%BeginFeature: *InstalledDuplexer False\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
"[{\n"
"%%BeginFeature: *InputSlot Tray\n"
"InputSlot=Tray\n"
main(int argc, /* I - Number of command-line arguments */
char *argv[]) /* I - Command-line arguments */
{
+ int i; /* Looping var */
ppd_file_t *ppd; /* PPD file loaded from disk */
int status; /* Status of tests (0 = success, 1 = fail) */
int conflicts; /* Number of conflicts */
char *s; /* String */
char buffer[8192]; /* String buffer */
const char *text; /* Localized text */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
status = 0;
* Do tests with test.ppd...
*/
- fputs("ppdOpenFile: ", stdout);
+ fputs("ppdOpenFile(test.ppd): ", stdout);
if ((ppd = ppdOpenFile("test.ppd")) != NULL)
puts("PASS");
if (s)
free(s);
+ /*
+ * Test constraints...
+ */
+
+ fputs("ppdConflicts(): ", stdout);
+ ppdMarkOption(ppd, "PageSize", "Letter");
+ ppdMarkOption(ppd, "InputSlot", "Envelope");
+
+ if ((conflicts = ppdConflicts(ppd)) == 2)
+ puts("PASS (2)");
+ else
+ {
+ printf("FAIL (%d)\n", conflicts);
+ status ++;
+ }
+
+ fputs("cupsResolveConflicts(): ", stdout);
+ num_options = 0;
+ options = NULL;
+ if (cupsResolveConflicts(ppd, "InputSlot", "Envelope", &num_options,
+ &options) &&
+ num_options == 1 && !strcasecmp(options->name, "InputSlot") &&
+ !strcasecmp(options->value, "Tray"))
+ puts("PASS");
+ else if (num_options > 0)
+ {
+ printf("FAIL (%d options:", num_options);
+ for (i = 0; i < num_options; i ++)
+ printf(" %s=%s", options[i].name, options[i].value);
+ puts(")");
+ status ++;
+ }
+ else
+ {
+ puts("FAIL (Unable to resolve!)");
+ status ++;
+ }
+ cupsFreeOptions(num_options, options);
+
+ fputs("ppdInstallableConflict(): ", stdout);
+ if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
+ !ppdInstallableConflict(ppd, "Duplex", "None"))
+ puts("PASS");
+ else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
+ {
+ puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
+ status ++;
+ }
+ else
+ {
+ puts("FAIL (Duplex=None conflicted)");
+ status ++;
+ }
+
/*
* Test localization...
*/
printf("FAIL (\"%s\" instead of \"Number 1 Cyan Toner\")\n",
text ? text : "(null)");
}
+
+ ppdClose(ppd);
+
+ /*
+ * Test new constraints...
+ */
+
+ fputs("ppdOpenFile(test2.ppd): ", stdout);
+
+ if ((ppd = ppdOpenFile("test2.ppd")) != NULL)
+ puts("PASS");
+ else
+ {
+ ppd_status_t err; /* Last error in file */
+ int line; /* Line number in file */
+
+
+ status ++;
+ err = ppdLastError(&line);
+
+ printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
+ }
+
+ fputs("ppdMarkDefaults: ", stdout);
+ ppdMarkDefaults(ppd);
+
+ if ((conflicts = ppdConflicts(ppd)) == 0)
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (%d conflicts)\n", conflicts);
+ }
+
+ fputs("ppdConflicts(): ", stdout);
+ ppdMarkOption(ppd, "PageSize", "Env10");
+ ppdMarkOption(ppd, "InputSlot", "Envelope");
+ ppdMarkOption(ppd, "Quality", "Photo");
+
+ if ((conflicts = ppdConflicts(ppd)) == 2)
+ puts("PASS (2)");
+ else
+ {
+ printf("FAIL (%d)\n", conflicts);
+ status ++;
+ }
+
+ fputs("cupsResolveConflicts(): ", stdout);
+ num_options = 0;
+ options = NULL;
+ if (cupsResolveConflicts(ppd, "Quality", "Photo", &num_options,
+ &options) &&
+ num_options == 1 && !strcasecmp(options->name, "Quality") &&
+ !strcasecmp(options->value, "Normal"))
+ puts("PASS");
+ else if (num_options > 0)
+ {
+ printf("FAIL (%d options:", num_options);
+ for (i = 0; i < num_options; i ++)
+ printf(" %s=%s", options[i].name, options[i].value);
+ puts(")");
+ status ++;
+ }
+ else
+ {
+ puts("FAIL (Unable to resolve!)");
+ status ++;
+ }
+ cupsFreeOptions(num_options, options);
+
+ fputs("cupsResolveConflicts(loop test): ", stdout);
+ ppdMarkOption(ppd, "PageSize", "A4");
+ ppdMarkOption(ppd, "Quality", "Photo");
+ num_options = 0;
+ options = NULL;
+ if (!cupsResolveConflicts(ppd, "Quality", "Photo", &num_options,
+ &options))
+ puts("PASS");
+ else if (num_options > 0)
+ {
+ printf("FAIL (%d options:", num_options);
+ for (i = 0; i < num_options; i ++)
+ printf(" %s=%s", options[i].name, options[i].value);
+ puts(")");
+ }
+ else
+ puts("FAIL (No conflicts!)");
+
+ fputs("ppdInstallableConflict(): ", stdout);
+ if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
+ !ppdInstallableConflict(ppd, "Duplex", "None"))
+ puts("PASS");
+ else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
+ {
+ puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
+ status ++;
+ }
+ else
+ {
+ puts("FAIL (Duplex=None conflicted)");
+ status ++;
+ }
}
else
{
}
else
{
- int i, j, k; /* Looping vars */
+ int j, k; /* Looping vars */
ppd_attr_t *attr; /* Current attribute */
ppd_group_t *group; /* Option group */
ppd_option_t *option; /* Option */
ppd_coption_t *coption; /* Custom option */
ppd_cparam_t *cparam; /* Custom parameter */
+ ppd_const_t *c; /* UIConstraints */
char lang[255]; /* LANG environment variable */
}
}
+ puts("Constraints:");
+
+ for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+ printf(" *UIConstraints: *%s %s *%s %s\n", c->option1, c->choice1,
+ c->option2, c->choice2);
+
puts("Attributes:");
for (attr = (ppd_attr_t *)cupsArrayFirst(ppd->sorted_attrs);
</ul></li>
</ul>
<!--
- "$Id: api-httpipp.shtml 7258 2008-01-28 00:15:05Z mike $"
+ "$Id: api-httpipp.shtml 7684 2008-06-23 16:47:38Z mike $"
HTTP and IPP API introduction for the Common UNIX Printing System (CUPS).
</ul></li>
<li><a href="#FUNCTIONS">Functions</a><ul class="code">
<li><a href="#cupsMarkOptions" title="Mark command-line options in a PPD file.">cupsMarkOptions</a></li>
+<li><a href="#cupsResolveConflicts" title="Resolve conflicts in a marked PPD.">cupsResolveConflicts</a></li>
<li><a href="#ppdClose" title="Free all memory used by the PPD file.">ppdClose</a></li>
<li><a href="#ppdCollect" title="Collect all marked options that reside in the specified
section.">ppdCollect</a></li>
<li><a href="#ppdFindOption" title="Return a pointer to the specified option.">ppdFindOption</a></li>
<li><a href="#ppdFirstCustomParam" title="Return the first parameter for a custom option.">ppdFirstCustomParam</a></li>
<li><a href="#ppdFirstOption" title="Return the first option in the PPD file.">ppdFirstOption</a></li>
+<li><a href="#ppdInstallableConflict" title="Test whether an option choice conflicts with
+an installable option.">ppdInstallableConflict</a></li>
<li><a href="#ppdIsMarked" title="Check to see if an option is marked.">ppdIsMarked</a></li>
<li><a href="#ppdLastError" title="Return the status from the last ppdOpen*().">ppdLastError</a></li>
<li><a href="#ppdLocalize" title="Localize the PPD file to the current locale.">ppdLocalize</a></li>
<li><a href="#ppdLocalizeMarkerName" title="Get the localized version of a marker-names
attribute value.">ppdLocalizeMarkerName</a></li>
<li><a href="#ppdMarkDefaults" title="Mark all default options in the PPD file.">ppdMarkDefaults</a></li>
-<li><a href="#ppdMarkOption" title="Mark an option in a PPD file.">ppdMarkOption</a></li>
+<li><a href="#ppdMarkOption" title="Mark an option in a PPD file and return the number of
+conflicts.">ppdMarkOption</a></li>
<li><a href="#ppdNextCustomParam" title="Return the next parameter for a custom option.">ppdNextCustomParam</a></li>
<li><a href="#ppdNextOption" title="Return the next option in the PPD file.">ppdNextOption</a></li>
<li><a href="#ppdOpen" title="Read a PPD file into memory.">ppdOpen</a></li>
<dd class="description">Options</dd>
</dl>
<h4 class="returnvalue">Return Value</h4>
-<p class="description">1 if conflicting</p>
+<p class="description">1 if conflicts exist, 0 otherwise</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">This function maps the IPP "finishings", "media", "mirror",
"multiple-document-handling", "output-bin", "printer-resolution", and
"sides" attributes to their corresponding PPD options and choices.</p>
+<h3 class="function"><span class="info"> CUPS 1.4 </span><a name="cupsResolveConflicts">cupsResolveConflicts</a></h3>
+<p class="description">Resolve conflicts in a marked PPD.</p>
+<p class="code">
+int cupsResolveConflicts (<br>
+ <a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+ const char *option,<br>
+ const char *choice,<br>
+ int *num_options,<br>
+ cups_option_t **options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>option</dt>
+<dd class="description">Newly selected option or <code>NULL</code> for none</dd>
+<dt>choice</dt>
+<dd class="description">Newly selected choice or <code>NULL</code> for none</dd>
+<dt>num_options</dt>
+<dd class="description">Number of additional selected options</dd>
+<dt>options</dt>
+<dd class="description">Additional selected options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function attempts to resolve any conflicts in a marked PPD, returning
+a list of option changes that are required to resolve any conflicts. On
+input, "num_options" and "options" contain any pending option changes that
+have not yet been marked, while "option" and "choice" contain the most recent
+selection which may or may not be in "num_options" or "options".<br>
+<br>
+On successful return, "num_options" and "options" are updated to contain
+"option" and "choice" along with any changes required to resolve conflicts
+specified in the PPD file. If option conflicts cannot be resolved,
+"num_options" and "options" are not changed.
+
+<code>ppdResolveConflicts</code> uses one of two sources of option constraint
+information. The preferred constraint information is defined by
+<code>cupsUIConstraints</code> and <code>cupsUIResolver</code> attributes - in this
+case, the PPD file provides constraint resolution actions. In this case,
+it should not be possible for @ppdResolveConflicts@ to fail, however it
+will do so if a resolver loop is detected.<br>
+<br>
+The backup constraint infomration is defined by the
+<code>UIConstraints</code> and <code>NonUIConstraints</code> attributes. These
+constraints are resolved algorithmically by selecting the default choice
+for the conflicting option. Unfortunately, this method is far more likely
+to fail.
+
+</p>
<h3 class="function"><a name="ppdClose">ppdClose</a></h3>
<p class="description">Free all memory used by the PPD file.</p>
<p class="code">
<h4 class="discussion">Discussion</h4>
<p class="discussion">Options are returned from all groups in ascending alphanumeric order.
+</p>
+<h3 class="function"><span class="info"> CUPS 1.4 </span><a name="ppdInstallableConflict">ppdInstallableConflict</a></h3>
+<p class="description">Test whether an option choice conflicts with
+an installable option.</p>
+<p class="code">
+int ppdInstallableConflict (<br>
+ <a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+ const char *option,<br>
+ const char *choice<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>option</dt>
+<dd class="description">Option</dd>
+<dt>choice</dt>
+<dd class="description">Choice</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if conflicting, 0 if not conflicting</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function tests whether a particular option choice is available based
+on constraints against options in the "InstallableOptions" group.
+
</p>
<h3 class="function"><a name="ppdIsMarked">ppdIsMarked</a></h3>
<p class="description">Check to see if an option is marked.</p>
<dd class="description">PPD file record</dd>
</dl>
<h3 class="function"><a name="ppdMarkOption">ppdMarkOption</a></h3>
-<p class="description">Mark an option in a PPD file.</p>
+<p class="description">Mark an option in a PPD file and return the number of
+conflicts.</p>
<p class="code">
int ppdMarkOption (<br>
<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
<dd class="description">Number of pre-loaded fonts</dd>
<dt>num_groups </dt>
<dd class="description">Number of UI groups</dd>
-<dt>num_profiles </dt>
-<dd class="description">Number of sRGB color profiles</dd>
+<dt>num_profiles <span class="info"> DEPRECATED </span></dt>
+<dd class="description">Number of sRGB color profiles </dd>
<dt>num_sizes </dt>
<dd class="description">Number of page sizes</dd>
<dt>patches </dt>
<dd class="description">PCFileName string </dd>
<dt>product </dt>
<dd class="description">Product name (from PS RIP/interpreter)</dd>
-<dt>profiles </dt>
-<dd class="description">sRGB color profiles</dd>
+<dt>profiles <span class="info"> DEPRECATED </span></dt>
+<dd class="description">sRGB color profiles </dd>
<dt>protocols <span class="info"> CUPS 1.1.19 </span></dt>
<dd class="description">Protocols (BCP, TBCP) string </dd>
<dt>shortnickname </dt>
</pre>
+<h2 class='title'><a name='CONSTRAINTS'>Constraints</a></h2>
+
+<p>Constraints are option choices that are not allowed by the driver or
+device, for example printing 2-sided transparencies. All versions of CUPS
+support constraints defined by the legacy Adobe <tt>UIConstraints</tt> and
+<tt>NonUIConstraints</tt> attributes which support conflicts between any two
+option choices, for example:</p>
+
+<pre class='command'>
+*% Do not allow 2-sided printing on transparency media
+*UIConstraints: "*Duplex *MediaType Transparency"
+*UIConstraints: "*MediaType Transparency *Duplex"
+</pre>
+
+<p>While nearly all constraints can be expressed using these attributes, there
+are valid scenarios requiring constraints between more than two option choices.
+In addition, resolution of constraints is problematic since users and software
+have to guess how a particular constraint is best resolved.</p>
+
+<p>CUPS 1.4 and higher define two new attributes for constraints,
+<tt>cupsUIConstraints</tt> and <tt>cupsUIResolver</tt>. Each
+<tt>cupsUIConstraints</tt> attribute points to a <tt>cupsUIResolver</tt>
+attribute which corrects the conflict condition. The same
+<tt>cupsUIResolver</tt> can be used by multiple <tt>cupsUIConstraints</tt>.</p>
+
+<h3><span class='info'>CUPS 1.4</span><a name='cupsUIConstraints'>cupsUIConstraints</a></h3>
+
+<p class='summary'>*cupsUIConstraints resolver: "*Keyword1 *Keyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 *Keyword2 OptionKeyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."<br>
+*cupsUIConstraints: "*InstallableKeyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."</p>
+
+<p>Lists two or more options which conflict. The "resolver" string is a
+(possibly unique) keyword which specifies which options to change when the
+constraint exists. When no resolver is provided, a "revert to defaults"
+change is assumed - this type of constraint is typically only used for
+installable options.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify that 2-sided printing cannot happen on transparencies</em>
+*cupsUIConstraints transparency: "*Duplex *MediaType Transparency"
+
+<em>*% Specify that photo printing cannot happen on plain paper or transparencies at 1200dpi</em>
+*cupsUIConstraints photo: "*OutputMode Photo *MediaType Plain *Resolution 1200dpi"
+*cupsUIConstraints photo: "*OutputMode Photo *MediaType Transparency *Resolution 1200dpi"
+</pre>
+
+<h3><span class='info'>CUPS 1.4</span><a name='cupsUIResolver'>cupsUIResolver</a></h3>
+
+<p class='summary'>*cupsUIResolution resolver: "*Keyword OptionKeyword ..."</p>
+
+<p>Specifies one or more options to mark/select to resolve a constraint. The
+"resolver" string identifies a particular action to take for one or more
+<a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>. The same action
+can be used for multiple constraints.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify the option to change for the 2-sided transparency constraint</em>
+*cupsUIResolver transparency: "*Duplex None"
+
+<em>*% Specify the options to change for the photo printing constraints</em>
+*cupsUIResolver photo: "*OutputMode Best *Resolution 600dpi"
+</pre>
+
+
<h2 class='title'><a name='I18N'>Globalized PPD Support</a></h2>
<p>CUPS 1.2 and higher adds support for PPD files containing multiple
<li>Added <tt>cupsPJLDisplay</tt> attribute.</li>
+ <li>Added <tt>cupsUIResolver</tt> and <tt>cupsUIConstraints</tt>
+ attributes.</li>
+
</ul>
* Constants...
*/
-#define PPD_SYNC 0x50504434 /* Sync word for ppds.dat (PPD4) */
+#define PPD_SYNC 0x50504435 /* Sync word for ppds.dat (PPD5) */
#define PPD_MAX_LANG 32 /* Maximum languages */
#define PPD_MAX_PROD 8 /* Maximum products */
#define PPD_MAX_VERS 8 /* Maximum versions */
#define PPD_TYPE_RASTER 2 /* CUPS raster PPD */
#define PPD_TYPE_FAX 3 /* Facsimile/MFD PPD */
#define PPD_TYPE_UNKNOWN 4 /* Other/hybrid PPD */
+#define PPD_TYPE_DRV 5 /* Driver info file */
static const char * const ppd_types[] = /* ppd-type values */
{
size_t size; /* Size in bytes */
int model_number; /* cupsModelNumber */
int type; /* ppd-type */
- char name[512], /* PPD name */
+ char filename[512], /* Filename */
+ name[512], /* PPD name */
languages[PPD_MAX_LANG][6],
/* LanguageVersion/cupsLanguages */
products[PPD_MAX_PROD][128],
/* PSVersion strings */
make[128], /* Manufacturer */
make_and_model[128], /* NickName/ModelName */
- device_id[128]; /* IEEE 1284 Device ID */
+ device_id[256]; /* IEEE 1284 Device ID */
} ppd_rec_t;
typedef struct /**** In-memory record ****/
* Globals...
*/
-int NumPPDs, /* Number of PPD files */
- SortedPPDs, /* Number of sorted PPD files */
- AllocPPDs; /* Number of allocated entries */
-ppd_info_t *PPDs; /* PPD file info */
+cups_array_t *PPDsByName = NULL, /* PPD files sorted by filename and name */
+ *PPDsByMakeModel = NULL;/* PPD files sorted by make and model */
int ChangedPPD; /* Did we change the PPD database? */
* Local functions...
*/
-static ppd_info_t *add_ppd(const char *name, const char *language,
- const char *make, const char *make_and_model,
+static ppd_info_t *add_ppd(const char *filename, const char *name,
+ const char *language, const char *make,
+ const char *make_and_model,
const char *device_id, const char *product,
const char *psversion, time_t mtime,
size_t size, int model_number, int type);
*/
static ppd_info_t * /* O - PPD */
-add_ppd(const char *name, /* I - PPD name */
+add_ppd(const char *filename, /* I - PPD filename */
+ const char *name, /* I - PPD name */
const char *language, /* I - LanguageVersion */
const char *make, /* I - Manufacturer */
const char *make_and_model, /* I - NickName/ModelName */
* Add a new PPD file...
*/
- if (NumPPDs >= AllocPPDs)
+ if ((ppd = (ppd_info_t *)calloc(1, sizeof(ppd_info_t))) == NULL)
{
- /*
- * Allocate (more) memory for the PPD files...
- */
-
- AllocPPDs += 128;
-
- if (!PPDs)
- ppd = (ppd_info_t *)malloc(sizeof(ppd_info_t) * AllocPPDs);
- else
- ppd = (ppd_info_t *)realloc(PPDs, sizeof(ppd_info_t) * AllocPPDs);
-
- if (ppd == NULL)
- {
- fprintf(stderr,
- "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
- AllocPPDs);
- return (NULL);
- }
-
- PPDs = ppd;
+ fprintf(stderr,
+ "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
+ cupsArrayCount(PPDsByName));
+ return (NULL);
}
- ppd = PPDs + NumPPDs;
- NumPPDs ++;
-
/*
* Zero-out the PPD data and copy the values over...
*/
- memset(ppd, 0, sizeof(ppd_info_t));
-
ppd->found = 1;
ppd->record.mtime = mtime;
ppd->record.size = size;
ppd->record.model_number = model_number;
ppd->record.type = type;
+ strlcpy(ppd->record.filename, filename, sizeof(ppd->record.filename));
strlcpy(ppd->record.name, name, sizeof(ppd->record.name));
strlcpy(ppd->record.languages[0], language,
sizeof(ppd->record.languages[0]));
" (recommended)")) != NULL)
*recommended = '\0';
+ /*
+ * Add the PPD to the PPD arrays...
+ */
+
+ cupsArrayAdd(PPDsByName, ppd);
+ cupsArrayAdd(PPDsByMakeModel, ppd);
+
/*
* Return the new PPD pointer...
*/
compare_names(const ppd_info_t *p0, /* I - First PPD file */
const ppd_info_t *p1) /* I - Second PPD file */
{
- return (strcasecmp(p0->record.name, p1->record.name));
+ int diff; /* Difference between strings */
+
+
+ if ((diff = strcasecmp(p0->record.filename, p1->record.filename)) != 0)
+ return (diff);
+ else
+ return (strcasecmp(p0->record.name, p1->record.name));
}
int limit, /* I - Limit */
const char *opt) /* I - Option argument */
{
- int i, j; /* Looping vars */
+ int i; /* Looping vars */
int count; /* Number of PPDs to send */
ppd_info_t *ppd; /* Current PPD file */
cups_file_t *fp; /* ppds.dat file */
* See if we a PPD database file...
*/
- NumPPDs = 0;
- AllocPPDs = 0;
- PPDs = (ppd_info_t *)NULL;
- ChangedPPD = 0;
+ PPDsByName = cupsArrayNew((cups_array_func_t)compare_names, NULL);
+ PPDsByMakeModel = cupsArrayNew((cups_array_func_t)compare_ppds, NULL);
+ ChangedPPD = 0;
if ((cups_cachedir = getenv("CUPS_CACHEDIR")) == NULL)
cups_cachedir = CUPS_CACHEDIR;
*/
unsigned ppdsync; /* Sync word */
+ int num_ppds; /* Number of PPDs */
+
if (cupsFileRead(fp, (char *)&ppdsync, sizeof(ppdsync))
== sizeof(ppdsync) &&
ppdsync == PPD_SYNC &&
!stat(filename, &fileinfo) &&
((fileinfo.st_size - sizeof(ppdsync)) % sizeof(ppd_rec_t)) == 0 &&
- (NumPPDs = (fileinfo.st_size - sizeof(ppdsync)) /
- sizeof(ppd_rec_t)) > 0)
+ (num_ppds = (fileinfo.st_size - sizeof(ppdsync)) /
+ sizeof(ppd_rec_t)) > 0)
{
/*
* We have a ppds.dat file, so read it!
*/
- if ((PPDs = (ppd_info_t *)malloc(sizeof(ppd_info_t) * NumPPDs)) == NULL)
- fprintf(stderr,
- "ERROR: [cups-driverd] Unable to allocate memory for %d "
- "PPD files!\n", NumPPDs);
- else
+ for (; num_ppds > 0; num_ppds --)
{
- AllocPPDs = NumPPDs;
-
- for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
+ if ((ppd = (ppd_info_t *)calloc(1, sizeof(ppd_info_t))) == NULL)
{
- cupsFileRead(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
- ppd->found = 0;
+ fputs("ERROR: [cups-driverd] Unable to allocate memory for PPD!\n",
+ stderr);
+ exit(1);
}
- fprintf(stderr, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
- filename, NumPPDs);
+ if (cupsFileRead(fp, (char *)&(ppd->record), sizeof(ppd_rec_t)) > 0)
+ {
+ cupsArrayAdd(PPDsByName, ppd);
+ cupsArrayAdd(PPDsByMakeModel, ppd);
+ }
+ else
+ {
+ free(ppd);
+ break;
+ }
}
+
+ fprintf(stderr, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
+ filename, cupsArrayCount(PPDsByName));
}
cupsFileClose(fp);
* Load all PPDs in the specified directory and below...
*/
- SortedPPDs = NumPPDs;
-
if ((cups_datadir = getenv("CUPS_DATADIR")) == NULL)
cups_datadir = CUPS_DATADIR;
* Cull PPD files that are no longer present...
*/
- for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
+ for (ppd = (ppd_info_t *)cupsArrayFirst(PPDsByName);
+ ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByName))
if (!ppd->found)
{
/*
* Remove this PPD file from the list...
*/
- if (i > 1)
- memmove(ppd, ppd + 1, (i - 1) * sizeof(ppd_info_t));
-
- NumPPDs --;
- ppd --;
+ cupsArrayRemove(PPDsByName, ppd);
+ cupsArrayRemove(PPDsByMakeModel, ppd);
+ free(ppd);
}
- /*
- * Sort the PPDs by name...
- */
-
- if (NumPPDs > 1)
- qsort(PPDs, NumPPDs, sizeof(ppd_info_t),
- (int (*)(const void *, const void *))compare_names);
-
/*
* Write the new ppds.dat file...
*/
cupsFileWrite(fp, (char *)&ppdsync, sizeof(ppdsync));
- for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
+ for (ppd = (ppd_info_t *)cupsArrayFirst(PPDsByName);
+ ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByName))
cupsFileWrite(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
cupsFileClose(fp);
fprintf(stderr, "INFO: [cups-driverd] Wrote \"%s\", %d PPDs...\n",
- filename, NumPPDs);
+ filename, cupsArrayCount(PPDsByName));
}
else
fprintf(stderr, "ERROR: [cups-driverd] Unable to write \"%s\" - %s\n",
* Add the raw driver...
*/
- add_ppd("raw", "en", "Raw", "Raw Queue", "", "", "", 0, 0, 0,
+ add_ppd("", "raw", "en", "Raw", "Raw Queue", "", "", "", 0, 0, 0,
PPD_TYPE_UNKNOWN);
- /*
- * Sort the PPDs by make and model...
- */
-
- if (NumPPDs > 1)
- qsort(PPDs, NumPPDs, sizeof(ppd_info_t),
- (int (*)(const void *, const void *))compare_ppds);
-
/*
* Send IPP attributes...
*/
sent_header = 0;
- if (limit <= 0 || limit > NumPPDs)
- count = NumPPDs;
+ if (limit <= 0 || limit > cupsArrayCount(PPDsByMakeModel))
+ count = cupsArrayCount(PPDsByMakeModel);
else
count = limit;
- for (i = NumPPDs, ppd = PPDs; count > 0 && i > 0; i --, ppd ++)
+ for (ppd = (ppd_info_t *)cupsArrayFirst(PPDsByMakeModel);
+ count > 0 && ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByMakeModel))
{
/*
* Filter PPDs based on make, model, or device ID...
*/
+ if (ppd->record.type < PPD_TYPE_POSTSCRIPT ||
+ ppd->record.type >= PPD_TYPE_DRV)
+ continue;
+
if (device_id && strncasecmp(ppd->record.device_id, device_id,
device_id_len))
continue; /* TODO: implement smart compare */
if (language)
{
- for (j = 0; j < PPD_MAX_LANG; j ++)
- if (!ppd->record.languages[j][0] ||
- !strcasecmp(ppd->record.languages[j], language))
+ for (i = 0; i < PPD_MAX_LANG; i ++)
+ if (!ppd->record.languages[i][0] ||
+ !strcasecmp(ppd->record.languages[i], language))
break;
- if (j >= PPD_MAX_LANG || !ppd->record.languages[j][0])
+ if (i >= PPD_MAX_LANG || !ppd->record.languages[i][0])
continue;
}
if (product)
{
- for (j = 0; j < PPD_MAX_PROD; j ++)
- if (!ppd->record.products[j][0] ||
- !strcasecmp(ppd->record.products[j], product))
+ for (i = 0; i < PPD_MAX_PROD; i ++)
+ if (!ppd->record.products[i][0] ||
+ !strcasecmp(ppd->record.products[i], product))
break;
- if (j >= PPD_MAX_PROD || !ppd->record.products[j][0])
+ if (i >= PPD_MAX_PROD || !ppd->record.products[i][0])
continue;
}
if (psversion)
{
- for (j = 0; j < PPD_MAX_VERS; j ++)
- if (!ppd->record.psversions[j][0] ||
- !strcasecmp(ppd->record.psversions[j], psversion))
+ for (i = 0; i < PPD_MAX_VERS; i ++)
+ if (!ppd->record.psversions[i][0] ||
+ !strcasecmp(ppd->record.psversions[i], psversion))
break;
- if (j >= PPD_MAX_VERS || !ppd->record.psversions[j][0])
+ if (i >= PPD_MAX_VERS || !ppd->record.psversions[i][0])
continue;
}
cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language",
ppd->record.languages[0]);
- for (j = 1; j < PPD_MAX_LANG && ppd->record.languages[j][0]; j ++)
- cupsdSendIPPString(IPP_TAG_LANGUAGE, "", ppd->record.languages[j]);
+ for (i = 1; i < PPD_MAX_LANG && ppd->record.languages[i][0]; i ++)
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "", ppd->record.languages[i]);
}
if (send_make)
cupsdSendIPPString(IPP_TAG_TEXT, "ppd-product",
ppd->record.products[0]);
- for (j = 1; j < PPD_MAX_PROD && ppd->record.products[j][0]; j ++)
- cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.products[j]);
+ for (i = 1; i < PPD_MAX_PROD && ppd->record.products[i][0]; i ++)
+ cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.products[i]);
}
if (send_psversion)
cupsdSendIPPString(IPP_TAG_TEXT, "ppd-psversion",
ppd->record.psversions[0]);
- for (j = 1; j < PPD_MAX_VERS && ppd->record.psversions[j][0]; j ++)
- cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.psversions[j]);
+ for (i = 1; i < PPD_MAX_VERS && ppd->record.psversions[i][0]; i ++)
+ cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.psversions[i]);
}
if (send_type)
const char *this_make; /* This ppd-make */
- for (this_make = ppd->record.make, i --, ppd ++; i > 0; i --, ppd ++)
+ for (this_make = ppd->record.make,
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByMakeModel);
+ ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByMakeModel))
if (strcasecmp(this_make, ppd->record.make))
break;
- i ++;
- ppd --;
+ cupsArrayPrev(PPDsByMakeModel);
}
}
* See if this file has been scanned before...
*/
- if (SortedPPDs > 0)
- {
- strcpy(key.record.name, name);
+ strcpy(key.record.filename, name);
+ strcpy(key.record.name, name);
- ppd = (ppd_info_t *)bsearch(&key, PPDs, SortedPPDs, sizeof(ppd_info_t),
- (cupsd_compare_func_t)compare_names);
+ ppd = (ppd_info_t *)cupsArrayFind(PPDsByName, &key);
- if (ppd &&
- ppd->record.size == dent->fileinfo.st_size &&
- ppd->record.mtime == dent->fileinfo.st_mtime)
+ if (ppd &&
+ ppd->record.size == dent->fileinfo.st_size &&
+ ppd->record.mtime == dent->fileinfo.st_mtime)
+ {
+ do
{
ppd->found = 1;
- continue;
}
+ while ((ppd = (ppd_info_t *)cupsArrayNext(PPDsByName)) != NULL &&
+ !strcasecmp(ppd->record.filename, name));
+
+ continue;
}
- else
- ppd = NULL;
/*
* No, file is new/changed, so re-scan it...
fprintf(stderr, "DEBUG: [cups-driverd] Adding ppd \"%s\"...\n", name);
- ppd = add_ppd(name, lang_version, manufacturer, make_model, device_id,
- (char *)cupsArrayFirst(products),
+ ppd = add_ppd(name, name, lang_version, manufacturer, make_model,
+ device_id, (char *)cupsArrayFirst(products),
(char *)cupsArrayFirst(psversions),
dent->fileinfo.st_mtime, dent->fileinfo.st_size,
model_number, type);
int type; // Driver type
+ /*
+ * Load the driver info file...
+ */
+
src = new ppdcSource(filename, fp);
if (src->drivers->count == 0)
return (0);
}
+ /*
+ * Add a dummy entry for the file...
+ */
+
+ add_ppd(filename, filename, "", "", "", "", "", "", mtime, size, 0,
+ PPD_TYPE_DRV);
+
+ /*
+ * Then the drivers in the file...
+ */
+
for (d = (ppdcDriver *)src->drivers->first();
d;
d = (ppdcDriver *)src->drivers->next())
{
product_found = true;
- add_ppd(uri, "en", d->manufacturer->value, make_model,
+ add_ppd(filename, uri, "en", d->manufacturer->value, make_model,
device_id ? device_id->value->value : "",
product->value->value,
ps_version ? ps_version->value->value : "(3010) 0",
}
if (!product_found)
- add_ppd(uri, "en", d->manufacturer->value, make_model,
+ add_ppd(filename, uri, "en", d->manufacturer->value, make_model,
device_id ? device_id->value->value : "",
d->model_name->value,
ps_version ? ps_version->value->value : "(3010) 0",
type = PPD_TYPE_UNKNOWN;
}
- ppd = add_ppd(name, languages, make, make_and_model, device_id,
+ ppd = add_ppd("", name, languages, make, make_and_model, device_id,
product, psversion, 0, 0, 0, type);
if (!ppd)
echo Linking $@...
$(CC) $(LDFLAGS) -o $@ cupstestppd.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS)
+cupstestppd-static: cupstestppd.o ../cups/libcups.a ../filter/libcupsimage.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ cupstestppd.o ../filter/libcupsimage.a \
+ ../cups/libcups.a $(IMGLIBS) $(LIBGSSAPI) $(LIBS) $(LIBZ)
+
#
# lp
int verbose, /* I - Verbosity level */
int warn) /* I - Warnings only? */
{
- int j; /* Looping var */
- ppd_const_t *c; /* Current constraint */
- ppd_option_t *option; /* Standard UI option */
- ppd_option_t *option2; /* Standard UI option */
- const char *prefix; /* WARN/FAIL prefix */
+ int i; /* Looping var */
+ const char *prefix; /* WARN/FAIL prefix */
+ ppd_const_t *c; /* Current UIConstraints data */
+ ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */
+ const char *vptr; /* Pointer into constraint value */
+ char option[PPD_MAX_NAME],
+ /* Option name/MainKeyword */
+ choice[PPD_MAX_NAME],
+ /* Choice/OptionKeyword */
+ *ptr; /* Pointer into option or choice */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ ppd_option_t *o; /* PPD option */
prefix = warn ? " WARN " : "**FAIL**";
- for (j = ppd->num_consts, c = ppd->consts; j > 0; j --, c ++)
+
+ /*
+ * See what kind of constraint data we have in the PPD...
+ */
+
+ if ((constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL)) != NULL)
{
- option = ppdFindOption(ppd, c->option1);
- option2 = ppdFindOption(ppd, c->option2);
+ /*
+ * Check new-style cupsUIConstraints data...
+ */
- if (!option || !option2)
+ for (; constattr;
+ constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
{
- if (!warn && !errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
+ if (!constattr->value)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Empty cupsUIConstraints %s!\n"),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ for (i = 0, vptr = strchr(constattr->value, '*');
+ vptr;
+ i ++, vptr = strchr(vptr + 1, '*'));
+
+ if (i == 0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Bad cupsUIConstraints %s: \"%s\"!\n"),
+ prefix, constattr->spec, constattr->value);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ cupsArraySave(ppd->sorted_attrs);
+
+ if (constattr->spec[0] &&
+ !ppdFindAttr(ppd, "cupsUIResolver", constattr->spec))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing cupsUIResolver %s!\n"),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+ }
+
+ cupsArrayRestore(ppd->sorted_attrs);
+
+ num_options = 0;
+ options = NULL;
+
+ for (vptr = strchr(constattr->value, '*');
+ vptr;
+ vptr = strchr(vptr + 1, '*'))
+ {
+ /*
+ * Extract "*Option Choice" or just "*Option"...
+ */
+
+ for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++)
+ if (ptr < (option + sizeof(option) - 1))
+ *ptr++ = *vptr;
+
+ *ptr = '\0';
+
+ while (isspace(*vptr & 255))
+ vptr ++;
+
+ if (*vptr == '*')
+ {
+ vptr --;
+ choice[0] = '\0';
+ }
+ else
+ {
+ for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
+ if (ptr < (choice + sizeof(choice) - 1))
+ *ptr++ = *vptr;
+
+ *ptr = '\0';
+ }
+
+ if (!strncasecmp(option, "Custom", 6) && !strcasecmp(choice, "True"))
+ {
+ _cups_strcpy(option, option + 6);
+ strcpy(choice, "Custom");
+ }
+
+ if ((o = ppdFindOption(ppd, option)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing option %s in "
+ "cupsUIConstraints %s: \"%s\"!\n"),
+ prefix, option, constattr->spec, constattr->value);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ if (choice[0] && !ppdFindChoice(o, choice))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing choice *%s %s in "
+ "cupsUIConstraints %s: \"%s\"!\n"),
+ prefix, option, choice, constattr->spec,
+ constattr->value);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ if (choice[0])
+ num_options = cupsAddOption(option, choice, num_options, &options);
+ else
+ {
+ for (i = 0; i < o->num_choices; i ++)
+ if (strcasecmp(o->choices[i].choice, "None") &&
+ strcasecmp(o->choices[i].choice, "Off") &&
+ strcasecmp(o->choices[i].choice, "False"))
+ {
+ num_options = cupsAddOption(option, o->choices[i].choice,
+ num_options, &options);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Test the resolver...
+ */
+
+ if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s cupsUIResolver %s causes a loop!\n"),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+ }
+
+ cupsFreeOptions(num_options, options);
+ }
+ }
+ else
+ {
+ /*
+ * Check old-style [Non]UIConstraints data...
+ */
+
+ for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+ {
+ if (!strncasecmp(c->option1, "Custom", 6) &&
+ !strcasecmp(c->choice1, "True"))
+ {
+ strcpy(option, c->option1 + 6);
+ strcpy(choice, "Custom");
+ }
+ else
+ {
+ strcpy(option, c->option1);
+ strcpy(choice, c->choice1);
+ }
+
+ if ((o = ppdFindOption(ppd, option)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
- if (!option)
_cupsLangPrintf(stdout,
_(" %s Missing option %s in "
- "UIConstraint \"*%s %s *%s %s\"!\n"),
+ "UIConstraints \"*%s %s *%s %s\"!\n"),
prefix, c->option1,
c->option1, c->choice1, c->option2, c->choice2);
-
- if (!option2)
+
+ if (!warn)
+ errors ++;
+ }
+ else if (choice[0] && !ppdFindChoice(o, choice))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
_cupsLangPrintf(stdout,
- _(" %s Missing option %s in "
- "UIConstraint \"*%s %s *%s %s\"!\n"),
- prefix, c->option2,
+ _(" %s Missing choice *%s %s in "
+ "UIConstraints \"*%s %s *%s %s\"!\n"),
+ prefix, c->option1, c->choice1,
c->option1, c->choice1, c->option2, c->choice2);
- if (!warn)
- errors ++;
-
- continue;
- }
+ if (!warn)
+ errors ++;
+ }
- if (c->choice1[0] && !ppdFindChoice(option, c->choice1))
- {
- if (!warn && !errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
+ if (!strncasecmp(c->option2, "Custom", 6) &&
+ !strcasecmp(c->choice2, "True"))
+ {
+ strcpy(option, c->option2 + 6);
+ strcpy(choice, "Custom");
+ }
+ else
+ {
+ strcpy(option, c->option2);
+ strcpy(choice, c->choice2);
+ }
- _cupsLangPrintf(stdout,
- _(" %s Missing choice *%s %s in "
- "UIConstraint \"*%s %s *%s %s\"!\n"),
- prefix, c->option1, c->choice1,
- c->option1, c->choice1, c->option2, c->choice2);
+ if ((o = ppdFindOption(ppd, option)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
- if (!warn)
- errors ++;
- }
+ _cupsLangPrintf(stdout,
+ _(" %s Missing option %s in "
+ "UIConstraints \"*%s %s *%s %s\"!\n"),
+ prefix, c->option2,
+ c->option1, c->choice1, c->option2, c->choice2);
- if (c->choice2[0] && !ppdFindChoice(option2, c->choice2))
- {
- if (!warn && !errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
+ if (!warn)
+ errors ++;
+ }
+ else if (choice[0] && !ppdFindChoice(o, choice))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
- _cupsLangPrintf(stdout,
- _(" %s Missing choice *%s %s in "
- "UIConstraint \"*%s %s *%s %s\"!\n"),
- prefix, c->option2, c->choice2,
- c->option1, c->choice1, c->option2, c->choice2);
+ _cupsLangPrintf(stdout,
+ _(" %s Missing choice *%s %s in "
+ "UIConstraints \"*%s %s *%s %s\"!\n"),
+ prefix, c->option2, c->choice2,
+ c->option1, c->choice1, c->option2, c->choice2);
- if (!warn)
- errors ++;
+ if (!warn)
+ errors ++;
+ }
}
}