]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - ppdc/ppdc-source.cxx
Merge changes from CUPS 1.5svn-r8950.
[thirdparty/cups.git] / ppdc / ppdc-source.cxx
index b4e31fc52a11e837f23465a3ba29977991b56517..3b211534715960bd79003540e36a2564753d632f 100644 (file)
@@ -3,7 +3,7 @@
 //
 //   Source class for the CUPS PPD Compiler.
 //
-//   Copyright 2007-2009 by Apple Inc.
+//   Copyright 2007-2010 by Apple Inc.
 //   Copyright 2002-2007 by Easy Software Products.
 //
 //   These coded instructions, statements, and computer programs are the
@@ -19,6 +19,8 @@
 //   ppdcSource::add_include()        - Add an include directory.
 //   ppdcSource::find_driver()        - Find a driver.
 //   ppdcSource::find_include()       - Find an include file.
+//   ppdcSource::find_po()            - Find a message catalog for the given
+//                                      locale...
 //   ppdcSource::find_size()          - Find a media size.
 //   ppdcSource::find_variable()      - Find a variable.
 //   ppdcSource::get_attr()           - Get an attribute.
 //   ppdcSource::get_color_profile()  - Get a color profile definition.
 //   ppdcSource::get_color_space()    - Get an old-style colorspace value.
 //   ppdcSource::get_constraint()     - Get a constraint.
-//   ppdcSource::get_custom_size()    - Get a custom media size definition
-//                                      from a file.
+//   ppdcSource::get_custom_size()    - Get a custom media size definition from
+//                                      a file.
+//   ppdcSource::get_duplex()         - Get a duplex option.
 //   ppdcSource::get_filter()         - Get a filter.
 //   ppdcSource::get_float()          - Get a single floating-point number.
 //   ppdcSource::get_font()           - Get a font definition.
 //   ppdcSource::get_generic()        - Get a generic old-style option.
 //   ppdcSource::get_group()          - Get an option group.
 //   ppdcSource::get_installable()    - Get an installable option.
-//   ppdcSource::get_integer()        - Get an integer value from a string.
 //   ppdcSource::get_integer()        - Get an integer value from a file.
 //   ppdcSource::get_measurement()    - Get a measurement value.
 //   ppdcSource::get_option()         - Get an option definition.
+//   ppdcSource::get_po()             - Get a message catalog.
 //   ppdcSource::get_resolution()     - Get an old-style resolution option.
 //   ppdcSource::get_simple_profile() - Get a simple color profile definition.
 //   ppdcSource::get_size()           - Get a media size definition from a file.
@@ -57,7 +60,7 @@
 // Include necessary headers...
 //
 
-#include "ppdc.h"
+#include "ppdc-private.h"
 #include <cups/globals.h>
 #include <limits.h>
 #include <math.h>
@@ -68,6 +71,9 @@
 #include "data/hp.h"
 #include "data/label.h"
 #include "data/pcl.h"
+#ifndef WIN32
+#  include <sys/utsname.h>
+#endif // !WIN32
 
 
 //
@@ -93,7 +99,10 @@ const char   *ppdcSource::driver_types[] =
 
 ppdcSource::ppdcSource(const char  *f, // I - File to read
                        cups_file_t *ffp)// I - File pointer to use
