]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/ppd.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / cups / ppd.c
index 7c6c61a9a9b41666da119e469ae17795718a9b7b..ef2b0c718d5a722cde602097e0e45063fed8c588 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: ppd.c,v 1.51.2.33 2003/02/14 03:05:48 mike Exp $"
+ * "$Id: ppd.c,v 1.51.2.64 2004/06/29 03:46:29 mike Exp $"
  *
  *   PPD file routines for the Common UNIX Printing System (CUPS).
  *
@@ -15,9 +15,9 @@
  *       Attn: CUPS Licensing Information
  *       Easy Software Products
  *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636-3111 USA
+ *       Hollywood, Maryland 20636-3142 USA
  *
- *       Voice: (301) 373-9603
+ *       Voice: (301) 373-9600
  *       EMail: cups-info@cups.org
  *         WWW: http://www.cups.org
  *
@@ -41,6 +41,7 @@
  *   ppdOpen()             - Read a PPD file into memory.
  *   ppdOpenFd()           - Read a PPD file into memory.
  *   ppdOpenFile()         - Read a PPD file into memory.
+ *   ppdSetConformance()   - Set the conformance level for PPD files.
  *   ppd_add_attr()        - Add an attribute to the PPD data.
  *   ppd_add_choice()      - Add a choice to an option.
  *   ppd_add_size()        - Add a page size.
@@ -51,7 +52,8 @@
  *                           0x9f to be valid ISO-8859-1 characters...
  *   ppd_free_group()      - Free a single UI group.
  *   ppd_free_option()     - Free a single option.
- *   ppd_get_extopt()      - Get an extended option record.
+ *   ppd_get_extoption()   - Get an extended option record.
+ *   ppd_get_extparam()    - Get an extended parameter record.
  *   ppd_get_group()       - Find or create the named group as needed.
  *   ppd_get_option()      - Find or create the named option as needed.
  *   ppd_read()            - Read a line from a PPD file, skipping comment
@@ -97,6 +99,8 @@
 static ppd_status_t    ppd_status = PPD_OK;
                                        /* Status of last ppdOpen*() */
 static int             ppd_line = 0;   /* Current line number */
+static ppd_conform_t   ppd_conform = PPD_CONFORM_RELAXED;
+                                       /* Level of conformance required */
 
 
 /*
@@ -104,27 +108,31 @@ static int                ppd_line = 0;   /* Current line number */
  */
 
 static ppd_attr_t      *ppd_add_attr(ppd_file_t *ppd, const char *name,
-                                     const char *spec, const char *value);
+                                     const char *spec, const char *text,
+                                     const char *value);
 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);
 #ifndef __APPLE__
 static int             ppd_compare_groups(ppd_group_t *g0, ppd_group_t *g1);
 static int             ppd_compare_options(ppd_option_t *o0, ppd_option_t *o1);
 #endif /* !__APPLE__ */
-static void            ppd_decode(char *string);
+static int             ppd_decode(char *string);
 #ifndef __APPLE__
 static void            ppd_fix(char *string);
 #else
-#  define ppd_fix(s)
+#  define              ppd_fix(s)
 #endif /* !__APPLE__ */
 static void            ppd_free_group(ppd_group_t *group);
 static void            ppd_free_option(ppd_option_t *option);
-static ppd_ext_option_t        *ppd_get_extopt(ppd_file_t *ppd, const char *name);
+static ppd_ext_option_t        *ppd_get_extoption(ppd_file_t *ppd, const char *name);
+static ppd_ext_param_t *ppd_get_extparam(ppd_ext_option_t *opt,
+                                         const char *param,
+                                         const char *text);
 static ppd_group_t     *ppd_get_group(ppd_file_t *ppd, const char *name,
                                       const char *text);
 static ppd_option_t    *ppd_get_option(ppd_group_t *group, const char *name);
 static int             ppd_read(FILE *fp, char *keyword, char *option,
-                                char *text, char **string);
+                                char *text, char **string, int ignoreblank);
 
 
 /*
@@ -154,12 +162,14 @@ _ppd_attr_compare(ppd_attr_t **a, /* I - First attribute */
 void
 ppdClose(ppd_file_t *ppd)              /* I - PPD file record */
 {
-  int          i;                      /* Looping var */
-  ppd_emul_t   *emul;                  /* Current emulation */
-  ppd_group_t  *group;                 /* Current group */
-  char         **font;                 /* Current font */
-  char         **filter;               /* Current filter */
-  ppd_attr_t   **attr;                 /* Current attribute */
+  int                  i, j;           /* Looping var */
+  ppd_emul_t           *emul;          /* Current emulation */
+  ppd_group_t          *group;         /* Current group */
+  char                 **font;         /* Current font */
+  char                 **filter;       /* Current filter */
+  ppd_attr_t           **attr;         /* Current attribute */
+  ppd_ext_option_t     **opt;          /* Current extended option */
+  ppd_ext_param_t      **param;        /* Current extended parameter */
 
 
  /*
@@ -175,15 +185,8 @@ ppdClose(ppd_file_t *ppd)          /* I - PPD file record */
 
   ppd_free(ppd->patches);
   ppd_free(ppd->jcl_begin);
-  ppd_free(ppd->jcl_ps);
   ppd_free(ppd->jcl_end);
-  ppd_free(ppd->lang_encoding);
-  ppd_free(ppd->lang_version);
-  ppd_free(ppd->modelname);
-  ppd_free(ppd->ttrasterizer);
-  ppd_free(ppd->manufacturer);
-  ppd_free(ppd->nickname);
-  ppd_free(ppd->shortnickname);
+  ppd_free(ppd->jcl_ps);
 
  /*
   * Free any emulations...
@@ -217,14 +220,18 @@ ppdClose(ppd_file_t *ppd)         /* I - PPD file record */
   */
 
   if (ppd->num_sizes > 0)
+  {
     ppd_free(ppd->sizes);
+  }
 
  /*
   * Free any constraints...
   */
 
   if (ppd->num_consts > 0)
+  {
     ppd_free(ppd->consts);
+  }
 
  /*
   * Free any filters...
@@ -233,7 +240,9 @@ ppdClose(ppd_file_t *ppd)           /* I - PPD file record */
   if (ppd->num_filters > 0)
   {
     for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
+    {
       ppd_free(*filter);
+    }
 
     ppd_free(ppd->filters);
   }
@@ -245,7 +254,9 @@ ppdClose(ppd_file_t *ppd)           /* I - PPD file record */
   if (ppd->num_fonts > 0)
   {
     for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
+    {
       ppd_free(*font);
+    }
 
     ppd_free(ppd->fonts);
   }
@@ -255,7 +266,9 @@ ppdClose(ppd_file_t *ppd)           /* I - PPD file record */
   */
 
   if (ppd->num_profiles > 0)
+  {
     ppd_free(ppd->profiles);
+  }
 
  /*
   * Free any attributes...
@@ -272,6 +285,21 @@ ppdClose(ppd_file_t *ppd)          /* I - PPD file record */
     ppd_free(ppd->attrs);
   }
 
+  if (ppd->num_extended)
+  {
+    for (i = ppd->num_extended, opt = ppd->extended; i > 0; i --, opt ++)
+    {
+      ppd_free((*opt)->code);
+
+      for (j = (*opt)->num_params, param = (*opt)->params; j > 0; j --, param ++)
+        ppd_free((*param)->value);
+
+      ppd_free((*opt)->params);
+    }
+
+    ppd_free(ppd->extended);
+  }
+
  /*
   * Free the whole record...
   */
@@ -292,17 +320,27 @@ ppdErrorString(ppd_status_t status)       /* I - PPD status */
                  "OK",
                  "Unable to open PPD file",
                  "NULL PPD file pointer",
-                 "Missing PPD-Adobe-4.x header",
                  "Memory allocation error",
+                 "Missing PPD-Adobe-4.x header",
                  "Missing value string",
                  "Internal error",
+                 "Bad OpenGroup",
                  "OpenGroup without a CloseGroup first",
+                 "Bad OpenUI/JCLOpenUI",
+                 "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first",
                  "Bad OrderDependency",
                  "Bad UIConstraints",
+                 "Missing asterisk in column 1",
+                 "Line longer than the maximum allowed (255 characters)",
+                 "Illegal control character",
+                 "Illegal main keyword string",
+                 "Illegal option keyword string",
+                 "Illegal translation string",
+                 "Illegal whitespace character"
                };
 
 
-  if (status < PPD_OK || status > PPD_BAD_UI_CONSTRAINTS)
+  if (status < PPD_OK || status > PPD_ILLEGAL_WHITESPACE)
     return ("Unknown");
   else
     return (messages[status]);
