]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge CUPS 1.4svn-r7762.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Fri, 18 Jul 2008 18:47:53 +0000 (18:47 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Fri, 18 Jul 2008 18:47:53 +0000 (18:47 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@868 a1ca3aef-8c08-0410-bb20-df032aa958be

19 files changed:
CHANGES.txt
cups/Dependencies
cups/Makefile
cups/cups.h
cups/libcups.exp
cups/libcups_s.exp
cups/mark.c
cups/ppd-private.h
cups/ppd.c
cups/ppd.h
cups/test.ppd
cups/testhttp.c
cups/testppd.c
doc/help/api-httpipp.html
doc/help/api-ppd.html
doc/help/spec-ppd.html
scheduler/cups-driverd.cxx
systemv/Makefile
systemv/cupstestppd.c

index e2478d39d481d72d727bb4d32de065aa71269563..083ceae010f91e774f3b3cab639b256454f0a3db 100644 (file)
@@ -1,8 +1,13 @@
-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
index deb6a77eabdfca6d60cb55ad1c5d11d4fd499555..537343a45afc672141df4800cc6550ef96339112 100644 (file)
@@ -14,6 +14,8 @@ backchannel.o: language.h
 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
@@ -85,7 +87,7 @@ ppd.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
@@ -109,7 +111,8 @@ testarray.o: ../cups/string.h ../config.h string.h array.h versioning.h dir.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
@@ -118,8 +121,8 @@ testoptions.o: string.h ../config.h cups.h ipp.h http.h versioning.h ppd.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
 
@@ -137,6 +140,8 @@ backchannel.32.o: backchannel.c  language.h
 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
@@ -208,7 +213,7 @@ ppd.32.o: ppd.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
@@ -232,7 +237,8 @@ testarray.32.o: testarray.c  ../cups/string.h ../config.h string.h array.h versi
 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
@@ -241,8 +247,8 @@ testoptions.32.o: testoptions.c  string.h ../config.h cups.h ipp.h http.h versio
 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
 
@@ -260,6 +266,8 @@ backchannel.64.o: backchannel.c  language.h
 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
@@ -331,7 +339,7 @@ ppd.64.o: ppd.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
@@ -355,7 +363,8 @@ testarray.64.o: testarray.c  ../cups/string.h ../config.h string.h array.h versi
 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
@@ -364,6 +373,6 @@ testoptions.64.o: testoptions.c  string.h ../config.h cups.h ipp.h http.h versio
 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
index 6d4a684813d42f14ec1a08122756308900b7d3a0..735c89dd97c2a4d542894917f620e54befae388b 100644 (file)
@@ -28,6 +28,7 @@ LIBOBJS       =       \
                auth.o \
                backchannel.o \
                backend.o \
+               conflicts.o \
                custom.o \
                debug.o \
                dest.o \
@@ -532,7 +533,7 @@ apihelp:
        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 \
@@ -575,8 +576,8 @@ framedhelp:
                --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 \
index e80b1665a441148c9dd15076315233db95c2c3b4..1038c8313d613e8e2360616f5c9b0db3f8029744 100644 (file)
@@ -291,6 +291,10 @@ extern ipp_t               *cupsGetResponse(http_t *http,
                                         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;
index 4100b6e48f52fa940f64233313bf399ba9b3efdb..53c15631aa476abddb24700832fe77a480d615ea 100644 (file)
@@ -55,6 +55,7 @@ __ppdGetLanguages
 __ppdHashName
 __ppdLocalizedAttr
 __ppdNormalizeMakeAndModel
+__ppdParseOptions
 _cupsAddDest
 _cupsAddOption
 _cupsAdminCreateWindowsPPD
@@ -170,6 +171,7 @@ _cupsPutFile
 _cupsReadResponseData
 _cupsRemoveDest
 _cupsRemoveOption
+_cupsResolveConflicts
 _cupsSendRequest
 _cupsServer
 _cupsSetDefaultDest
@@ -317,6 +319,7 @@ _ppdFindNextAttr
 _ppdFindOption
 _ppdFirstCustomParam
 _ppdFirstOption
+_ppdInstallableConflict
 _ppdIsMarked
 _ppdLastError
 _ppdLocalize
index c952a35ff9e47206c1974a4811add21cedf15f6b..bb480e85d61f305e3c58fcc4462922657f9335b7 100644 (file)
@@ -53,3 +53,4 @@ _ppdGetLanguages
 _ppdHashName
 _ppdLocalizedAttr
 _ppdNormalizeMakeAndModel
+_ppdParseOptions
\ No newline at end of file
index 91de0951c80d1966fa19c4999f6c9f19fea8300c..b0de90076f2545be6330d8e92fca17a4f7b9c8e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$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);
 
 
 /*
@@ -64,14 +68,13 @@ static int  ppd_mark_choices(ppd_file_t *ppd, const char *options);
  * "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 */
@@ -119,8 +122,6 @@ cupsMarkOptions(
   * Mark options...
   */
 
-  conflict  = 0;
-
   for (i = num_options, optptr = options; i > 0; i --, optptr ++)
     if (!strcasecmp(optptr->name, "media"))
     {
@@ -154,35 +155,31 @@ cupsMarkOptions(
        */
 
         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])))
@@ -200,18 +197,20 @@ cupsMarkOptions(
         * 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;
             }
         }