+  : ppdcShared()
 {
+  PPDC_NEW;
+
   filename      = new ppdcString(f);
   base_fonts    = new ppdcArray();
   drivers       = new ppdcArray();
@@ -104,6 +113,33 @@ ppdcSource::ppdcSource(const char  *f,     // I - File to read
   cond_current  = cond_stack;
   cond_stack[0] = PPDC_COND_NORMAL;
 
+  // Add standard #define variables...
+#define MAKE_STRING(x) #x
+
+  vars->add(new ppdcVariable("CUPS_VERSION", MAKE_STRING(CUPS_VERSION)));
+  vars->add(new ppdcVariable("CUPS_VERSION_MAJOR", MAKE_STRING(CUPS_VERSION_MAJOR)));
+  vars->add(new ppdcVariable("CUPS_VERSION_MINOR", MAKE_STRING(CUPS_VERSION_MINOR)));
+  vars->add(new ppdcVariable("CUPS_VERSION_PATCH", MAKE_STRING(CUPS_VERSION_PATCH)));
+
+#ifdef WIN32
+  vars->add(new ppdcVariable("PLATFORM_NAME", "Windows"));
+  vars->add(new ppdcVariable("PLATFORM_ARCH", "X86"));
+
+#else
+  struct utsname name;                 // uname information
+
+  if (!uname(&name))
+  {
+    vars->add(new ppdcVariable("PLATFORM_NAME", name.sysname));
+    vars->add(new ppdcVariable("PLATFORM_ARCH", name.machine));
+  }
+  else
+  {
+    vars->add(new ppdcVariable("PLATFORM_NAME", "unknown"));
+    vars->add(new ppdcVariable("PLATFORM_ARCH", "unknown"));
+  }
+#endif // WIN32
+
   if (f)
     read_file(f, ffp);
 }
@@ -115,6 +151,8 @@ ppdcSource::ppdcSource(const char  *f,      // I - File to read
 
 ppdcSource::~ppdcSource()
 {
+  PPDC_DELETE;
+
   filename->release();
   base_fonts->release();
   drivers->release();
@@ -189,7 +227,7 @@ ppdcSource::find_include(
     if (*ptr != '>')
     {
       _cupsLangPrintf(stderr,
-                      _("ppdc: Invalid #include/#po filename \"%s\"!\n"), n);
+                      _("ppdc: Invalid #include/#po filename \"%s\"\n"), n);
       return (0);
     }
 
@@ -315,7 +353,7 @@ ppdcSource::get_attr(ppdcFile *fp,  // I - File to read
   if (!get_token(fp, name, sizeof(name)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected name after %s on line %d of %s!\n"),
+                    _("ppdc: Expected name after %s on line %d of %s\n"),
                    loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
     return (0);
   }
@@ -323,7 +361,7 @@ ppdcSource::get_attr(ppdcFile *fp,  // I - File to read
   if (!get_token(fp, selector, sizeof(selector)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected selector after %s on line %d of %s!\n"),
+                    _("ppdc: Expected selector after %s on line %d of %s\n"),
                    loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
     return (0);
   }
@@ -334,7 +372,7 @@ ppdcSource::get_attr(ppdcFile *fp,  // I - File to read
   if (!get_token(fp, value, sizeof(value)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected value after %s on line %d of %s!\n"),
+                    _("ppdc: Expected value after %s on line %d of %s\n"),
                    loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
     return (0);
   }
@@ -442,7 +480,7 @@ ppdcSource::get_color_model(ppdcFile *fp)
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected name/text combination for ColorModel on "
-                     "line %d of %s!\n"), fp->line, fp->filename);
+                     "line %d of %s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
@@ -455,7 +493,7 @@ ppdcSource::get_color_model(ppdcFile *fp)
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected colorspace for ColorModel on line %d of "
-                     "%s!\n"), fp->line, fp->filename);
+                     "%s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
@@ -466,7 +504,7 @@ ppdcSource::get_color_model(ppdcFile *fp)
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected color order for ColorModel on line %d of "
-                     "%s!\n"), fp->line, fp->filename);
+                     "%s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
@@ -477,7 +515,7 @@ ppdcSource::get_color_model(ppdcFile *fp)
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected compression for ColorModel on line %d of "
-                     "%s!\n"), fp->line, fp->filename);
+                     "%s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
@@ -535,7 +573,7 @@ ppdcSource::get_color_profile(
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected resolution/mediatype following "
-                     "ColorProfile on line %d of %s!\n"),
+                     "ColorProfile on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -658,7 +696,7 @@ ppdcSource::get_constraint(ppdcFile *fp)// I - File to read
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected constraints string for UIConstraints on "
-                     "line %d of %s!\n"), fp->line, fp->filename);
+                     "line %d of %s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
@@ -667,7 +705,7 @@ ppdcSource::get_constraint(ppdcFile *fp)// I - File to read
   if (*ptr != '*')
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Option constraint must *name on line %d of %s!\n"),
+                    _("ppdc: Option constraint must *name on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -690,7 +728,7 @@ ppdcSource::get_constraint(ppdcFile *fp)// I - File to read
   if (*ptr != '*')
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected two option names on line %d of %s!\n"),
+                    _("ppdc: Expected two option names on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -789,7 +827,7 @@ ppdcSource::get_duplex(ppdcFile   *fp,      // I - File to read from
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected duplex type after Duplex on line %d of "
-                     "%s!\n"), fp->line, fp->filename);
+                     "%s\n"), fp->line, fp->filename);
     return;
   }
 