@@ -358,6 +396,54 @@ ppdOpen(FILE *fp)                  /* I - File to read from */
   ppd_profile_t                *profile;       /* Pointer to color profile */
   char                 **filter;       /* Pointer to filter */
   cups_lang_t          *language;      /* Default language */
+  int                  ui_keyword;     /* Is this line a UI keyword? */
+  static const char * const ui_keywords[] =
+                       {
+                         /* Boolean keywords */
+                         "BlackSubstitution",
+                         "Booklet",
+                         "Collate",
+                         "ManualFeed",
+                         "MirrorPrint",
+                         "NegativePrint",
+                         "Sorter",
+                         "TraySwitch",
+
+                         /* PickOne keywords */
+                         "AdvanceMedia",
+                         "BindColor",
+                         "BindEdge",
+                         "BindType",
+                         "BindWhen",
+                         "BitsPerPixel",
+                         "ColorModel",
+                         "CutMedia",
+                         "Duplex",
+                         "FoldType",
+                         "FoldWhen",
+                         "InputSlot",
+                         "JCLFrameBufferSize",
+                         "JCLResolution",
+                         "Jog",
+                         "MediaColor",
+                         "MediaType",
+                         "MediaWeight",
+                         "OutputBin",
+                         "OutputMode",
+                         "OutputOrder",
+                         "PageRegion",
+                         "PageSize",
+                         "Resolution",
+                         "Separations",
+                         "Signature",
+                         "Slipsheet",
+                         "Smoothing",
+                         "StapleLocation",
+                         "StapleOrientation",
+                         "StapleWhen",
+                         "StapleX",
+                         "StapleY"
+                       };
 
 
  /*
@@ -381,7 +467,9 @@ ppdOpen(FILE *fp)                   /* I - File to read from */
   * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
   */
 
-  mask = ppd_read(fp, keyword, name, text, &string);
+  mask = ppd_read(fp, keyword, name, text, &string, 0);
+
+  DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask, keyword));
 
   if (mask == 0 ||
       strcmp(keyword, "PPD-Adobe") != 0 ||
@@ -391,7 +479,8 @@ ppdOpen(FILE *fp)                   /* I - File to read from */
     * Either this is not a PPD file, or it is not a 4.x PPD file.
     */
 
-    ppd_status = PPD_MISSING_PPDADOBE4;
+    if (ppd_status == PPD_OK)
+      ppd_status = PPD_MISSING_PPDADOBE4;
 
     ppd_free(string);
 
@@ -406,7 +495,7 @@ ppdOpen(FILE *fp)                   /* I - File to read from */
   * Allocate memory for the PPD file record...
   */
 
-  if ((ppd = calloc(sizeof(ppd_file_t), 1)) == NULL)
+  if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
   {
     ppd_status = PPD_ALLOC_ERROR;
 
@@ -425,21 +514,22 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
   language = cupsLangDefault();
 
 #ifdef LC_NUMERIC
-  oldlocale = setlocale(LC_NUMERIC, "C");
+  oldlocale = _cupsSaveLocale(LC_NUMERIC, "C");
 #else
-  oldlocale = setlocale(LC_ALL, "C");
+  oldlocale = _cupsSaveLocale(LC_ALL, "C");
 #endif /* LC_NUMERIC */
 
  /*
   * Read lines from the PPD file and add them to the file record...
   */
 
-  group    = NULL;
-  subgroup = NULL;
-  option   = NULL;
-  choice   = NULL;
+  group      = NULL;
+  subgroup   = NULL;
+  option     = NULL;
+  choice     = NULL;
+  ui_keyword = 0;
 
-  while ((mask = ppd_read(fp, keyword, name, text, &string)) != 0)
+  while ((mask = ppd_read(fp, keyword, name, text, &string, 1)) != 0)
   {
 #ifdef DEBUG
     printf("mask = %x, keyword = \"%s\"", mask, keyword);
@@ -461,123 +551,174 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
     puts("");
 #endif /* DEBUG */
 
-    if (strcmp(keyword, "CloseUI") != 0 &&
-        strcmp(keyword, "JCLCloseUI") != 0 &&
-        strcmp(keyword, "CloseGroup") != 0 &&
-       strcmp(keyword, "CloseSubGroup") != 0 &&
-       strncmp(keyword, "Default", 7) != 0 &&
-       string == NULL)
+    if (strcmp(keyword, "CloseUI") && strcmp(keyword, "CloseGroup") &&
+       strcmp(keyword, "CloseSubGroup") && strncmp(keyword, "Default", 7) &&
+        strcmp(keyword, "JCLCloseUI") && strcmp(keyword, "JCLOpenUI") &&
+       strcmp(keyword, "OpenUI") && strcmp(keyword, "OpenGroup") &&
+       strcmp(keyword, "OpenSubGroup") && string == NULL)
     {
      /*
       * Need a string value!
       */
 
-      ppdClose(ppd);
+      ppd_status = PPD_MISSING_VALUE;
 
-      cupsLangFree(language);
+      goto error;
+    }
 
-#ifdef LC_NUMERIC
-      setlocale(LC_NUMERIC, oldlocale);
-#else
-      setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
+   /*
+    * Certain main keywords (as defined by the PPD spec) may be used
+    * without the usual OpenUI/CloseUI stuff.  Presumably this is just
+    * so that Adobe wouldn't completely break compatibility with PPD
+    * files prior to v4.0 of the spec, but it is hopelessly
+    * inconsistent...  Catch these main keywords and automatically
+    * create the corresponding option, as needed...
+    */
 
-      ppd_status = PPD_MISSING_VALUE;
+    if (ui_keyword)
+    {
+     /*
+      * Previous line was a UI keyword...
+      */
 
-      return (NULL);
+      option     = NULL;
+      ui_keyword = 0;
+    }
+
+    if (option == NULL &&
+        (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
+           (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
+    {
+      for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
+        if (!strcmp(keyword, ui_keywords[i]))
+         break;
+
+      if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
+      {
+       /*
+        * Create the option in the appropriate group...
+       */
+
+        ui_keyword = 1;
+
+        DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
+                     keyword));
+
+        if (!group)
+       {
+          if (strcmp(keyword, "Collate") && strcmp(keyword, "Duplex") &&
+              strcmp(keyword, "InputSlot") && strcmp(keyword, "ManualFeed") &&
+              strcmp(keyword, "MediaType") && strcmp(keyword, "MediaColor") &&
+              strcmp(keyword, "MediaWeight") && strcmp(keyword, "OutputBin") &&
+              strcmp(keyword, "OutputMode") && strcmp(keyword, "OutputOrder") &&
+             strcmp(keyword, "PageSize") && strcmp(keyword, "PageRegion"))
+           group = ppd_get_group(ppd, "Extra",
+                                 cupsLangString(language, CUPS_MSG_EXTRA));
+         else
+           group = ppd_get_group(ppd, "General",
+                                 cupsLangString(language, CUPS_MSG_GENERAL));
+
+          if (group == NULL)
+           goto error;
+
+          DEBUG_printf(("Adding to group %s...\n", group->text));
+          option = ppd_get_option(group, keyword);
+         group  = NULL;
+       }
+       else
+          option = ppd_get_option(group, keyword);
+
+       if (option == NULL)
+       {
+          ppd_status = PPD_ALLOC_ERROR;
+
+          goto error;
+       }
+
+       /*
+       * Now fill in the initial information for the option...
+       */
+
+       if (!strncmp(keyword, "JCL", 3))
+          option->section = PPD_ORDER_JCL;
+       else
+          option->section = PPD_ORDER_ANY;
+
+       option->order = 10.0f;
+
+       if (i < 8)
+          option->ui = PPD_UI_BOOLEAN;
+       else
+          option->ui = PPD_UI_PICKONE;
+
+        for (j = 0; j < ppd->num_attrs; j ++)
+         if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
+             !strcmp(ppd->attrs[j]->name + 7, keyword) &&
+             ppd->attrs[j]->value)
+         {
+           DEBUG_printf(("Setting Default%s to %s via attribute...\n",
+                         option->keyword, ppd->attrs[j]->value));
+           strlcpy(option->defchoice, ppd->attrs[j]->value,
+                   sizeof(option->defchoice));
+           break;
+         }
+
+        if (strcmp(keyword, "PageSize") == 0)
+         strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SIZE),
+                  sizeof(option->text));
+       else if (strcmp(keyword, "MediaType") == 0)
+         strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_TYPE),
+                  sizeof(option->text));
+       else if (strcmp(keyword, "InputSlot") == 0)
+         strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SOURCE),
+                  sizeof(option->text));
+       else if (strcmp(keyword, "ColorModel") == 0)
+         strlcpy(option->text, cupsLangString(language, CUPS_MSG_OUTPUT_MODE),
+                  sizeof(option->text));
+       else if (strcmp(keyword, "Resolution") == 0)
+         strlcpy(option->text, cupsLangString(language, CUPS_MSG_RESOLUTION),
+                  sizeof(option->text));
+        else
+         strlcpy(option->text, keyword, sizeof(option->text));
+      }
     }
 
     if (strcmp(keyword, "LanguageLevel") == 0)
       ppd->language_level = atoi(string);
     else if (strcmp(keyword, "LanguageEncoding") == 0)