@@ -222,18 +221,20 @@ cupsMarkOptions(
         * 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;
             }
         }
@@ -244,18 +245,20 @@ cupsMarkOptions(
         * 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;
             }
         }
@@ -264,21 +267,18 @@ cupsMarkOptions(
     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"))
     {
@@ -286,15 +286,9 @@ cupsMarkOptions(
           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"))
@@ -335,163 +329,32 @@ cupsMarkOptions(
         * 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);
 }
 
 
@@ -650,7 +513,8 @@ ppdMarkDefaults(ppd_file_t *ppd)    /* I - PPD file record */
 
 
 /*
- * '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 */
@@ -658,14 +522,6 @@ ppdMarkOption(ppd_file_t *ppd,             /* I - PPD file record */
               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));
 
@@ -676,6 +532,229 @@ ppdMarkOption(ppd_file_t *ppd,            /* I - PPD file record */
   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...
@@ -699,7 +778,7 @@ ppdMarkOption(ppd_file_t *ppd,              /* I - PPD file record */
   */
 
   if ((o = ppdFindOption(ppd, option)) == NULL)
-    return (0);
+    return;
 
   loc = localeconv();
 
@@ -710,7 +789,7 @@ ppdMarkOption(ppd_file_t *ppd,              /* I - PPD file record */
     */
 
     if ((c = ppdFindChoice(o, "Custom")) == NULL)
-      return (0);
+      return;
 
     if (!strcasecmp(option, "PageSize"))
     {
@@ -734,7 +813,7 @@ ppdMarkOption(ppd_file_t *ppd,              /* I - PPD file record */
       if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
       {
         if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
-         return (0);
+         return;
 
         switch (cparam->type)
        {
@@ -802,7 +881,7 @@ ppdMarkOption(ppd_file_t *ppd,              /* I - PPD file record */
 
 
     if ((c = ppdFindChoice(o, "Custom")) == NULL)
-      return (0);
+      return;
 
     if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
     {
@@ -867,7 +946,7 @@ ppdMarkOption(ppd_file_t *ppd,              /* I - PPD file record */
         break;
 
     if (!i)
-      return (0);
+      return;
   }
 
  /*
@@ -964,177 +1043,9 @@ ppdMarkOption(ppd_file_t *ppd,           /* I - PPD file record */
   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 $".
  */
index a7db6507537bfd5cbd6982695334ebf0785fbd55..fa33e96c6ad1b27f60a93df1c91ff082e16a45f6 100644 (file)
@@ -43,6 +43,30 @@ extern "C" {
 #  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);
@@ -54,6 +78,8 @@ extern ppd_attr_t     *_ppdLocalizedAttr(ppd_file_t *ppd, const char *keyword,
 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);
 
 
 /*
index c10cbc491c385d85630715e71aead54e1cc4819f..436dd05f293c023105cdf4d25f6147d79e838ae4 100644 (file)
@@ -40,7 +40,6 @@
  *   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.
@@ -109,7 +108,6 @@ static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
 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);
@@ -1747,52 +1745,6 @@ ppdOpen2(cups_file_t *fp)                /* I - File to read from */
            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...
       */
@@ -1958,14 +1910,6 @@ ppdOpen2(cups_file_t *fp)                /* I - File to read from */
     }
   }
 
- /*
-  * 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...
   */
@@ -2280,28 +2224,6 @@ ppd_compare_choices(ppd_choice_t *a,     /* I - First choice */
 }
 
 
-/*
- * '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.
  */
index 8396e61e4fc20b0218bec731951028df429be336..4261aae1ae6bf893e099e5eb832cd44d26d25ae3 100644 (file)
@@ -306,8 +306,8 @@ typedef struct ppd_file_s           /**** PPD File ****/
   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... */
 
@@ -328,6 +328,9 @@ typedef struct ppd_file_s           /**** PPD File ****/
 
   /**** 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;
 
 
@@ -399,6 +402,9 @@ extern const char   *ppdLocalizeIPPReason(ppd_file_t *ppd,
                                              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,
index 14d631283ab63578ec8d4dd19590f85d1ea4b98d..80927065a81c38d15c624a34d75400542f7827cc 100644 (file)
@@ -8,11 +8,11 @@
 *% 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
 
index 302d4fde5da6daa541c6ab8f02a70f05ec322d61..7d676ae5d049e497ecd43009c8ac6d0e30f2d493 100644 (file)
@@ -464,7 +464,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
     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);
index 3c8a8dc6bb576cc5e9d8db49d276c30b52200cea..10f11650f4095d2f9fd4150e851d0c938389236f 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   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"
@@ -62,6 +66,10 @@ static const char    *default_code =
                        "} 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"
@@ -95,12 +103,15 @@ int                                        /* O - Exit status */
 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;
@@ -126,7 +137,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
     * Do tests with test.ppd...
     */
 
-    fputs("ppdOpenFile: ", stdout);
+    fputs("ppdOpenFile(test.ppd): ", stdout);
 
     if ((ppd = ppdOpenFile("test.ppd")) != NULL)
       puts("PASS");
@@ -189,6 +200,60 @@ main(int  argc,                            /* I - Number of command-line arguments */
     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...
     */
@@ -310,6 +375,108 @@ main(int  argc,                           /* I - Number of command-line arguments */
       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
   {
@@ -334,12 +501,13 @@ main(int  argc,                           /* I - Number of command-line arguments */
     }
     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 */
 
 
@@ -436,6 +604,12 @@ main(int  argc,                            /* I - Number of command-line arguments */
        }
       }
 
+      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);
index e55c460b46b59fc304813b4a8b21ad30a48a8547..ab5fcc7e3f259968f163cc79d1736d4bcb26d498 100644 (file)
@@ -498,7 +498,7 @@ with a hostname. ">http_addrlist_s</a></li>
 </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).
 
index b8ea921548513e654e50e35721aa8192b6e7bcbd..125c7b29b3448c85227bdc94c539c237e7a99386 100644 (file)
@@ -300,6 +300,7 @@ div.contents ul.subcontents li {
 </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>
@@ -323,6 +324,8 @@ marked option choices.">ppdConflicts</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>
@@ -332,7 +335,8 @@ attribute.">ppdLocalizeIPPReason</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>
@@ -627,11 +631,62 @@ int cupsMarkOptions (<br>
 <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 &quot;finishings&quot;, &quot;media&quot;, &quot;mirror&quot;,
 &quot;multiple-document-handling&quot;, &quot;output-bin&quot;, &quot;printer-resolution&quot;, and
 &quot;sides&quot; attributes to their corresponding PPD options and choices.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsResolveConflicts">cupsResolveConflicts</a></h3>
+<p class="description">Resolve conflicts in a marked PPD.</p>
+<p class="code">
+int cupsResolveConflicts (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *option,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *choice,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;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, &quot;num_options&quot; and &quot;options&quot; contain any pending option changes that
+have not yet been marked, while &quot;option&quot; and &quot;choice&quot; contain the most recent
+selection which may or may not be in &quot;num_options&quot; or &quot;options&quot;.<br>
+<br>
+On successful return, &quot;num_options&quot; and &quot;options&quot; are updated to contain
+&quot;option&quot; and &quot;choice&quot; along with any changes required to resolve conflicts
+specified in the PPD file.  If option conflicts cannot be resolved,
+&quot;num_options&quot; and &quot;options&quot; 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">
@@ -1010,6 +1065,31 @@ const char *ppdErrorString (<br>
 <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">&nbsp;CUPS 1.4&nbsp;</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>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *option,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;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 &quot;InstallableOptions&quot; group.
+
 </p>
 <h3 class="function"><a name="ppdIsMarked">ppdIsMarked</a></h3>
 <p class="description">Check to see if an option is marked.</p>
@@ -1155,7 +1235,8 @@ void ppdMarkDefaults (<br>
 <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>
 &nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
@@ -1639,8 +1720,8 @@ typedef enum <a href="#ppd_ui_e">ppd_ui_e</a> ppd_ui_t;
 <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">&nbsp;DEPRECATED&nbsp;</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>
@@ -1649,8 +1730,8 @@ typedef enum <a href="#ppd_ui_e">ppd_ui_e</a> ppd_ui_t;
 <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">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">sRGB color profiles </dd>
 <dt>protocols <span class="info">&nbsp;CUPS 1.1.19&nbsp;</span></dt>
 <dd class="description">Protocols (BCP, TBCP) string </dd>
 <dt>shortnickname </dt>
index 87209f39a887134367d8d2d3e83d4044c7830376..5a9865090c0fdfa52a80ba3802ec86a77efc3bb3 100644 (file)
@@ -358,6 +358,76 @@ attribute can be used to override the default 3-component (RGB) colorspace.</p>
 </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
@@ -1649,6 +1719,9 @@ the device.</p>
 
        <li>Added <tt>cupsPJLDisplay</tt> attribute.</li>
 
+       <li>Added <tt>cupsUIResolver</tt> and <tt>cupsUIConstraints</tt>
+       attributes.</li>
+
 </ul>
 
 
index 962cb9362dc69f1f2abb6768638280016f15783d..bed393eae5f3a248cbee88899cac7dc2e5c581dd 100644 (file)
@@ -47,7 +47,7 @@
  * 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 */
@@ -57,6 +57,7 @@
 #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 */
 {
@@ -78,7 +79,8 @@ typedef struct                                /**** PPD record ****/
   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],
@@ -87,7 +89,7 @@ typedef struct                                /**** PPD record ****/
                                        /* 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 ****/
@@ -101,10 +103,8 @@ 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? */
 
 
@@ -112,8 +112,9 @@ 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);
@@ -169,7 +170,8 @@ main(int  argc,                             /* I - Number of command-line args */
  */
 
 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 */
@@ -189,45 +191,25 @@ add_ppd(const char *name,         /* I - PPD name */
   * 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]));
@@ -248,6 +230,13 @@ add_ppd(const char *name,          /* I - PPD name */
                             " (recommended)")) != NULL)
     *recommended = '\0';
 
+ /*
+  * Add the PPD to the PPD arrays...
+  */
+
+  cupsArrayAdd(PPDsByName, ppd);
+  cupsArrayAdd(PPDsByMakeModel, ppd);
+
  /*
   * Return the new PPD pointer...
   */
@@ -654,7 +643,13 @@ static int                         /* O - Result of comparison */
 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));
 }
 
 
@@ -712,7 +707,7 @@ list_ppds(int        request_id,    /* I - Request ID */
           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 */
@@ -756,10 +751,9 @@ list_ppds(int        request_id,   /* I - Request ID */
   * 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;
@@ -772,36 +766,44 @@ list_ppds(int        request_id,  /* I - Request ID */
     */
 
     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);
@@ -811,8 +813,6 @@ list_ppds(int        request_id,    /* I - Request ID */
   * Load all PPDs in the specified directory and below...
   */
 
-  SortedPPDs = NumPPDs;
-
   if ((cups_datadir = getenv("CUPS_DATADIR")) == NULL)
     cups_datadir = CUPS_DATADIR;
 
@@ -853,28 +853,20 @@ list_ppds(int        request_id,  /* I - Request ID */
   * 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...
   */
@@ -888,13 +880,15 @@ list_ppds(int        request_id,  /* I - Request ID */
 
       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",
@@ -913,17 +907,9 @@ list_ppds(int        request_id,   /* I - Request ID */
   * 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...
   */
@@ -1030,29 +1016,35 @@ list_ppds(int        request_id,        /* I - Request ID */
 
   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;
     }
 
@@ -1068,23 +1060,23 @@ list_ppds(int        request_id,        /* I - Request ID */
 
     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;
     }
 
@@ -1120,8 +1112,8 @@ list_ppds(int        request_id,  /* I - Request ID */
       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)
@@ -1140,8 +1132,8 @@ list_ppds(int        request_id,  /* I - Request ID */
       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)
@@ -1149,8 +1141,8 @@ list_ppds(int        request_id,  /* I - Request ID */
       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)
@@ -1171,12 +1163,14 @@ list_ppds(int        request_id,        /* I - Request ID */
       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);
     }
   }
 
@@ -1314,23 +1308,24 @@ load_ppds(const char *d,                /* I - Actual directory */
     * 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...
@@ -1610,8 +1605,8 @@ load_ppds(const char *d,          /* I - Actual directory */
 
       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);
@@ -1715,6 +1710,10 @@ load_drv(const char  *filename,          /* I - Actual filename */
   int          type;                   // Driver type
 
 
+ /*
+  * Load the driver info file...
+  */
+
   src = new ppdcSource(filename, fp);
 
   if (src->drivers->count == 0)
@@ -1726,6 +1725,17 @@ load_drv(const char  *filename,          /* I - Actual filename */
     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())
@@ -1777,7 +1787,7 @@ load_drv(const char  *filename,           /* I - Actual filename */
       {
         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",
@@ -1785,7 +1795,7 @@ load_drv(const char  *filename,           /* I - Actual filename */
       }
 
     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",
@@ -1926,7 +1936,7 @@ load_drivers(void)
            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)
index 1c8a8e3a7c524f181f4a8dd8bcec1e9d20433734..5b906e6c9ee9ffe47de0d15033e0a7baae152960 100644 (file)
@@ -195,6 +195,11 @@ cupstestppd:       cupstestppd.o ../cups/$(LIBCUPS) ../filter/$(LIBCUPSIMAGE)
        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
index b2317564956ccae7c3a377628b322152731fd6d1..f376dd46ef0223cd87aae025d76a9eca4a42f9f9 100644 (file)
@@ -1679,73 +1679,287 @@ check_constraints(ppd_file_t *ppd,     /* I - PPD file */
                   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 ++;
+      }
     }
   }