@@ -868,7 +906,7 @@ ppdcSource::get_duplex(ppdcFile   *fp,      // I - File to read from
   }
   else
     _cupsLangPrintf(stderr,
-                    _("ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"),
+                    _("ppdc: Unknown duplex type \"%s\" on line %d of %s\n"),
                    temp, fp->line, fp->filename);
 }
 
@@ -894,7 +932,7 @@ ppdcSource::get_filter(ppdcFile *fp)        // I - File to read
   if (!get_token(fp, type, sizeof(type)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected a filter definition on line %d of %s!\n"),
+                    _("ppdc: Expected a filter definition on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -917,7 +955,7 @@ ppdcSource::get_filter(ppdcFile *fp)        // I - File to read
     if (!get_token(fp, program, sizeof(program)))
     {
       _cupsLangPrintf(stderr,
-                      _("ppdc: Expected a program name on line %d of %s!\n"),
+                      _("ppdc: Expected a program name on line %d of %s\n"),
                      fp->line, fp->filename);
       return (NULL);
     }
@@ -927,14 +965,14 @@ ppdcSource::get_filter(ppdcFile *fp)      // I - File to read
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Invalid empty MIME type for filter on line %d of "
-                     "%s!\n"), fp->line, fp->filename);
+                     "%s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
   if (cost < 0 || cost > 200)
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Invalid cost for filter on line %d of %s!\n"),
+                    _("ppdc: Invalid cost for filter on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -943,7 +981,7 @@ ppdcSource::get_filter(ppdcFile *fp)        // I - File to read
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Invalid empty program name for filter on line %d "
-                     "of %s!\n"), fp->line, fp->filename);
+                     "of %s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
@@ -966,7 +1004,7 @@ ppdcSource::get_float(ppdcFile *fp)        // I - File to read
   // Get the number from the file and range-check...
   if (!get_token(fp, temp, sizeof(temp)))
   {
-    _cupsLangPrintf(stderr, _("ppdc: Expected real number on line %d of %s!\n"),
+    _cupsLangPrintf(stderr, _("ppdc: Expected real number on line %d of %s\n"),
                    fp->line, fp->filename);
     return (-1.0f);
   }
@@ -977,7 +1015,7 @@ ppdcSource::get_float(ppdcFile *fp)        // I - File to read
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Unknown trailing characters in real number \"%s\" "
-                     "on line %d of %s!\n"), temp, fp->line, fp->filename);
+                     "on line %d of %s\n"), temp, fp->line, fp->filename);
     return (-1.0f);
   }
   else
@@ -1020,7 +1058,7 @@ ppdcSource::get_font(ppdcFile *fp)        // I - File to read
   if (!get_token(fp, name, sizeof(name)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected name after Font on line %d of %s!\n"),
+                    _("ppdc: Expected name after Font on line %d of %s\n"),
                    fp->line, fp->filename);
     return (0);
   }
@@ -1040,7 +1078,7 @@ ppdcSource::get_font(ppdcFile *fp)        // I - File to read
     {
       _cupsLangPrintf(stderr,
                       _("ppdc: Expected encoding after Font on line %d of "
-                       "%s!\n"), fp->line, fp->filename);
+                       "%s\n"), fp->line, fp->filename);
       return (0);
     }
 
@@ -1048,7 +1086,7 @@ ppdcSource::get_font(ppdcFile *fp)        // I - File to read
     {
       _cupsLangPrintf(stderr,
                       _("ppdc: Expected version after Font on line %d of "
-                       "%s!\n"), fp->line, fp->filename);
+                       "%s\n"), fp->line, fp->filename);
       return (0);
     }
 