-    {
-      ppd_free(ppd->lang_encoding);
       ppd->lang_encoding = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "LanguageVersion") == 0)
-    {
-      ppd_free(ppd->lang_version);
       ppd->lang_version = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "Manufacturer") == 0)
-    {
-      ppd_free(ppd->manufacturer);
       ppd->manufacturer = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "ModelName") == 0)
-    {
-      ppd_free(ppd->modelname);
       ppd->modelname = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "Protocols") == 0)
-    {
-      ppd_free(ppd->protocols);
       ppd->protocols = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "PCFileName") == 0)
-    {
-      ppd_free(ppd->pcfilename);
       ppd->pcfilename = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "NickName") == 0)
-    {
-      ppd_free(ppd->nickname);
       ppd->nickname = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "Product") == 0)
-    {
-     /*
-      * Add each Product keyword as an attribute...
-      */
-
-      ppd_add_attr(ppd, keyword, "", string);
-
-     /*
-      * Save the last one in the product element...
-      */
-
       ppd->product = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "ShortNickName") == 0)
-    {
-      ppd_free(ppd->shortnickname);
       ppd->shortnickname = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "TTRasterizer") == 0)
-    {
-      ppd_free(ppd->ttrasterizer);
       ppd->ttrasterizer = string;
-      string = NULL;                   /* Don't free this string below */
-    }
     else if (strcmp(keyword, "JCLBegin") == 0)
     {
-      ppd_free(ppd->jcl_begin);
-      ppd_decode(string);              /* Decode quoted string */
-      ppd->jcl_begin = string;
-      string = NULL;                   /* Don't free this string below */
+      ppd->jcl_begin = strdup(string);
+      ppd_decode(ppd->jcl_begin);      /* Decode quoted string */
     }
     else if (strcmp(keyword, "JCLEnd") == 0)
     {
-      ppd_free(ppd->jcl_end);
-      ppd_decode(string);              /* Decode quoted string */
-      ppd->jcl_end = string;
-      string = NULL;                   /* Don't free this string below */
+      ppd->jcl_end = strdup(string);
+      ppd_decode(ppd->jcl_end);                /* Decode quoted string */
     }
     else if (strcmp(keyword, "JCLToPSInterpreter") == 0)
     {
-      ppd_free(ppd->jcl_ps);
-      ppd_decode(string);              /* Decode quoted string */
-      ppd->jcl_ps = string;
-      string = NULL;                   /* Don't free this string below */
+      ppd->jcl_ps = strdup(string);
+      ppd_decode(ppd->jcl_ps);         /* Decode quoted string */
     }
     else if (strcmp(keyword, "AccurateScreensSupport") == 0)
       ppd->accurate_screens = strcmp(string, "True") == 0;
@@ -585,21 +726,6 @@ ppdOpen(FILE *fp)                  /* I - File to read from */
       ppd->color_device = strcmp(string, "True") == 0;
     else if (strcmp(keyword, "ContoneOnly") == 0)
       ppd->contone_only = strcmp(string, "True") == 0;
-    else if (strcmp(keyword, "DefaultColorSpace") == 0)
-    {
-      if (strcmp(string, "CMY") == 0)
-        ppd->colorspace = PPD_CS_CMY;
-      else if (strcmp(string, "CMYK") == 0)
-        ppd->colorspace = PPD_CS_CMYK;
-      else if (strcmp(string, "RGB") == 0)
-        ppd->colorspace = PPD_CS_RGB;
-      else if (strcmp(string, "RGBK") == 0)
-        ppd->colorspace = PPD_CS_RGBK;
-      else if (strcmp(string, "N") == 0)
-        ppd->colorspace = PPD_CS_N;
-      else
-        ppd->colorspace = PPD_CS_GRAY;
-    }
     else if (strcmp(keyword, "cupsFlipDuplex") == 0)
       ppd->flip_duplex = strcmp(string, "True") == 0;
     else if (strcmp(keyword, "cupsManualCopies") == 0)
@@ -640,19 +766,9 @@ ppdOpen(FILE *fp)                  /* I - File to read from */
       {
         ppd_free(filter);
 
-       ppdClose(ppd);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
         ppd_status = PPD_ALLOC_ERROR;
 
-       return (NULL);
+       goto error;
       }
 
       ppd->filters     = filter;
@@ -682,116 +798,15 @@ ppdOpen(FILE *fp)                        /* I - File to read from */
 
       if (tempfonts == NULL)
       {
-        ppd_free(string);
-
-        ppdClose(ppd);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
         ppd_status = PPD_ALLOC_ERROR;
 
-       return (NULL);
+       goto error;
       }
       
       ppd->fonts                 = tempfonts;
       ppd->fonts[ppd->num_fonts] = strdup(name);
       ppd->num_fonts ++;
     }