@@ -1056,14 +1094,14 @@ ppdcSource::get_font(ppdcFile *fp)      // I - File to read
     {
       _cupsLangPrintf(stderr,
                       _("ppdc: Expected charset after Font on line %d of "
-                       "%s!\n"), fp->line, fp->filename);
+                       "%s\n"), fp->line, fp->filename);
       return (0);
     }
 
     if (!get_token(fp, temp, sizeof(temp)))
     {
       _cupsLangPrintf(stderr,
-                      _("ppdc: Expected status after Font on line %d of %s!\n"),
+                      _("ppdc: Expected status after Font on line %d of %s\n"),
                      fp->line, fp->filename);
       return (0);
     }
@@ -1075,7 +1113,7 @@ ppdcSource::get_font(ppdcFile *fp)        // I - File to read
     else
     {
       _cupsLangPrintf(stderr,
-                      _("ppdc: Bad status keyword %s on line %d of %s!\n"),
+                      _("ppdc: Bad status keyword %s on line %d of %s\n"),
                      temp, fp->line, fp->filename);
       return (0);
     }
@@ -1118,7 +1156,7 @@ ppdcSource::get_generic(ppdcFile   *fp,   // I - File to read
   if (!get_token(fp, name, sizeof(name)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected name/text after %s on line %d of %s!\n"),
+                    _("ppdc: Expected name/text after %s on line %d of %s\n"),
                    keyword, fp->line, fp->filename);
     return (NULL);
   }
@@ -1167,7 +1205,7 @@ ppdcSource::get_group(ppdcFile   *fp,     // I - File to read
   if (!get_token(fp, name, sizeof(name)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected group name/text on line %d of %s!\n"),
+                    _("ppdc: Expected group name/text on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -1208,7 +1246,7 @@ ppdcSource::get_installable(ppdcFile *fp)
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected name/text after Installable on line %d "
-                     "of %s!\n"), fp->line, fp->filename);
+                     "of %s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
@@ -1283,7 +1321,7 @@ ppdcSource::get_integer(const char *v)    // I - Value string
     while (*v && *v != ')')
     {
       // Skip leading whitespace...
-      while (*v && isspace(*v & 255));
+      while (*v && isspace(*v & 255))
         v ++;
 
       if (!*v || *v == ')')
@@ -1463,7 +1501,7 @@ ppdcSource::get_integer(ppdcFile *fp)     // I - File to read
 
   if (!get_token(fp, temp, sizeof(temp)))
   {
-    _cupsLangPrintf(stderr, _("ppdc: Expected integer on line %d of %s!\n"),
+    _cupsLangPrintf(stderr, _("ppdc: Expected integer on line %d of %s\n"),
                    fp->line, fp->filename);
     return (-1);
   }
@@ -1526,6 +1564,7 @@ ppdcSource::get_option(ppdcFile   *fp,    // I - File to read
   ppdcOptSection section;              // Option section
   float                order;                  // Option order
   ppdcOption   *o;                     // Option
+  ppdcGroup    *mg;                    // Matching group, if any
 
 
   // Read the Option parameters:
@@ -1534,7 +1573,7 @@ ppdcSource::get_option(ppdcFile   *fp,    // I - File to read
   if (!get_token(fp, name, sizeof(name)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected option name/text on line %d of %s!\n"),
+                    _("ppdc: Expected option name/text on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -1546,7 +1585,7 @@ ppdcSource::get_option(ppdcFile   *fp,    // I - File to read
 
   if (!get_token(fp, type, sizeof(type)))
   {
-    _cupsLangPrintf(stderr, _("ppdc: Expected option type on line %d of %s!\n"),
+    _cupsLangPrintf(stderr, _("ppdc: Expected option type on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -1560,7 +1599,7 @@ ppdcSource::get_option(ppdcFile   *fp,    // I - File to read
   else
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Invalid option type \"%s\" on line %d of %s!\n"),
+                    _("ppdc: Invalid option type \"%s\" on line %d of %s\n"),
                    type, fp->line, fp->filename);
     return (NULL);
   }
@@ -1568,7 +1607,7 @@ ppdcSource::get_option(ppdcFile   *fp,    // I - File to read
   if (!get_token(fp, type, sizeof(type)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected option section on line %d of %s!\n"),
+                    _("ppdc: Expected option section on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -1589,14 +1628,14 @@ ppdcSource::get_option(ppdcFile   *fp,  // I - File to read
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Invalid option section \"%s\" on line %d of "
-                     "%s!\n"), type, fp->line, fp->filename);
+                     "%s\n"), type, fp->line, fp->filename);
     return (NULL);
   }
 
   order = get_float(fp);
 
   // See if the option already exists...
-  if ((o = d->find_option(name)) == NULL)
+  if ((o = d->find_option_group(name, &mg)) == NULL)
   {
     // Nope, add a new one...
     o = new ppdcOption(ot, name, text, section, order);
@@ -1605,7 +1644,14 @@ ppdcSource::get_option(ppdcFile   *fp,   // I - File to read
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Option %s redefined with a different type on line "
-                     "%d of %s!\n"), name, fp->line, fp->filename);
+                     "%d of %s\n"), name, fp->line, fp->filename);
+    return (NULL);
+  }
+  else if (g != mg)
+  {
+    _cupsLangPrintf(stderr,
+                    _("ppdc: Option %s defined in two different groups on line "
+                     "%d of %s\n"), name, fp->line, fp->filename);
     return (NULL);
   }
 
@@ -1634,7 +1680,7 @@ ppdcSource::get_po(ppdcFile *fp)  // I - File to read
   if (!get_token(fp, locale, sizeof(locale)))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Expected locale after #po on line %d of %s!\n"),
+                    _("ppdc: Expected locale after #po on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -1643,7 +1689,7 @@ ppdcSource::get_po(ppdcFile *fp)  // I - File to read
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected filename after #po %s on line %d of "
-                     "%s!\n"), locale, fp->line, fp->filename);
+                     "%s\n"), locale, fp->line, fp->filename);
     return (NULL);
   }
 
@@ -1651,7 +1697,7 @@ ppdcSource::get_po(ppdcFile *fp)  // I - File to read
   if (find_po(locale))
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Duplicate #po for locale %s on line %d of %s!\n"),
+                    _("ppdc: Duplicate #po for locale %s on line %d of %s\n"),
                    locale, fp->line, fp->filename);
     return (NULL);
   }
@@ -1665,7 +1711,9 @@ ppdcSource::get_po(ppdcFile *fp)  // I - File to read
     strcpy(basedir, ".");
 
   // Find the po file...
-  if (!pofilename[0] ||
+  pofilename[0] = '\0';
+
+  if (!poname[0] ||
       find_include(poname, basedir, pofilename, sizeof(pofilename)))
   {
     // Found it, so load it...
@@ -1681,7 +1729,7 @@ ppdcSource::get_po(ppdcFile *fp)  // I - File to read
   else
   {
     _cupsLangPrintf(stderr,
-                    _("ppdc: Unable to find #po file %s on line %d of %s!\n"),
+                    _("ppdc: Unable to find #po file %s on line %d of %s\n"),
                    poname, fp->line, fp->filename);
     return (NULL);
   }
@@ -1717,7 +1765,7 @@ ppdcSource::get_resolution(ppdcFile *fp)// I - File to read
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected override field after Resolution on line "
-                     "%d of %s!\n"), fp->line, fp->filename);
+                     "%d of %s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
@@ -1734,7 +1782,7 @@ ppdcSource::get_resolution(ppdcFile *fp)// I - File to read
   {
     _cupsLangPrintf(stderr,
                    _("ppdc: Expected name/text after Resolution on line %d of "
-                     "%s!\n"), fp->line, fp->filename);
+                     "%s\n"), fp->line, fp->filename);
     return (NULL);
   }
 
@@ -1748,7 +1796,7 @@ ppdcSource::get_resolution(ppdcFile *fp)// I - File to read
     case 0 :
         _cupsLangPrintf(stderr,
                        _("ppdc: Bad resolution name \"%s\" on line %d of "
-                         "%s!\n"), name, fp->line, fp->filename);
+                         "%s\n"), name, fp->line, fp->filename);
         break;
     case 1 :
         ydpi = xdpi;
@@ -1815,7 +1863,7 @@ ppdcSource::get_simple_profile(ppdcFile *fp)
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Expected resolution/mediatype following "
-                     "SimpleColorProfile on line %d of %s!\n"),
+                     "SimpleColorProfile on line %d of %s\n"),
                    fp->line, fp->filename);
     return (NULL);
   }
@@ -2003,9 +2051,11 @@ ppdcSource::get_token(ppdcFile *fp,      // I - File to read
        }
        else
        {
-         _cupsLangPrintf(stderr,
-                         _("ppdc: Undefined variable (%s) on line %d of "
-                           "%s.\n"), name, fp->line, fp->filename);
+         if (!(cond_state & PPDC_COND_SKIP))
+           _cupsLangPrintf(stderr,
+                           _("ppdc: Undefined variable (%s) on line %d of "
+                             "%s.\n"), name, fp->line, fp->filename);
+
          snprintf(bufptr, bufend - bufptr + 1, "$%s", name);
          bufptr += strlen(name) + 1;
        }