-    else if (strcmp(keyword, "VariablePaperSize") == 0 &&
-             strcmp(string, "True") == 0 &&
-            !ppd->variable_sizes)
-    {
-      ppd->variable_sizes = 1;
-
-     /*
-      * Add a "Custom" page size entry...
-      */
-
-      ppd_add_size(ppd, "Custom");
-
-     /*
-      * Add a "Custom" page size option...
-      */
-
-      if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
-      {
-        ppd_group_t    *temp;
-
-
-       if ((temp = ppd_get_group(ppd, "General",
-                                  cupsLangString(language,
-                                                 CUPS_MSG_GENERAL))) == NULL)
-       {
-          ppdClose(ppd);
-
-         ppd_free(string);
-
-          cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-          setlocale(LC_NUMERIC, oldlocale);
-#else
-          setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
-          ppd_status = PPD_ALLOC_ERROR;
-
-         return (NULL);
-       }
-
-       if ((option = ppd_get_option(temp, "PageSize")) == NULL)
-       {
-          ppdClose(ppd);
-
-         ppd_free(string);
-
-          cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-          setlocale(LC_NUMERIC, oldlocale);
-#else
-          setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
-          ppd_status = PPD_ALLOC_ERROR;
-
-         return (NULL);
-       }
-      }
-
-      if ((choice = ppd_add_choice(option, "Custom")) == NULL)
-      {
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
-        ppd_status = PPD_ALLOC_ERROR;
-
-       return (NULL);
-      }
-
-      strlcpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
-              sizeof(choice->text));
-      option = NULL;
-    }
-    else if (strcmp(keyword, "MaxMediaWidth") == 0)
-      ppd->custom_max[0] = (float)atof(string);
-    else if (strcmp(keyword, "MaxMediaHeight") == 0)
-      ppd->custom_max[1] = (float)atof(string);
     else if (strcmp(keyword, "ParamCustomPageSize") == 0)
     {
       if (strcmp(name, "Width") == 0)
@@ -808,6 +823,8 @@ ppdOpen(FILE *fp)                   /* I - File to read from */
     else if (strcmp(keyword, "CustomPageSize") == 0 &&
              strcmp(name, "True") == 0)
     {
+      DEBUG_puts("Processing CustomPageSize...");
+
       if (!ppd->variable_sizes)
       {
        ppd->variable_sizes = 1;
@@ -827,48 +844,24 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
          ppd_group_t   *temp;
 
 
+          DEBUG_puts("PageSize option not found for CustomPageSize...");
+
          if ((temp = ppd_get_group(ppd, "General",
                                     cupsLangString(language,
                                                    CUPS_MSG_GENERAL))) == NULL)
          {
            DEBUG_puts("Unable to get general group!");
 
-            ppdClose(ppd);
-
-           ppd_free(string);
-
-            cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-            setlocale(LC_NUMERIC, oldlocale);
-#else
-            setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
-            ppd_status = PPD_ALLOC_ERROR;
-
-           return (NULL);
+           goto error;
          }
 
          if ((option = ppd_get_option(temp, "PageSize")) == NULL)
          {
            DEBUG_puts("Unable to get PageSize option!");
 
-            ppdClose(ppd);
-
-           ppd_free(string);
-
-            cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-            setlocale(LC_NUMERIC, oldlocale);
-#else
-            setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
             ppd_status = PPD_ALLOC_ERROR;
 
-           return (NULL);
+           goto error;
          }
         }
 
@@ -876,21 +869,9 @@ ppdOpen(FILE *fp)                  /* I - File to read from */
        {
          DEBUG_puts("Unable to add Custom choice!");
 
-          ppdClose(ppd);
-
-         ppd_free(string);
-
-          cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-          setlocale(LC_NUMERIC, oldlocale);
-#else
-          setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
           ppd_status = PPD_ALLOC_ERROR;
 
-         return (NULL);
+         goto error;
        }
 
        strlcpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
@@ -902,47 +883,23 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
       {
        DEBUG_puts("Unable to find PageSize option!");
 
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
         ppd_status = PPD_INTERNAL_ERROR;
 
-       return (NULL);
+       goto error;
       }
 
       if ((choice = ppdFindChoice(option, "Custom")) == NULL)
       {
        DEBUG_puts("Unable to find Custom choice!");
 
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
         ppd_status = PPD_INTERNAL_ERROR;
 
-       return (NULL);
+       goto error;
       }
 
       choice->code = string;
-      string = NULL;
-      option = NULL;
+      option       = NULL;
+      string       = NULL;             /* Don't add as an attribute below */
     }
     else if (strcmp(keyword, "LandscapeOrientation") == 0)
     {
@@ -962,7 +919,7 @@ ppdOpen(FILE *fp)                   /* I - File to read from */
        }
 
       ppd->num_emulations = count;
-      ppd->emulations     = calloc(sizeof(ppd_emul_t), count);
+      ppd->emulations     = calloc(count, sizeof(ppd_emul_t));
 
       for (i = 0, sptr = string; i < count; i ++)
       {
@@ -1003,31 +960,16 @@ ppdOpen(FILE *fp)                        /* I - File to read from */
     else if (strcmp(keyword, "JobPatchFile") == 0)
     {
       if (ppd->patches == NULL)
-      {
-        ppd->patches = string;
-       string       = NULL;
-      }
+        ppd->patches = strdup(string);
       else
       {
         temp = realloc(ppd->patches, strlen(ppd->patches) +
                                     strlen(string) + 1);
         if (temp == NULL)
        {
-          ppdClose(ppd);
-
-         ppd_free(string);
-
-          cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-          setlocale(LC_NUMERIC, oldlocale);
-#else
-          setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
           ppd_status = PPD_ALLOC_ERROR;
 
-         return (NULL);
+         goto error;
        }
 
         ppd->patches = temp;
@@ -1037,14 +979,25 @@ ppdOpen(FILE *fp)                        /* I - File to read from */
     }
     else if (strcmp(keyword, "OpenUI") == 0)
     {
+     /*
+      * Don't allow nesting of options...
+      */
+
+      if (option && ppd_conform == PPD_CONFORM_STRICT)
+      {
+        ppd_status = PPD_NESTED_OPEN_UI;
+
+       goto error;
+      }
+
      /*
       * Add an option record to the current sub-group, group, or file...
       */
 
       if (name[0] == '*')
-        strcpy(name, name + 1); /* Eliminate leading asterisk */
+        cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
 
-      for (i = strlen(name) - 1; i > 0 && isspace(name[i]); i --)
+      for (i = strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
         name[i] = '\0'; /* Eliminate trailing spaces */
 
       DEBUG_printf(("OpenUI of %s in group %s...\n", name,
@@ -1054,18 +1007,12 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
         option = ppd_get_option(subgroup, name);
       else if (group == NULL)
       {
-        if (strcmp(name, "Collate") != 0 &&
-            strcmp(name, "Duplex") != 0 &&
-            strcmp(name, "InputSlot") != 0 &&
-            strcmp(name, "ManualFeed") != 0 &&
-            strcmp(name, "MediaType") != 0 &&
-            strcmp(name, "MediaColor") != 0 &&
-            strcmp(name, "MediaWeight") != 0 &&
-            strcmp(name, "OutputBin") != 0 &&
-            strcmp(name, "OutputMode") != 0 &&
-            strcmp(name, "OutputOrder") != 0 &&
-           strcmp(name, "PageSize") != 0 &&
-            strcmp(name, "PageRegion") != 0)
+        if (strcmp(name, "Collate") && strcmp(name, "Duplex") &&
+            strcmp(name, "InputSlot") && strcmp(name, "ManualFeed") &&
+            strcmp(name, "MediaType") && strcmp(name, "MediaColor") &&
+            strcmp(name, "MediaWeight") && strcmp(name, "OutputBin") &&
+            strcmp(name, "OutputMode") && strcmp(name, "OutputOrder") &&
+           strcmp(name, "PageSize") && strcmp(name, "PageRegion"))
          group = ppd_get_group(ppd, "Extra",
                                cupsLangString(language, CUPS_MSG_EXTRA));
        else
@@ -1073,23 +1020,7 @@ ppdOpen(FILE *fp)                        /* I - File to read from */
                                cupsLangString(language, CUPS_MSG_GENERAL));
 
         if (group == NULL)
-       {
-          ppdClose(ppd);
-
-         ppd_free(string);
-
-          cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-          setlocale(LC_NUMERIC, oldlocale);
-#else
-          setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
-          ppd_status = PPD_ALLOC_ERROR;
-
-         return (NULL);
-       }
+         goto error;
 
         DEBUG_printf(("Adding to group %s...\n", group->text));
         option = ppd_get_option(group, name);
@@ -1100,34 +1031,42 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
 
       if (option == NULL)
       {
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
         ppd_status = PPD_ALLOC_ERROR;
 
-       return (NULL);
+       goto error;
       }
 
      /*
       * Now fill in the initial information for the option...
       */
 
-      if (strcmp(string, "PickMany") == 0)
+      if (string && strcmp(string, "PickMany") == 0)
         option->ui = PPD_UI_PICKMANY;
-      else if (strcmp(string, "Boolean") == 0)
+      else if (string && strcmp(string, "Boolean") == 0)
         option->ui = PPD_UI_BOOLEAN;
+      else if (string && strcmp(string, "PickOne") == 0)
+        option->ui = PPD_UI_PICKONE;
+      else if (ppd_conform == PPD_CONFORM_STRICT)
+      {
+        ppd_status = PPD_BAD_OPEN_UI;
+
+       goto error;
+      }
       else
         option->ui = PPD_UI_PICKONE;
 
+      for (j = 0; j < ppd->num_attrs; j ++)
+       if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
+           !strcmp(ppd->attrs[j]->name + 7, name) &&
+           ppd->attrs[j]->value)
+       {
+         DEBUG_printf(("Setting Default%s to %s via attribute...\n",
+                       option->keyword, ppd->attrs[j]->value));
+         strlcpy(option->defchoice, ppd->attrs[j]->value,
+                 sizeof(option->defchoice));
+         break;
+       }
+
       if (text[0])
       {
         strlcpy(option->text, text, sizeof(option->text));
@@ -1155,81 +1094,93 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
       }
 
       option->section = PPD_ORDER_ANY;
+
+      ppd_free(string);
+      string = NULL;
     }
     else if (strcmp(keyword, "JCLOpenUI") == 0)
     {
      /*
-      * Find the JCL group, and add if needed...
+      * Don't allow nesting of options...
       */
 
-      group = ppd_get_group(ppd, "JCL", "JCL");
-
-      if (group == NULL)
+      if (option && ppd_conform == PPD_CONFORM_STRICT)
       {
-        ppdClose(ppd);
+        ppd_status = PPD_NESTED_OPEN_UI;
 
-       ppd_free(string);
-
-        cupsLangFree(language);
+       goto error;
+      }
 
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
+     /*
+      * Find the JCL group, and add if needed...
+      */
 
-        ppd_status = PPD_ALLOC_ERROR;
+      group = ppd_get_group(ppd, "JCL", "JCL");
 
-       return (NULL);
-      }
+      if (group == NULL)
+       goto error;
 
      /*
       * Add an option record to the current JCLs...
       */
 
       if (name[0] == '*')
-        strcpy(name, name + 1);
+        cups_strcpy(name, name + 1);
 
       option = ppd_get_option(group, name);
 
       if (option == NULL)
       {
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
         ppd_status = PPD_ALLOC_ERROR;
 
-       return (NULL);
+       goto error;
       }
 
      /*
       * Now fill in the initial information for the option...
       */
 
-      if (strcmp(string, "PickMany") == 0)
+      if (string && strcmp(string, "PickMany") == 0)
         option->ui = PPD_UI_PICKMANY;
-      else if (strcmp(string, "Boolean") == 0)
+      else if (string && strcmp(string, "Boolean") == 0)
         option->ui = PPD_UI_BOOLEAN;
-      else
+      else if (string && strcmp(string, "PickOne") == 0)
         option->ui = PPD_UI_PICKONE;
+      else
+      {
+        ppd_status = PPD_BAD_OPEN_UI;
+
+       goto error;
+      }
+
+      for (j = 0; j < ppd->num_attrs; j ++)
+       if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
+           !strcmp(ppd->attrs[j]->name + 7, name) &&
+           ppd->attrs[j]->value)
+       {
+         DEBUG_printf(("Setting Default%s to %s via attribute...\n",
+                       option->keyword, ppd->attrs[j]->value));
+         strlcpy(option->defchoice, ppd->attrs[j]->value,
+                 sizeof(option->defchoice));
+         break;
+       }
 
       strlcpy(option->text, text, sizeof(option->text));
 
       option->section = PPD_ORDER_JCL;
       group = NULL;
+
+      ppd_free(string);
+      string = NULL;
     }
     else if (strcmp(keyword, "CloseUI") == 0 ||
              strcmp(keyword, "JCLCloseUI") == 0)
+    {
       option = NULL;
+
+      ppd_free(string);
+      string = NULL;
+    }
     else if (strcmp(keyword, "OpenGroup") == 0)
     {
      /*
@@ -1238,21 +1189,16 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
 
       if (group != NULL)
       {
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
+        ppd_status = PPD_NESTED_OPEN_GROUP;
 
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
+       goto error;
+      }
 
-        ppd_status = PPD_NESTED_OPEN_GROUP;
+      if (!string)
+      {
+        ppd_status = PPD_BAD_OPEN_GROUP;
 
-       return (NULL);
+       goto error;
       }
 
      /*
@@ -1276,33 +1222,32 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
       */
 
       group = ppd_get_group(ppd, string, sptr);
+
+      if (group == NULL)
+       goto error;
+
+      ppd_free(string);
+      string = NULL;
     }
     else if (strcmp(keyword, "CloseGroup") == 0)
+    {
       group = NULL;
+
+      ppd_free(string);
+      string = NULL;
+    }
     else if (strcmp(keyword, "OrderDependency") == 0 ||
              strcmp(keyword, "NonUIOrderDependency") == 0)
     {
       if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3)
       {
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
         ppd_status = PPD_BAD_ORDER_DEPENDENCY;
 
-       return (NULL);
+       goto error;
       }
 
       if (keyword[0] == '*')
-        strcpy(keyword, keyword + 1);
+        cups_strcpy(keyword, keyword + 1);
 
       if (strcmp(name, "ExitServer") == 0)
         section = PPD_ORDER_EXIT;
@@ -1344,66 +1289,87 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
         option->section = section;
        option->order   = order;
       }
+
+      ppd_free(string);
+      string = NULL;
     }
     else if (strncmp(keyword, "Default", 7) == 0)
     {
       if (string == NULL)
         continue;
 
+     /*
+      * Drop UI text, if any, from value...
+      */
+
       if (strchr(string, '/') != NULL)
         *strchr(string, '/') = '\0';
 
-      if (option == NULL)
+     /*
+      * Assign the default value as appropriate...
+      */
+
+      if (strcmp(keyword, "DefaultColorSpace") == 0)
       {
-        ppd_group_t    *temp;
+       /*
+        * Set default colorspace...
+       */
 
+       if (strcmp(string, "CMY") == 0)
+          ppd->colorspace = PPD_CS_CMY;
+       else if (strcmp(string, "CMYK") == 0)
+          ppd->colorspace = PPD_CS_CMYK;
+       else if (strcmp(string, "RGB") == 0)
+          ppd->colorspace = PPD_CS_RGB;
+       else if (strcmp(string, "RGBK") == 0)
+          ppd->colorspace = PPD_CS_RGBK;
+       else if (strcmp(string, "N") == 0)
+          ppd->colorspace = PPD_CS_N;
+       else
+          ppd->colorspace = PPD_CS_GRAY;
+      }
+      else if (option && strcmp(keyword + 7, option->keyword) == 0)
+      {
+       /*
+        * Set the default as part of the current option...
+       */
+
+        DEBUG_printf(("Setting %s to %s...\n", keyword, string));
 
+        strlcpy(option->defchoice, string, sizeof(option->defchoice));
+
+        DEBUG_printf(("%s is now %s...\n", keyword, option->defchoice));
+      }
+      else
+      {
        /*
-        * Only valid for Non-UI options...
+        * Lookup option and set if it has been defined...
        */
 
-        for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
-          if (temp->text[0] == '\0')
-           break;
+        ppd_option_t   *toption;       /* Temporary option */
 
-        if (i > 0)
-          for (i = 0; i < temp->num_options; i ++)
-           if (strcmp(keyword, temp->options[i].keyword) == 0)
-           {
-             strlcpy(temp->options[i].defchoice, string,
-                      sizeof(temp->options[i].defchoice));
-             break;
-           }
+
+        if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
+       {
+         DEBUG_printf(("Setting %s to %s...\n", keyword, string));
+         strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
+       }
       }
-      else if (strcmp(keyword + 7, option->keyword) == 0)
-        strlcpy(option->defchoice, string, sizeof(option->defchoice));
     }
     else if (strcmp(keyword, "UIConstraints") == 0 ||
              strcmp(keyword, "NonUIConstraints") == 0)
     {
       if (ppd->num_consts == 0)
-       constraint = calloc(sizeof(ppd_const_t), 1);
+       constraint = calloc(1, sizeof(ppd_const_t));
       else
        constraint = realloc(ppd->consts,
                             (ppd->num_consts + 1) * sizeof(ppd_const_t));
 
-      if (constraint == NULL)
-      {
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
+      if (constraint == NULL)
+      {
         ppd_status = PPD_ALLOC_ERROR;
 
-       return (NULL);
+       goto error;
       }
 
       ppd->consts = constraint;
@@ -1416,10 +1382,8 @@ ppdOpen(FILE *fp)                        /* I - File to read from */
       {
         case 0 : /* Error */
        case 1 : /* Error */
-           ppdClose(ppd);
-           ppd_free(string);
            ppd_status = PPD_BAD_UI_CONSTRAINTS;
-           return (NULL);
+           goto error;
 
        case 2 : /* Two options... */
           /*
@@ -1428,12 +1392,12 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
            */
 
            if (constraint->option1[0] == '*')
-             strcpy(constraint->option1, constraint->option1 + 1);
+             cups_strcpy(constraint->option1, constraint->option1 + 1);
 
            if (constraint->choice1[0] == '*')
-             strcpy(constraint->option2, constraint->choice1 + 1);
+             cups_strcpy(constraint->option2, constraint->choice1 + 1);
            else
-             strcpy(constraint->option2, constraint->choice1);
+             cups_strcpy(constraint->option2, constraint->choice1);
 
             constraint->choice1[0] = '\0';
             constraint->choice2[0] = '\0';
@@ -1441,23 +1405,23 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
            
        case 3 : /* Two options, one choice... */
           /*
-           * The following strcpy's are safe, as optionN and
+           * The following cups_strcpy's are safe, as optionN and
            * choiceN are all the same size (size defined by PPD spec...)
            */
 
            if (constraint->option1[0] == '*')
-             strcpy(constraint->option1, constraint->option1 + 1);
+             cups_strcpy(constraint->option1, constraint->option1 + 1);
 
            if (constraint->choice1[0] == '*')
            {
-             strcpy(constraint->choice2, constraint->option2);
-             strcpy(constraint->option2, constraint->choice1 + 1);
+             cups_strcpy(constraint->choice2, constraint->option2);
+             cups_strcpy(constraint->option2, constraint->choice1 + 1);
               constraint->choice1[0] = '\0';
            }
            else
            {
              if (constraint->option2[0] == '*')
-               strcpy(constraint->option2, constraint->option2 + 1);
+               cups_strcpy(constraint->option2, constraint->option2 + 1);
 
               constraint->choice2[0] = '\0';
            }
@@ -1465,12 +1429,15 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
            
        case 4 : /* Two options, two choices... */
            if (constraint->option1[0] == '*')
-             strcpy(constraint->option1, constraint->option1 + 1);
+             cups_strcpy(constraint->option1, constraint->option1 + 1);
 
            if (constraint->option2[0] == '*')
-             strcpy(constraint->option2, constraint->option2 + 1);
+             cups_strcpy(constraint->option2, constraint->option2 + 1);
            break;
       }
+
+      ppd_free(string);
+      string = NULL;
     }
     else if (strcmp(keyword, "PaperDimension") == 0)
     {
@@ -1483,24 +1450,15 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
         * Unable to add or find size!
        */
 
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
         ppd_status = PPD_ALLOC_ERROR;
 
-       return (NULL);
+       goto error;
       }
 
       sscanf(string, "%f%f", &(size->width), &(size->length));
+
+      ppd_free(string);
+      string = NULL;
     }
     else if (strcmp(keyword, "ImageableArea") == 0)
     {
@@ -1513,25 +1471,16 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
         * Unable to add or find size!
        */
 
-        ppdClose(ppd);
-
-       ppd_free(string);
-
-        cupsLangFree(language);
-
-#ifdef LC_NUMERIC
-        setlocale(LC_NUMERIC, oldlocale);
-#else
-        setlocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
         ppd_status = PPD_ALLOC_ERROR;
 
-       return (NULL);
+       goto error;
       }
 
       sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom),
             &(size->right), &(size->top));