@@ -2114,7 +2164,7 @@ ppdcSource::get_token(ppdcFile *fp,       // I - File to read
   {
     _cupsLangPrintf(stderr,
                     _("ppdc: Unterminated string starting with %c on line %d "
-                     "of %s!\n"), quote, startline, fp->filename);
+                     "of %s\n"), quote, startline, fp->filename);
     return (NULL);
   }
 
@@ -2351,7 +2401,7 @@ ppdcSource::read_file(const char  *f,     // I - File to read
   delete fp;
 
   if (cond_current != cond_stack)
-    _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"!\n"), f);
+    _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"\n"), f);
 }
 
 
@@ -2366,6 +2416,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
 {
   ppdcDriver   *d;                     // Current driver
   ppdcGroup    *g,                     // Current group
+               *mg,                    // Matching group
                *general,               // General options group
                *install;               // Installable options group
   ppdcOption   *o;                     // Current option
@@ -2377,7 +2428,10 @@ ppdcSource::scan_file(ppdcFile   *fp,    // I - File to read
 
   // Initialize things as needed...
   if (inc && td)
+  {
     d = td;
+    d->retain();
+  }
   else
     d = new ppdcDriver(td);
 
@@ -2430,13 +2484,13 @@ ppdcSource::scan_file(ppdcFile   *fp,   // I - File to read
       if ((cond_current - cond_stack) >= 100)
       {
         _cupsLangPrintf(stderr,
-                       _("ppdc: Too many nested #if's on line %d of %s!\n"),
+                       _("ppdc: Too many nested #if's on line %d of %s\n"),
                        fp->line, fp->filename);
        break;
       }
 
       cond_current ++;
-      if (get_integer(fp))
+      if (get_integer(fp) > 0)
         *cond_current = PPDC_COND_SATISFIED;
       else
       {
@@ -2448,7 +2502,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
     {
       if (cond_current == cond_stack)
       {
-        _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s!\n"),
+        _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s\n"),
                        fp->line, fp->filename);
         break;
       }
@@ -2458,7 +2512,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
         get_integer(fp);
        *cond_current |= PPDC_COND_SKIP;
       }
-      else if (get_integer(fp))
+      else if (get_integer(fp) > 0)
       {
         *cond_current |= PPDC_COND_SATISFIED;
        *cond_current &= ~PPDC_COND_SKIP;
@@ -2483,7 +2537,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
     {
       if (cond_current == cond_stack)
       {
-        _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s!\n"),
+        _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s\n"),
                        fp->line, fp->filename);
         break;
       }
@@ -2513,7 +2567,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
     {
       if (cond_current == cond_stack)
       {
-        _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s!\n"),
+        _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s\n"),
                        fp->line, fp->filename);
         break;
       }
@@ -2555,7 +2609,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Expected include filename on line %d of "
-                         "%s!\n"), fp->line, fp->filename);
+                         "%s\n"), fp->line, fp->filename);
         break;
       }
 
@@ -2579,7 +2633,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
        delete incfile;
 
        if (cond_current != old_current)
-         _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"!\n"),
+         _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"\n"),
                          incname);
       }
       else
@@ -2587,7 +2641,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
        // Can't find it!
        _cupsLangPrintf(stderr,
                        _("ppdc: Unable to find include file \"%s\" on line %d "
-                         "of %s!\n"), inctemp, fp->line, fp->filename);
+                         "of %s\n"), inctemp, fp->line, fp->filename);
        break;
       }
     }
@@ -2655,7 +2709,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Choice found on line %d of %s with no "
-                         "Option!\n"), fp->line, fp->filename);
+                         "Option\n"), fp->line, fp->filename);
         break;
       }
 
@@ -2730,7 +2784,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Expected string after Copyright on line %d "
-                         "of %s!\n"), fp->line, fp->filename);
+                         "of %s\n"), fp->line, fp->filename);
        break;
       }
 
@@ -2807,13 +2861,22 @@ ppdcSource::scan_file(ppdcFile   *fp,   // I - File to read
       }
 
       // Add the choice to the cupsDarkness option...
-      if ((o = d->find_option("cupsDarkness")) == NULL)
+      if ((o = d->find_option_group("cupsDarkness", &mg)) == NULL)
       {
        // Create the cupsDarkness option...
        o = new ppdcOption(PPDC_PICKONE, "cupsDarkness", "Darkness", PPDC_SECTION_ANY, 10.0f);
        g = general;
        g->add_option(o);
       }
+      else if (mg != general)
+      {
+       _cupsLangPrintf(stderr,
+                       _("ppdc: Option %s defined in two different groups on "
+                         "line %d of %s\n"), "cupsDarkness", fp->line,
+                       fp->filename);
+       c->release();
+       continue;
+      }
 
       o->add_choice(c);
 
@@ -2832,7 +2895,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Expected driver type keyword following "
-                         "DriverType on line %d of %s!\n"),
+                         "DriverType on line %d of %s\n"),
                        fp->line, fp->filename);
         continue;
       }
@@ -2850,7 +2913,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
         d->type = PPDC_DRIVER_LABEL;
       else
         _cupsLangPrintf(stderr,
-                       _("ppdc: Unknown driver type %s on line %d of %s!\n"),
+                       _("ppdc: Unknown driver type %s on line %d of %s\n"),
                        temp, fp->line, fp->filename);
     }
     else if (!strcasecmp(temp, "Duplex"))
@@ -2884,13 +2947,22 @@ ppdcSource::scan_file(ppdcFile   *fp,   // I - File to read
       }
 
       // Add the choice to the cupsFinishing option...
-      if ((o = d->find_option("cupsFinishing")) == NULL)
+      if ((o = d->find_option_group("cupsFinishing", &mg)) == NULL)
       {
        // Create the cupsFinishing option...
        o = new ppdcOption(PPDC_PICKONE, "cupsFinishing", "Finishing", PPDC_SECTION_ANY, 10.0f);
        g = general;
        g->add_option(o);
       }
+      else if (mg != general)
+      {
+       _cupsLangPrintf(stderr,
+                       _("ppdc: Option %s defined in two different groups on "
+                         "line %d of %s\n"), "cupsFinishing", fp->line,
+                       fp->filename);
+       c->release();
+       continue;
+      }
 
       o->add_choice(c);
 
@@ -2966,7 +3038,8 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       }
 
       // Add the choice to the InputSlot option...
-      if ((o = d->find_option("InputSlot")) == NULL)
+      
+      if ((o = d->find_option_group("InputSlot", &mg)) == NULL)
       {
        // Create the InputSlot option...
        o = new ppdcOption(PPDC_PICKONE, "InputSlot", "Media Source",
@@ -2974,6 +3047,15 @@ ppdcSource::scan_file(ppdcFile   *fp,    // I - File to read
        g = general;
        g->add_option(o);
       }
+      else if (mg != general)
+      {
+       _cupsLangPrintf(stderr,
+                       _("ppdc: Option %s defined in two different groups on "
+                         "line %d of %s\n"), "InputSlot", fp->line,
+                       fp->filename);
+       c->release();
+       continue;
+      }
 
       o->add_choice(c);
 
@@ -3016,7 +3098,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Expected name after Manufacturer on line %d "
-                         "of %s!\n"), fp->line, fp->filename);
+                         "of %s\n"), fp->line, fp->filename);
        break;
       }
 