+
+      ppd_free(string);
+      string = NULL;
     }
     else if (option != NULL &&
              (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
@@ -1572,8 +1521,9 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
         ppd_decode(string);            /* Decode quoted string */
 
       choice->code = string;
-      string = NULL;                   /* Don't free this string below */
+      string       = NULL;             /* Don't add as an attribute below */
     }
+#if 0
     else if (strcmp(keyword, "cupsUIType") == 0 &&
              (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING) &&
             option != NULL)
@@ -1582,7 +1532,7 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
       * Define an extended option value type...
       */
 
-      extopt = ppd_get_extopt(ppd, name);
+      extopt = ppd_get_extoption(ppd, name);
 
       if (strcmp(string, "Text") == 0)
         option->ui = PPD_UI_CUPS_TEXT;
@@ -1643,7 +1593,7 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
       * Define an extended option minimum value...
       */
 
-      extopt = ppd_get_extopt(ppd, name);
+      extopt = ppd_get_extoption(ppd, name);
 
       switch (option->ui)
       {
@@ -1689,7 +1639,7 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
       * Define an extended option minimum value...
       */
 
-      extopt = ppd_get_extopt(ppd, name);
+      extopt = ppd_get_extoption(ppd, name);
 
       switch (option->ui)
       {
@@ -1735,7 +1685,7 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
       * Define an extended option maximum value...
       */
 
-      extopt = ppd_get_extopt(ppd, name);
+      extopt = ppd_get_extoption(ppd, name);
 
       switch (option->ui)
       {
@@ -1781,23 +1731,24 @@ ppdOpen(FILE *fp)                       /* I - File to read from */
       * Define an extended option command...
       */
 
-      extopt = ppd_get_extopt(ppd, name);
+      extopt = ppd_get_extoption(ppd, name);
 
       extopt->command = string;
       string = NULL;
     }
-    else if (strcmp(keyword, "OpenSubGroup") != 0 &&
-             strcmp(keyword, "CloseSubGroup") != 0)
-    {
-      char     spec[PPD_MAX_NAME + PPD_MAX_TEXT];
+#endif /* 0 */
 
-      snprintf(spec, sizeof(spec), "%s/%s", name, text);
-      ppd_add_attr(ppd, keyword, spec, string);
+   /*
+    * Add remaining lines with keywords and string values as attributes...
+    */
 
-      string = NULL;                   /* Don't free this string below */
+    if (string &&
+        (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
+      ppd_add_attr(ppd, keyword, name, text, string);
+    else
+    {
+      ppd_free(string);
     }
-
-    ppd_free(string);
   }
 
  /*
@@ -1807,9 +1758,9 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
   cupsLangFree(language);
 
 #ifdef LC_NUMERIC
-  setlocale(LC_NUMERIC, oldlocale);
+  _cupsRestoreLocale(LC_NUMERIC, oldlocale);
 #else
-  setlocale(LC_ALL, oldlocale);
+  _cupsRestoreLocale(LC_ALL, oldlocale);
 #endif /* LC_NUMERIC */
 
 #ifdef DEBUG
@@ -1817,6 +1768,17 @@ ppdOpen(FILE *fp)                        /* I - File to read from */
     printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
 #endif /* DEBUG */
 
+  if (ppd_status != PPD_OK)
+  {
+   /*
+    * Had an error reading the PPD file, cannot continue!
+    */
+
+    ppdClose(ppd);
+
+    return (NULL);
+  }
+
 #ifndef __APPLE__
  /*
   * Make sure that all PPD files with an InputSlot option have an
@@ -1826,7 +1788,8 @@ ppdOpen(FILE *fp)                 /* I - File to read from */
   if ((option = ppdFindOption(ppd, "InputSlot")) != NULL)
   {
     for (i = 0; i < option->num_choices; i ++)
-      if (option->choices[i].code == NULL || !option->choices[i].code[0])
+      if (option->choices[i].code == NULL || !option->choices[i].code[0] ||
+          !strncasecmp(option->choices[i].choice, "Auto", 4))
        break;
 
     if (i >= option->num_choices)
@@ -1914,6 +1877,26 @@ ppdOpen(FILE *fp)                        /* I - File to read from */
   */
 
   return (ppd);
+
+ /*
+  * Common exit point for errors to save code size...
+  */
+
+  error:
+
+  ppd_free(string);
+
+  ppdClose(ppd);
+
+  cupsLangFree(language);
+
+#ifdef LC_NUMERIC
+  _cupsRestoreLocale(LC_NUMERIC, oldlocale);
+#else
+  _cupsRestoreLocale(LC_ALL, oldlocale);
+#endif /* LC_NUMERIC */
+
+  return (NULL);
 }
 
 
@@ -2015,6 +1998,17 @@ ppdOpenFile(const char *filename)        /* I - File to read from */
 }
 
 
+/*
+ * 'ppdSetConformance()' - Set the conformance level for PPD files.
+ */
+
+void
+ppdSetConformance(ppd_conform_t c)     /* I - Conformance level */
+{
+  ppd_conform = c;
+}
+
+
 /*
  * 'ppd_add_attr()' - Add an attribute to the PPD data.
  */
@@ -2023,6 +2017,7 @@ static ppd_attr_t *                       /* O - New attribute */
 ppd_add_attr(ppd_file_t *ppd,          /* I - PPD file data */
              const char *name,         /* I - Attribute name */
              const char *spec,         /* I - Specifier string, if any */
+            const char *text,          /* I - Text string, if any */
             const char *value)         /* I - Value of attribute */
 {
   ppd_attr_t   **ptr,                  /* New array */
@@ -2064,6 +2059,7 @@ ppd_add_attr(ppd_file_t *ppd,             /* I - PPD file data */
 
   strlcpy(temp->name, name, sizeof(temp->name));
   strlcpy(temp->spec, spec, sizeof(temp->spec));
+  strlcpy(temp->text, text, sizeof(temp->text));
   temp->value = (char *)value;
 
  /*
@@ -2165,7 +2161,7 @@ ppd_compare_options(ppd_option_t *o0,     /* I - First option */
  * 'ppd_decode()' - Decode a string value...
  */
 
-static void
+static int                             /* O - Length of decoded string */
 ppd_decode(char *string)               /* I - String to decode */
 {
   char *inptr,                         /* Input pointer */
@@ -2176,14 +2172,14 @@ ppd_decode(char *string)                /* I - String to decode */
   outptr = string;
 
   while (*inptr != '\0')
-    if (*inptr == '<' && isxdigit(inptr[1]))
+    if (*inptr == '<' && isxdigit(inptr[1] & 255))
     {
      /*
       * Convert hex to 8-bit values...
       */
 
       inptr ++;
-      while (isxdigit(*inptr))
+      while (isxdigit(*inptr & 255))
       {
        if (isalpha(*inptr))
          *outptr = (tolower(*inptr) - 'a' + 10) << 4;
@@ -2192,6 +2188,9 @@ ppd_decode(char *string)          /* I - String to decode */
 
        inptr ++;
 
+        if (!isxdigit(*inptr & 255))
+         break;
+
        if (isalpha(*inptr))
          *outptr |= tolower(*inptr) - 'a' + 10;
        else
@@ -2210,6 +2209,8 @@ ppd_decode(char *string)          /* I - String to decode */
       *outptr++ = *inptr++;
 
   *outptr = '\0';
+
+  return (outptr - string);
 }
 
 
@@ -2317,7 +2318,9 @@ ppd_free_option(ppd_option_t *option)     /* I - Option to free */
     for (i = option->num_choices, choice = option->choices;
          i > 0;
          i --, choice ++)
+    {
       ppd_free(choice->code);
+    }
 
     ppd_free(option->choices);
   }
@@ -2325,12 +2328,12 @@ ppd_free_option(ppd_option_t *option)   /* I - Option to free */
 
 
 /*
- * 'ppd_get_extopt()' - Get an extended option record.
+ * 'ppd_get_extoption()' - Get an extended option record.
  */
 
 static ppd_ext_option_t        *               /* O - Extended option... */
-ppd_get_extopt(ppd_file_t *ppd,                /* I - PPD file */
-               const char *name)       /* I - Name of option */
+ppd_get_extoption(ppd_file_t *ppd,     /* I - PPD file */
+                  const char *name)    /* I - Name of option */
 {
   ppd_ext_option_t     **temp,         /* New array pointer */
                        *extopt;        /* New extended option */
@@ -2347,7 +2350,7 @@ ppd_get_extopt(ppd_file_t *ppd,           /* I - PPD file */
   * Not found, so create the extended option record...
   */
 
-  if ((extopt = calloc(sizeof(ppd_ext_option_t), 1)) == NULL)
+  if ((extopt = calloc(1, sizeof(ppd_ext_option_t))) == NULL)
     return (NULL);
 
   strlcpy(extopt->keyword, name, sizeof(extopt->keyword));
@@ -2381,6 +2384,75 @@ ppd_get_extopt(ppd_file_t *ppd,          /* I - PPD file */
 }
 
 
+/*
+ * 'ppd_get_extparam()' - Get an extended parameter record.
+ */
+
+static ppd_ext_param_t *               /* O - Extended option... */
+ppd_get_extparam(ppd_ext_option_t *opt,        /* I - PPD file */
+                 const char      *param,/* I - Name of parameter */
+                const char      *text) /* I - Human-readable text */
+{
+  ppd_ext_param_t      **temp,         /* New array pointer */
+                       *extparam;      /* New extended parameter */
+
+
+ /*
+  * See if the parameter already exists...
+  */
+
+  if ((extparam = ppdFindExtParam(opt, param)) != NULL)
+    return (extparam);
+
+ /*
+  * Not found, so create the extended parameter record...
+  */
+
+  if ((extparam = calloc(1, sizeof(ppd_ext_param_t))) == NULL)
+    return (NULL);
+
+  if ((extparam->value = calloc(4, sizeof(ppd_ext_value_t))) == NULL)
+  {
+    ppd_free(extparam);
+    return (NULL);
+  }
+
+  extparam->defval = extparam->value + 1;
+  extparam->minval = extparam->value + 2;
+  extparam->maxval = extparam->value + 3;
+
+  strlcpy(extparam->keyword, param, sizeof(extparam->keyword));
+  strlcpy(extparam->text, text, sizeof(extparam->text));
+
+ /*
+  * Add this record to the end of the array...
+  */
+
+  if (opt->num_params == 0)
+    temp = malloc(sizeof(ppd_ext_param_t *));
+  else
+    temp = realloc(opt->params, sizeof(ppd_ext_param_t *) *
+                                       (opt->num_params + 1));
+
+  if (temp == NULL)
+  {
+    free(extparam);
+    return (NULL);
+  }
+
+  opt->params           = temp;
+  temp[opt->num_params] = extparam;
+
+  opt->num_params ++;
+
+ /*
+  * Return the new record...
+  */
+
+  return (extparam);
+}
+
+
 /*
  * 'ppd_get_group()' - Find or create the named group as needed.
  */
@@ -2404,6 +2476,13 @@ ppd_get_group(ppd_file_t *ppd,           /* I - PPD file */
   {
     DEBUG_printf(("Adding group %s...\n", name));
 
+    if (ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
+    {
+      ppd_status = PPD_ILLEGAL_TRANSLATION;
+
+      return (NULL);
+    }
+           
     if (ppd->num_groups == 0)
       group = malloc(sizeof(ppd_group_t));
     else
@@ -2411,7 +2490,11 @@ ppd_get_group(ppd_file_t *ppd,           /* I - PPD file */
                      (ppd->num_groups + 1) * sizeof(ppd_group_t));
 
     if (group == NULL)
+    {
+      ppd_status = PPD_ALLOC_ERROR;
+
       return (NULL);
+    }
 
     ppd->groups = group;
     group += ppd->num_groups;
@@ -2438,6 +2521,9 @@ ppd_get_option(ppd_group_t *group,        /* I - Group */
   ppd_option_t *option;                /* Option */
 
 
+  DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
+                group, group->name, name));
+
   for (i = group->num_options, option = group->options; i > 0; i --, option ++)
     if (strcmp(option->keyword, name) == 0)
       break;
@@ -2475,12 +2561,16 @@ ppd_read(FILE *fp,                      /* I - File to read from */
          char *keyword,                        /* O - Keyword from line */
         char *option,                  /* O - Option from line */
          char *text,                   /* O - Human-readable text from line */
-        char **string)                 /* O - Code/string data */
+        char **string,                 /* O - Code/string data */
+         int  ignoreblank)             /* I - Ignore blank lines? */
 {
   int          ch,                     /* Character from file */
+               col,                    /* Column in line */
                colon,                  /* Colon seen? */
                endquote,               /* Waiting for an end quote */
-               mask;                   /* Mask to be returned */
+               mask,                   /* Mask to be returned */
+               startline,              /* Start line */
+               textlen;                /* Length of text */
   char         *keyptr,                /* Keyword pointer */
                *optptr,                /* Option pointer */
                *textptr,               /* Text pointer */
@@ -2501,7 +2591,9 @@ ppd_read(FILE *fp,                        /* I - File to read from */
   * Now loop until we have a valid line...
   */
 
-  *string = NULL;
+  *string   = NULL;
+  col       = 0;
+  startline = ppd_line + 1;
 
   do
   {
@@ -2523,9 +2615,7 @@ ppd_read(FILE *fp,                        /* I - File to read from */
        */
 
         ppd_line ++;
-
-       if (lineptr == line)            /* Skip blank lines */
-          continue;
+       col = 0;
 
        if (ch == '\r')
        {
@@ -2539,6 +2629,9 @@ ppd_read(FILE *fp,                        /* I - File to read from */
            ungetc(ch, fp);
        }
 
+       if (lineptr == line && ignoreblank)
+          continue;                    /* Skip blank lines */
+
        ch = '\n';
 
        if (!endquote)                  /* Continue for multi-line text */
@@ -2546,47 +2639,43 @@ ppd_read(FILE *fp,                      /* I - File to read from */
 
        *lineptr++ = '\n';
       }
-      else
+      else if (ch < ' ' && ch != '\t' && ppd_conform == PPD_CONFORM_STRICT)
+      {
+       /*
+        * Other control characters...
+       */
+
+        ppd_line   = startline;
+        ppd_status = PPD_ILLEGAL_CHARACTER;
+
+        return (0);
+      }
+      else if (ch != 0x1a)
       {
        /*
        * Any other character...
        */
 
        *lineptr++ = ch;
+       col ++;
+
+       if (col > (PPD_MAX_LINE - 1))
+       {
+        /*
+          * Line is too long...
+         */
+
+          ppd_line   = startline;
+          ppd_status = PPD_LINE_TOO_LONG;
+
+          return (0);
+       }
 
        if (ch == ':' && strncmp(line, "*%", 2) != 0)
          colon = 1;
 
        if (ch == '\"' && colon)
-        {
          endquote = !endquote;
-
-          if (!endquote)
-         {
-          /*
-           * End of quoted string; ignore trailing characters...
-           */
-
-           while ((ch = getc(fp)) != EOF)
-             if (ch == '\r' || ch == '\n')
-             {
-                ppd_line ++;
-
-               if (ch == '\r')
-               {
-                 ch = getc(fp);
-                 if (ch != '\n')
-                   ungetc(ch, fp);
-
-                 ch = '\n';
-               }
-
-               break;
-             }
-
-            break;
-         }
-       }
       }
     }
 
@@ -2599,6 +2688,52 @@ ppd_read(FILE *fp,                       /* I - File to read from */
       while ((ch = getc(fp)) != EOF)
         if (ch == '\"')
          break;
+       else if (ch == '\r' || ch == '\n')
+       {
+         ppd_line ++;
+         col = 0;
+
+         if (ch == '\r')
+         {
+          /*
+            * Check for a trailing line feed...
+           */
+
+           if ((ch = getc(fp)) == EOF)
+             break;
+           if (ch != 0x0a)
+             ungetc(ch, fp);
+         }
+
+         ch = '\n';
+       }
+       else if (ch < ' ' && ch != '\t' && ppd_conform == PPD_CONFORM_STRICT)
+       {
+        /*
+          * Other control characters...
+         */
+
+          ppd_line   = startline;
+          ppd_status = PPD_ILLEGAL_CHARACTER;
+
+          return (0);
+       }
+       else if (ch != 0x1a)
+       {
+         col ++;
+
+         if (col > (PPD_MAX_LINE - 1))
+         {
+          /*
+            * Line is too long...
+           */
+
+            ppd_line   = startline;
+            ppd_status = PPD_LINE_TOO_LONG;
+
+            return (0);
+         }
+       }
     }
 
     if (ch != '\n')
@@ -2615,6 +2750,7 @@ ppd_read(FILE *fp,                        /* I - File to read from */
          */
 
           ppd_line ++;
+         col = 0;
 
          if (ch == '\r')
          {
@@ -2630,6 +2766,32 @@ ppd_read(FILE *fp,                       /* I - File to read from */
 
          break;
        }
+       else if (ch < ' ' && ch != '\t' && ppd_conform == PPD_CONFORM_STRICT)
+       {
+        /*
+          * Other control characters...
+         */
+
+          ppd_line   = startline;
+          ppd_status = PPD_ILLEGAL_CHARACTER;
+
+          return (0);
+       }
+       else if (ch != 0x1a)
+       {
+         col ++;
+
+         if (col > (PPD_MAX_LINE - 1))
+         {
+          /*
+            * Line is too long...
+           */
+
+            ppd_status = PPD_LINE_TOO_LONG;
+
+            return (0);
+         }
+       }
     }
 
     if (lineptr > line && lineptr[-1] == '\n')
@@ -2637,7 +2799,7 @@ ppd_read(FILE *fp,                        /* I - File to read from */
 
     *lineptr = '\0';
 
-/*    DEBUG_printf(("LINE = \"%s\"\n", line));*/
+    DEBUG_printf(("LINE = \"%s\"\n", line));
 
     if (ch == EOF && lineptr == line)
       return (0);
@@ -2654,14 +2816,57 @@ ppd_read(FILE *fp,                      /* I - File to read from */
     text[0]    = '\0';
     *string    = NULL;
 
-    if (line[0] != '*')                        /* All lines start with an asterisk */
+    if ((!line[0] ||                   /* Blank line */
+         strncmp(line, "*%", 2) == 0 ||        /* Comment line */
+         strcmp(line, "*End") == 0) && /* End of multi-line string */
+        ignoreblank)                   /* Ignore these? */
+    {
+      startline = ppd_line + 1;
       continue;
+    }
 
-    if (strcmp(line, "*") == 0 ||      /* (Bad) comment line */
-        strncmp(line, "*%", 2) == 0 || /* Comment line */
-        strncmp(line, "*?", 2) == 0 || /* Query line */
-        strcmp(line, "*End") == 0)     /* End of multi-line string */
-      continue;
+    if (strcmp(line, "*") == 0)                /* (Bad) comment line */
+    {
+      if (ppd_conform == PPD_CONFORM_RELAXED)
+      {
+       startline = ppd_line + 1;
+       continue;
+      }
+      else
+      {
+        ppd_line   = startline;
+        ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
+
+        return (0);
+      }
+    }
+
+    if (line[0] != '*')                        /* All lines start with an asterisk */
+    {
+      if (ppd_conform == PPD_CONFORM_STRICT)
+      {
+        ppd_status = PPD_MISSING_ASTERISK;
+        return (0);
+      }
+
+     /*
+      * Allow lines consisting of just whitespace...
+      */
+
+      for (lineptr = line; *lineptr; lineptr ++)
+        if (!isspace(*lineptr & 255))
+         break;
+
+      if (*lineptr)
+      {
+        ppd_status = PPD_MISSING_ASTERISK;
+        return (0);
+      }
+      else if (ignoreblank)
+        continue;
+      else
+        return (0);
+    }
 
    /*
     * Get a keyword...
@@ -2669,10 +2874,17 @@ ppd_read(FILE *fp,                      /* I - File to read from */
 
     keyptr = keyword;
 
-    for (; *lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr);
-         lineptr ++)
-      if ((keyptr - keyword) < (PPD_MAX_NAME - 1))
-       *keyptr++ = *lineptr;
+    while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
+    {
+      if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
+          (keyptr - keyword) >= (PPD_MAX_NAME - 1))
+      {
+        ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
+       return (0);
+      }
+
+      *keyptr++ = *lineptr++;
+    }
 
     *keyptr = '\0';
 
@@ -2683,23 +2895,41 @@ ppd_read(FILE *fp,                      /* I - File to read from */
 
 /*    DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
 
-    if (isspace(*lineptr))
+    if (isspace(*lineptr & 255))
     {
      /*
       * Get an option name...
       */
 
-      while (isspace(*lineptr))
+      while (isspace(*lineptr & 255))
         lineptr ++;
 
       optptr = option;
 
-      for (; *lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
-             *lineptr != '/'; lineptr ++)
-        if ((optptr - option) < (PPD_MAX_NAME - 1))
-         *optptr++ = *lineptr;
+      while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
+             *lineptr != '/')
+      {
+       if (*lineptr <= ' ' || *lineptr > 126 ||
+           (optptr - option) >= (PPD_MAX_NAME - 1))
+        {
+          ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
+         return (0);
+       }
+
+        *optptr++ = *lineptr++;
+      }
 
       *optptr = '\0';
+
+      if (isspace(*lineptr & 255) && ppd_conform == PPD_CONFORM_STRICT)
+      {
+        ppd_status = PPD_ILLEGAL_WHITESPACE;
+       return (0);
+      }
+
+      while (isspace(*lineptr & 255))
+       lineptr ++;
+
       mask |= PPD_OPTION;
 
 /*      DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
@@ -2714,38 +2944,74 @@ ppd_read(FILE *fp,                      /* I - File to read from */
        
        textptr = text;
 
-       for (; *lineptr != '\0' && *lineptr != '\n' && *lineptr != ':';
-            lineptr ++)
-         if ((textptr - text) < (PPD_MAX_LINE - 1))
-           *textptr++ = *lineptr;
+       while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
+       {
+         if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
+             (textptr - text) >= (PPD_MAX_LINE - 1))
+         {
+           ppd_status = PPD_ILLEGAL_TRANSLATION;
+           return (0);
+         }
+
+         *textptr++ = *lineptr++;
+        }
 
        *textptr = '\0';
-       ppd_decode(text);
+       textlen  = ppd_decode(text);
 
+       if (textlen > PPD_MAX_TEXT && ppd_conform == PPD_CONFORM_STRICT)
+       {
+         ppd_status = PPD_ILLEGAL_TRANSLATION;
+         return (0);
+       }
+           
        mask |= PPD_TEXT;
       }
 
 /*      DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
     }
 
+    if (isspace(*lineptr & 255) && ppd_conform == PPD_CONFORM_STRICT)
+    {
+      ppd_status = PPD_ILLEGAL_WHITESPACE;
+      return (0);
+    }
+
+    while (isspace(*lineptr & 255))
+      lineptr ++;
+
     if (*lineptr == ':')
     {
      /*
-      * Get string...
+      * Get string after triming leading and trailing whitespace...
       */
 
-      *string = malloc(strlen(lineptr) + 1);
-
-      while (*lineptr == ':' || isspace(*lineptr))
+      lineptr ++;
+      while (isspace(*lineptr & 255))
         lineptr ++;
 
-      strptr = *string;
+      strptr = lineptr + strlen(lineptr) - 1;
+      while (strptr >= lineptr && isspace(*strptr & 255))
+        *strptr-- = '\0';
 
-      for (; *lineptr != '\0'; lineptr ++)
-       if (*lineptr != '\"')
-         *strptr++ = *lineptr;
+      if (*strptr == '\"')
+      {
+       /*
+        * Quoted string by itself...
+       */
+
+       *string = malloc(strlen(lineptr) + 1);
 
-      *strptr = '\0';
+       strptr = *string;
+
+       for (; *lineptr != '\0'; lineptr ++)
+         if (*lineptr != '\"')
+           *strptr++ = *lineptr;
+
+       *strptr = '\0';
+      }
+      else
+        *string = strdup(lineptr);
 
 /*      DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
 
@@ -2759,5 +3025,5 @@ ppd_read(FILE *fp,                        /* I - File to read from */
 
 
 /*
- * End of "$Id: ppd.c,v 1.51.2.33 2003/02/14 03:05:48 mike Exp $".
+ * End of "$Id: ppd.c,v 1.51.2.64 2004/06/29 03:46:29 mike Exp $".
  */