@@ -3049,7 +3131,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Expected name after MediaSize on line %d of "
-                         "%s!\n"), fp->line, fp->filename);
+                         "%s\n"), fp->line, fp->filename);
        break;
       }
 
@@ -3062,7 +3144,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Unknown media size \"%s\" on line %d of "
-                         "%s!\n"), name, fp->line, fp->filename);
+                         "%s\n"), name, fp->line, fp->filename);
        break;
       }
 
@@ -3090,7 +3172,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       }
 
       // Add the choice to the MediaType option...
-      if ((o = d->find_option("MediaType")) == NULL)
+      if ((o = d->find_option_group("MediaType", &mg)) == NULL)
       {
        // Create the MediaType option...
        o = new ppdcOption(PPDC_PICKONE, "MediaType", "Media Type",
@@ -3098,6 +3180,15 @@ ppdcSource::scan_file(ppdcFile   *fp,    // I - File to read
        g = general;
        g->add_option(o);
       }
+      else if (mg != general)
+      {
+       _cupsLangPrintf(stderr,
+                       _("ppdc: Option %s defined in two different groups on "
+                         "line %d of %s\n"), "MediaType", fp->line,
+                       fp->filename);
+       c->release();
+       continue;
+      }
 
       o->add_choice(c);
 
@@ -3130,7 +3221,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Expected name after ModelName on line %d of "
-                         "%s!\n"), fp->line, fp->filename);
+                         "%s\n"), fp->line, fp->filename);
        break;
       }
 
@@ -3176,7 +3267,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Expected name after FileName on line %d of "
-                         "%s!\n"), fp->line, fp->filename);
+                         "%s\n"), fp->line, fp->filename);
        break;
       }
 
@@ -3193,7 +3284,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Expected name after PCFileName on line %d of "
-                         "%s!\n"), fp->line, fp->filename);
+                         "%s\n"), fp->line, fp->filename);
        break;
       }
 
@@ -3214,7 +3305,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       }
 
       // Add the choice to the Resolution option...
-      if ((o = d->find_option("Resolution")) == NULL)
+      if ((o = d->find_option_group("Resolution", &mg)) == NULL)
       {
        // Create the Resolution option...
        o = new ppdcOption(PPDC_PICKONE, "Resolution", NULL, PPDC_SECTION_ANY,
@@ -3222,6 +3313,15 @@ ppdcSource::scan_file(ppdcFile   *fp,    // I - File to read
        g = general;
        g->add_option(o);
       }
+      else if (mg != general)
+      {
+       _cupsLangPrintf(stderr,
+                       _("ppdc: Option %s defined in two different groups on "
+                         "line %d of %s\n"), "Resolution", fp->line,
+                       fp->filename);
+       c->release();
+       continue;
+      }
 
       o->add_choice(c);
 
@@ -3287,7 +3387,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       {
         _cupsLangPrintf(stderr,
                        _("ppdc: Expected string after Version on line %d of "
-                         "%s!\n"), fp->line, fp->filename);
+                         "%s\n"), fp->line, fp->filename);
        break;
       }
 
@@ -3297,7 +3397,7 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
     else
     {
       _cupsLangPrintf(stderr,
-                      _("ppdc: Unknown token \"%s\" seen on line %d of %s!\n"),
+                      _("ppdc: Unknown token \"%s\" seen on line %d of %s\n"),
                      temp, fp->line, fp->filename);
       break;
     }
@@ -3318,6 +3418,8 @@ ppdcSource::scan_file(ppdcFile   *fp,     // I - File to read
       drivers->add(d);
     }
   }
+  else if (inc && td)
+    td->release();
 }
 
 
@@ -3412,7 +3514,8 @@ ppdcSource::write_file(const char *f)     // I - File to write
   for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
   {
     // Start the driver...
-    cupsFilePrintf(fp, "\n// %s %s\n", d->manufacturer->value, d->model_name->value);
+    cupsFilePrintf(fp, "\n// %s %s\n", d->manufacturer->value,
+                   d->model_name->value);
     cupsFilePuts(fp, "{\n");
 
     // Write the copyright stings...