]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/ppd.c
Import CUPS 1.4svn r7023 into easysw/current.
[thirdparty/cups.git] / cups / ppd.c
index 37d0f8d6b5fa0bbd0c982d577efa5a27c43778c0..a2a7ef1a90fb632ab1f20211f0bbe9f1b6d53a33 100644 (file)
@@ -1,25 +1,16 @@
 /*
- * "$Id: ppd.c 6188 2007-01-10 16:23:06Z mike $"
+ * "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $"
  *
  *   PPD file routines for the Common UNIX Printing System (CUPS).
  *
+ *   Copyright 2007 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  *   PostScript is a trademark of Adobe Systems, Inc.
  *
@@ -48,6 +39,8 @@
  *   ppd_add_choice()       - Add a choice to an option.
  *   ppd_add_size()         - Add a page size.
  *   ppd_compare_attrs()    - Compare two attributes.
+ *   ppd_compare_choices()  - Compare two choices...
+ *   ppd_compare_consts()   - Compare two constraints.
  *   ppd_compare_coptions() - Compare two custom options.
  *   ppd_compare_cparams()  - Compare two custom parameters.
  *   ppd_compare_options()  - Compare two options.
@@ -58,6 +51,7 @@
  *   ppd_get_cparam()       - Get a custom 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_hash_option()      - Generate a hash of the option name...
  *   ppd_read()             - Read a line from a PPD file, skipping comment
  *                            lines as necessary.
  */
 #define PPD_TEXT       4               /* Line contained human-readable text */
 #define PPD_STRING     8               /* Line contained a string or code */
 
+#define PPD_HASHSIZE   512             /* Size of hash */
+
+
+/*
+ * Line buffer structure...
+ */
+
+typedef struct _ppd_line_s
+{
+  char         *buffer;                /* Pointer to buffer */
+  size_t       bufsize;                /* Size of the buffer */
+} _ppd_line_t;
+
 
 /*
  * Local functions...
@@ -101,6 +108,8 @@ static ppd_attr_t   *ppd_add_attr(ppd_file_t *ppd, const char *name,
 static ppd_choice_t    *ppd_add_choice(ppd_option_t *option, const char *name);
 static ppd_size_t      *ppd_add_size(ppd_file_t *ppd, const char *name);
 static int             ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
+static int             ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
+static int             ppd_compare_consts(ppd_const_t *a, ppd_const_t *b);
 static int             ppd_compare_coptions(ppd_coption_t *a,
                                             ppd_coption_t *b);
 static int             ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
@@ -116,8 +125,10 @@ static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
                                       const char *text, _cups_globals_t *cg,
                                       cups_encoding_t encoding);
 static ppd_option_t    *ppd_get_option(ppd_group_t *group, const char *name);
-static int             ppd_read(cups_file_t *fp, char *keyword, char *option,
-                                char *text, char **string, int ignoreblank,
+static int             ppd_hash_option(ppd_option_t *option);
+static int             ppd_read(cups_file_t *fp, _ppd_line_t *line,
+                                char *keyword, char *option, char *text,
+                                char **string, int ignoreblank,
                                 _cups_globals_t *cg);
 
 
@@ -149,12 +160,12 @@ ppdClose(ppd_file_t *ppd)         /* I - PPD file record */
   * Free all strings at the top level...
   */
 
-  ppd_free(ppd->lang_encoding);
-  ppd_free(ppd->nickname);
-  ppd_free(ppd->patches);
-  ppd_free(ppd->jcl_begin);
-  ppd_free(ppd->jcl_end);
-  ppd_free(ppd->jcl_ps);
+  _cupsStrFree(ppd->lang_encoding);
+  _cupsStrFree(ppd->nickname);
+  _cupsStrFree(ppd->patches);
+  _cupsStrFree(ppd->jcl_begin);
+  _cupsStrFree(ppd->jcl_end);
+  _cupsStrFree(ppd->jcl_ps);
 
  /*
   * Free any emulations...
@@ -164,8 +175,8 @@ ppdClose(ppd_file_t *ppd)           /* I - PPD file record */
   {
     for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
     {
-      ppd_free(emul->start);
-      ppd_free(emul->stop);
+      _cupsStrFree(emul->start);
+      _cupsStrFree(emul->stop);
     }
 
     ppd_free(ppd->emulations);
@@ -184,6 +195,7 @@ ppdClose(ppd_file_t *ppd)           /* I - PPD file record */
   }
 
   cupsArrayDelete(ppd->options);
+  cupsArrayDelete(ppd->marked);
 
  /*
   * Free any page sizes...
@@ -206,9 +218,7 @@ 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);
-    }
+      _cupsStrFree(*filter);
 
     ppd_free(ppd->filters);
   }
@@ -220,9 +230,7 @@ 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);
-    }
+      _cupsStrFree(*font);
 
     ppd_free(ppd->fonts);
   }
@@ -242,7 +250,7 @@ ppdClose(ppd_file_t *ppd)           /* I - PPD file record */
   {
     for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
     {
-      ppd_free((*attr)->value);
+      _cupsStrFree((*attr)->value);
       ppd_free(*attr);
     }
 
@@ -268,7 +276,7 @@ ppdClose(ppd_file_t *ppd)           /* I - PPD file record */
         case PPD_CUSTOM_PASSCODE :
         case PPD_CUSTOM_PASSWORD :
         case PPD_CUSTOM_STRING :
-            ppd_free(cparam->current.custom_string);
+            _cupsStrFree(cparam->current.custom_string);
            break;
 
        default :
@@ -425,6 +433,7 @@ ppdOpen2(cups_file_t *fp)           /* I - File to read from */
 {
   int                  i, j, k;        /* Looping vars */
   int                  count;          /* Temporary count */
+  _ppd_line_t          line;           /* Line buffer */
   ppd_file_t           *ppd;           /* PPD file record */
   ppd_group_t          *group,         /* Current group */
                        *subgroup;      /* Current sub-group */
@@ -538,7 +547,10 @@ ppdOpen2(cups_file_t *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, 0, cg);
+  line.buffer  = NULL;
+  line.bufsize = 0;
+
+  mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
 
   DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask, keyword));
 
@@ -553,14 +565,14 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
     if (cg->ppd_status == PPD_OK)
       cg->ppd_status = PPD_MISSING_PPDADOBE4;
 
-    ppd_free(string);
+    _cupsStrFree(string);
 
     return (NULL);
   }
 
   DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
 
-  ppd_free(string);
+  _cupsStrFree(string);
 
  /*
   * Allocate memory for the PPD file record...
@@ -573,7 +585,7 @@ ppdOpen2(cups_file_t *fp)           /* I - File to read from */
     return (NULL);
   }
 
-  ppd->language_level = 1;
+  ppd->language_level = 2;
   ppd->color_device   = 0;
   ppd->colorspace     = PPD_CS_GRAY;
   ppd->landscape      = -90;
@@ -598,7 +610,7 @@ ppdOpen2(cups_file_t *fp)           /* I - File to read from */
   ui_keyword = 0;
   encoding   = CUPS_ISO8859_1;
 
-  while ((mask = ppd_read(fp, keyword, name, text, &string, 1, cg)) != 0)
+  while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
   {
 #ifdef DEBUG
     printf("mask = %x, keyword = \"%s\"", mask, keyword);
@@ -744,7 +756,7 @@ ppdOpen2(cups_file_t *fp)           /* I - File to read from */
       * Say all PPD files are UTF-8, since we convert to UTF-8...
       */
 
-      ppd->lang_encoding = strdup("UTF-8");
+      ppd->lang_encoding = _cupsStrAlloc("UTF-8");
       encoding           = _ppdGetEncoding(string);
     }
     else if (!strcmp(keyword, "LanguageVersion"))
@@ -765,10 +777,10 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
 
 
         cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
-       ppd->nickname = strdup((char *)utf8);
+       ppd->nickname = _cupsStrAlloc((char *)utf8);
       }
       else
-        ppd->nickname = strdup(string);
+        ppd->nickname = _cupsStrAlloc(string);
     }
     else if (!strcmp(keyword, "Product"))
       ppd->product = string;
@@ -778,17 +790,17 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
       ppd->ttrasterizer = string;
     else if (!strcmp(keyword, "JCLBegin"))
     {
-      ppd->jcl_begin = strdup(string);
+      ppd->jcl_begin = _cupsStrAlloc(string);
       ppd_decode(ppd->jcl_begin);      /* Decode quoted string */
     }
     else if (!strcmp(keyword, "JCLEnd"))
     {
-      ppd->jcl_end = strdup(string);
+      ppd->jcl_end = _cupsStrAlloc(string);
       ppd_decode(ppd->jcl_end);                /* Decode quoted string */
     }
     else if (!strcmp(keyword, "JCLToPSInterpreter"))
     {
-      ppd->jcl_ps = strdup(string);
+      ppd->jcl_ps = _cupsStrAlloc(string);
       ppd_decode(ppd->jcl_ps);         /* Decode quoted string */
     }
     else if (!strcmp(keyword, "AccurateScreensSupport"))
@@ -840,8 +852,6 @@ ppdOpen2(cups_file_t *fp)           /* I - File to read from */
 
       if (filter == NULL)
       {
-        ppd_free(filter);
-
         cg->ppd_status = PPD_ALLOC_ERROR;
 
        goto error;
@@ -880,7 +890,7 @@ ppdOpen2(cups_file_t *fp)           /* I - File to read from */
       }
       
       ppd->fonts                 = tempfonts;
-      ppd->fonts[ppd->num_fonts] = strdup(name);
+      ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
       ppd->num_fonts ++;
     }
     else if (!strncmp(keyword, "ParamCustom", 11))
@@ -1003,7 +1013,7 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
       for (i = 0, sptr = string; i < 4; i ++)
         ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
     }
-    else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True"))
+    else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
     {
       DEBUG_puts("Processing Custom option...");
 
@@ -1013,11 +1023,15 @@ ppdOpen2(cups_file_t *fp)               /* I - File to read from */
 
       if ((option = ppdFindOption(ppd, keyword + 6)) == NULL)
       {
+        int            groupidx = -1;  /* Index for current group */
        ppd_group_t     *gtemp;         /* Temporary group */
 
 
         DEBUG_printf(("%s option not found for %s...\n", keyword + 6, keyword));
 
+        if (group)
+          groupidx = group - ppd->groups; /* Save index for current group */
+
        if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg,
                                   encoding)) == NULL)
        {
@@ -1026,6 +1040,9 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
          goto error;
        }
 
+        if (group)
+          group = ppd->groups + groupidx; /* Restore group pointer */
+
        if ((option = ppd_get_option(gtemp, keyword + 6)) == NULL)
        {
          DEBUG_printf(("Unable to get %s option!\n", keyword + 6));
@@ -1076,6 +1093,41 @@ ppdOpen2(cups_file_t *fp)                /* I - File to read from */
        */
 
        ppd_add_size(ppd, "Custom");
+
+       if ((option = ppdFindOption(ppd, "PageRegion")) == NULL)
+       {
+         int           groupidx = -1;  /* Index to current group */
+         ppd_group_t   *gtemp;         /* Temporary group */
+
+          if (group)
+            groupidx = group - ppd->groups; /* Save index for current group */
+
+         if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg,
+                                    encoding)) == NULL)
+         {
+           DEBUG_puts("Unable to get general group!");
+
+           goto error;
+         }
+
+          if (group)
+            group = ppd->groups + groupidx; /* Restore group pointer */
+
+         option = ppd_get_option(gtemp, "PageRegion");
+        }
+
+       if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+       {
+         DEBUG_puts("Unable to add Custom choice!");
+
+         cg->ppd_status = PPD_ALLOC_ERROR;
+
+         goto error;
+       }
+
+       strlcpy(choice->text, text[0] ? text : _("Custom"),
+               sizeof(choice->text));
+        option = NULL;
       }
     }
     else if (!strcmp(keyword, "LandscapeOrientation"))
@@ -1137,7 +1189,7 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
     else if (!strcmp(keyword, "JobPatchFile"))
     {
       if (ppd->patches == NULL)
-        ppd->patches = strdup(string);
+        ppd->patches = _cupsStrAlloc(string);
       else
       {
         temp = realloc(ppd->patches, strlen(ppd->patches) +
@@ -1171,6 +1223,8 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
       * Add an option record to the current sub-group, group, or file...
       */
 
+      DEBUG_printf(("name=\"%s\" (%d)\n", name, strlen(name)));
+
       if (name[0] == '*')
         _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
 
@@ -1254,7 +1308,7 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
 
       option->section = PPD_ORDER_ANY;
 
-      ppd_free(string);
+      _cupsStrFree(string);
       string = NULL;
     }
     else if (!strcmp(keyword, "JCLOpenUI"))
@@ -1333,14 +1387,14 @@ ppdOpen2(cups_file_t *fp)               /* I - File to read from */
       option->section = PPD_ORDER_JCL;
       group = NULL;
 
-      ppd_free(string);
+      _cupsStrFree(string);
       string = NULL;
     }
     else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
     {
       option = NULL;
 
-      ppd_free(string);
+      _cupsStrFree(string);
       string = NULL;
     }
     else if (!strcmp(keyword, "OpenGroup"))
@@ -1387,14 +1441,14 @@ ppdOpen2(cups_file_t *fp)               /* I - File to read from */
       if (group == NULL)
        goto error;
 
-      ppd_free(string);
+      _cupsStrFree(string);
       string = NULL;
     }
     else if (!strcmp(keyword, "CloseGroup"))
     {
       group = NULL;
 
-      ppd_free(string);
+      _cupsStrFree(string);
       string = NULL;
     }
     else if (!strcmp(keyword, "OrderDependency") ||
@@ -1453,7 +1507,7 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
        option->order   = order;
       }
 
-      ppd_free(string);
+      _cupsStrFree(string);
       string = NULL;
     }
     else if (!strncmp(keyword, "Default", 7))
@@ -1523,10 +1577,10 @@ ppdOpen2(cups_file_t *fp)               /* I - File to read from */
              !strcmp(keyword, "NonUIConstraints"))
     {
       if (ppd->num_consts == 0)
-       constraint = calloc(1, sizeof(ppd_const_t));
+       constraint = calloc(2, sizeof(ppd_const_t));
       else
        constraint = realloc(ppd->consts,
-                            (ppd->num_consts + 1) * sizeof(ppd_const_t));
+                            (ppd->num_consts + 2) * sizeof(ppd_const_t));
 
       if (constraint == NULL)
       {
@@ -1687,6 +1741,34 @@ ppdOpen2(cups_file_t *fp)                /* I - File to read from */
            break;
       }
 
+     /*
+      * For CustomPageSize and InputSlot/ManualFeed, create a duplicate
+      * constraint for PageRegion...
+      */
+
+      if (!strcasecmp(constraint->option1, "CustomPageSize") &&
+          (!strcasecmp(constraint->option2, "InputSlot") ||
+          !strcasecmp(constraint->option2, "ManualFeed")))
+      {
+        ppd->num_consts ++;
+
+        strcpy(constraint[1].option1, "PageRegion");
+       strcpy(constraint[1].choice1, "Custom");
+       strcpy(constraint[1].option2, constraint->option2);
+       strcpy(constraint[1].choice2, constraint->choice2);
+      }
+      else if (!strcasecmp(constraint->option2, "CustomPageSize") &&
+               (!strcasecmp(constraint->option1, "InputSlot") ||
+               !strcasecmp(constraint->option1, "ManualFeed")))
+      {
+        ppd->num_consts ++;
+
+       strcpy(constraint[1].option1, constraint->option1);
+       strcpy(constraint[1].choice1, constraint->choice1);
+        strcpy(constraint[1].option2, "PageRegion");
+       strcpy(constraint[1].choice2, "Custom");
+      }
+
      /*
       * Handle CustomFoo option constraints...
       */
@@ -1709,7 +1791,7 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
       * Don't add this one as an attribute...
       */
 
-      ppd_free(string);
+      _cupsStrFree(string);
       string = NULL;
     }
     else if (!strcmp(keyword, "PaperDimension"))
@@ -1731,7 +1813,7 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
       size->width  = (float)_cupsStrScand(string, &sptr, loc);
       size->length = (float)_cupsStrScand(sptr, NULL, loc);
 
-      ppd_free(string);
+      _cupsStrFree(string);
       string = NULL;
     }
     else if (!strcmp(keyword, "ImageableArea"))
@@ -1755,7 +1837,7 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
       size->right  = (float)_cupsStrScand(sptr, &sptr, loc);
       size->top    = (float)_cupsStrScand(sptr, NULL, loc);
 
-      ppd_free(string);
+      _cupsStrFree(string);
       string = NULL;
     }
     else if (option != NULL &&
@@ -1806,9 +1888,12 @@ ppdOpen2(cups_file_t *fp)                /* I - File to read from */
         (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
       ppd_add_attr(ppd, keyword, name, text, string);
     else
-      ppd_free(string);
+      _cupsStrFree(string);
   }
 
+  if (line.buffer)
+    free(line.buffer);
+
  /*
   * Reset language preferences...
   */
@@ -1816,8 +1901,8 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
   cupsLangFree(language);
 
 #ifdef DEBUG
-  if (!feof(fp))
-    printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
+  if (!cupsFileEOF(fp))
+    printf("Premature EOF at %lu...\n", (unsigned long)cupsFileTell(fp));
 #endif /* DEBUG */
 
   if (cg->ppd_status != PPD_OK)
@@ -1836,7 +1921,9 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
   * each choice and custom option...
   */
 
-  ppd->options = cupsArrayNew((cups_array_func_t)ppd_compare_options, NULL);
+  ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
+                               (cups_ahash_func_t)ppd_hash_option,
+                              PPD_HASHSIZE);
 
   for (i = ppd->num_groups, group = ppd->groups;
        i > 0;
@@ -1859,6 +1946,20 @@ ppdOpen2(cups_file_t *fp)                /* I - File to read from */
     }
   }
 
+ /*
+  * Sort the constraints...
+  */
+
+  if (ppd->num_consts > 1)
+    qsort(ppd->consts, ppd->num_consts, sizeof(ppd_const_t),
+          (int (*)(const void *, const void *))ppd_compare_consts);
+
+ /*
+  * Create an array to track the marked choices...
+  */
+
+  ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
+
  /*
   * Return the PPD file structure...
   */
@@ -1871,7 +1972,10 @@ ppdOpen2(cups_file_t *fp)                /* I - File to read from */
 
   error:
 
-  ppd_free(string);
+  if (line.buffer)
+    free(line.buffer);
+
+  _cupsStrFree(string);
 
   ppdClose(ppd);
 
@@ -2152,6 +2256,40 @@ ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
 }
 
 
+/*
+ * 'ppd_compare_choices()' - Compare two choices...
+ */
+
+static int                             /* O - Result of comparison */
+ppd_compare_choices(ppd_choice_t *a,   /* I - First choice */
+                    ppd_choice_t *b)   /* I - Second choice */
+{
+  return (strcmp(a->option->keyword, b->option->keyword));
+}
+
+
+/*
+ * 'ppd_compare_consts()' - Compare two constraints.
+ */
+
+static int                             /* O - Result of comparison */
+ppd_compare_consts(ppd_const_t *a,     /* I - First constraint */
+                   ppd_const_t *b)     /* I - Second constraint */
+{
+  int  ret;                            /* Result of comparison */
+
+
+  if ((ret = strcmp(a->option1, b->option1)) != 0)
+    return (ret);
+  else if ((ret = strcmp(a->choice1, b->choice1)) != 0)
+    return (ret);
+  else if ((ret = strcmp(a->option2, b->option2)) != 0)
+    return (ret);
+  else
+    return (strcmp(a->choice2, b->choice2));
+}
+
+
 /*
  * 'ppd_compare_coptions()' - Compare two custom options.
  */
@@ -2296,7 +2434,7 @@ ppd_free_option(ppd_option_t *option)     /* I - Option to free */
          i > 0;
          i --, choice ++)
     {
-      ppd_free(choice->code);
+      _cupsStrFree(choice->code);
     }
 
     ppd_free(option->choices);
@@ -2489,6 +2627,24 @@ ppd_get_option(ppd_group_t *group,       /* I - Group */
 }
 
 
+/*
+ * 'ppd_hash_option()' - Generate a hash of the option name...
+ */
+
+static int                             /* O - Hash index */
+ppd_hash_option(ppd_option_t *option)  /* I - Option */
+{
+  int          hash = 0;               /* Hash index */
+  const char   *k;                     /* Pointer into keyword */
+
+
+  for (hash = option->keyword[0], k = option->keyword + 1; *k;)
+    hash = 33 * hash + *k++;
+
+  return (hash & 511);
+}
+
+
 /*
  * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
  *                necessary.
@@ -2496,6 +2652,7 @@ ppd_get_option(ppd_group_t *group,        /* I - Group */
 
 static int                             /* O - Bitmask of fields read */
 ppd_read(cups_file_t    *fp,           /* I - File to read from */
+         _ppd_line_t    *line,         /* I - Line buffer */
          char           *keyword,      /* O - Keyword from line */
         char           *option,        /* O - Option from line */
          char           *text,         /* O - Human-readable text from line */
@@ -2514,16 +2671,8 @@ ppd_read(cups_file_t    *fp,             /* I - File to read from */
                *optptr,                /* Option pointer */
                *textptr,               /* Text pointer */
                *strptr,                /* Pointer into string */
-               *lineptr,               /* Current position in line buffer */
-               *line;                  /* Line buffer */
-  int          linesize;               /* Current size of line buffer */
-
- /*
-  * Range check everything...
-  */
+               *lineptr;               /* Current position in line buffer */
 
-  if (!fp || !keyword || !option || !text || !string)
-    return (0);
 
  /*
   * Now loop until we have a valid line...
@@ -2532,11 +2681,15 @@ ppd_read(cups_file_t    *fp,            /* I - File to read from */
   *string   = NULL;
   col       = 0;
   startline = cg->ppd_line + 1;
-  linesize  = 1024;
-  line      = malloc(linesize);
 
-  if (!line)
-    return (0);
+  if (!line->buffer)
+  {
+    line->bufsize = 1024;
+    line->buffer  = malloc(1024);
+
+    if (!line->buffer)
+      return (0);
+  }
 
   do
   {
@@ -2544,13 +2697,13 @@ ppd_read(cups_file_t    *fp,            /* I - File to read from */
     * Read the line...
     */
 
-    lineptr  = line;
+    lineptr  = line->buffer;
     endquote = 0;
     colon    = 0;
 
     while ((ch = cupsFileGetChar(fp)) != EOF)
     {
-      if (lineptr >= (line + linesize - 1))
+      if (lineptr >= (line->buffer + line->bufsize - 1))
       {
        /*
         * Expand the line buffer...
@@ -2559,8 +2712,8 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
         char *temp;                    /* Temporary line pointer */
 
 
-        linesize += 1024;
-       if (linesize > 262144)
+        line->bufsize += 1024;
+       if (line->bufsize > 262144)
        {
         /*
          * Don't allow lines longer than 256k!
@@ -2569,24 +2722,20 @@ ppd_read(cups_file_t    *fp,            /* I - File to read from */
           cg->ppd_line   = startline;
           cg->ppd_status = PPD_LINE_TOO_LONG;
 
-         free(line);
-
          return (0);
        }
 
-        temp = realloc(line, linesize);
+        temp = realloc(line->buffer, line->bufsize);
        if (!temp)
        {
           cg->ppd_line   = startline;
           cg->ppd_status = PPD_LINE_TOO_LONG;
 
-         free(line);
-
          return (0);
        }
 
-        lineptr = temp + (lineptr - line);
-       line    = temp;
+        lineptr      = temp + (lineptr - line->buffer);
+       line->buffer = temp;
       }
 
       if (ch == '\r' || ch == '\n')
@@ -2614,7 +2763,7 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
            cupsFileGetChar(fp);
        }
 
-       if (lineptr == line && ignoreblank)
+       if (lineptr == line->buffer && ignoreblank)
           continue;                    /* Skip blank lines */
 
        ch = '\n';
@@ -2633,8 +2782,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
         cg->ppd_line   = startline;
         cg->ppd_status = PPD_ILLEGAL_CHARACTER;
 
-        free(line);
-
         return (0);
       }
       else if (ch != 0x1a)
@@ -2655,12 +2802,10 @@ ppd_read(cups_file_t    *fp,            /* I - File to read from */
           cg->ppd_line   = startline;
           cg->ppd_status = PPD_LINE_TOO_LONG;
 
-          free(line);
-
           return (0);
        }
 
-       if (ch == ':' && strncmp(line, "*%", 2) != 0)
+       if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
          colon = 1;
 
        if (ch == '\"' && colon)
@@ -2705,8 +2850,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
           cg->ppd_line   = startline;
           cg->ppd_status = PPD_ILLEGAL_CHARACTER;
 
-          free(line);
-
           return (0);
        }
        else if (ch != 0x1a)
@@ -2722,8 +2865,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
             cg->ppd_line   = startline;
             cg->ppd_status = PPD_LINE_TOO_LONG;
 
-            free(line);
-
             return (0);
          }
        }
@@ -2768,8 +2909,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
           cg->ppd_line   = startline;
           cg->ppd_status = PPD_ILLEGAL_CHARACTER;
 
-          free(line);
-
           return (0);
        }
        else if (ch != 0x1a)
@@ -2785,14 +2924,12 @@ ppd_read(cups_file_t    *fp,            /* I - File to read from */
             cg->ppd_line   = startline;
             cg->ppd_status = PPD_LINE_TOO_LONG;
 
-            free(line);
-
             return (0);
          }
        }
     }
 
-    if (lineptr > line && lineptr[-1] == '\n')
+    if (lineptr > line->buffer && lineptr[-1] == '\n')
       lineptr --;
 
     *lineptr = '\0';
@@ -2806,40 +2943,34 @@ ppd_read(cups_file_t    *fp,            /* I - File to read from */
     * reading the PPD when we get to the start of this data.
     */
 
-    if (!strcmp(line, "*%APLWORKSET START"))
-    {
-      free(line);
+    if (!strcmp(line->buffer, "*%APLWORKSET START"))
       return (0);
-    }
 
-    if (ch == EOF && lineptr == line)
-    {
-      free(line);
+    if (ch == EOF && lineptr == line->buffer)
       return (0);
-    }
 
    /*
     * Now parse it...
     */
 
     mask    = 0;
-    lineptr = line + 1;
+    lineptr = line->buffer + 1;
 
     keyword[0] = '\0';
     option[0]  = '\0';
     text[0]    = '\0';
     *string    = NULL;
 
-    if ((!line[0] ||                   /* Blank line */
-         !strncmp(line, "*%", 2) ||    /* Comment line */
-         !strcmp(line, "*End")) &&     /* End of multi-line string */
+    if ((!line->buffer[0] ||           /* Blank line */
+         !strncmp(line->buffer, "*%", 2) || /* Comment line */
+         !strcmp(line->buffer, "*End")) && /* End of multi-line string */
         ignoreblank)                   /* Ignore these? */
     {
       startline = cg->ppd_line + 1;
       continue;
     }
 
-    if (!strcmp(line, "*"))            /* (Bad) comment line */
+    if (!strcmp(line->buffer, "*"))    /* (Bad) comment line */
     {
       if (cg->ppd_conform == PPD_CONFORM_RELAXED)
       {
@@ -2851,34 +2982,29 @@ ppd_read(cups_file_t    *fp,            /* I - File to read from */
         cg->ppd_line   = startline;
         cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
 
-        free(line);
         return (0);
       }
     }
 
-    if (line[0] != '*')                        /* All lines start with an asterisk */
+    if (line->buffer[0] != '*')                /* All lines start with an asterisk */
     {
      /*
       * Allow lines consisting of just whitespace...
       */
 
-      for (lineptr = line; *lineptr; lineptr ++)
+      for (lineptr = line->buffer; *lineptr; lineptr ++)
         if (!isspace(*lineptr & 255))
          break;
 
       if (*lineptr)
       {
         cg->ppd_status = PPD_MISSING_ASTERISK;
-        free(line);
         return (0);
       }
       else if (ignoreblank)
         continue;
       else
-      {
-        free(line);
         return (0);
-      }
     }
 
    /*
@@ -2893,7 +3019,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
           (keyptr - keyword) >= (PPD_MAX_NAME - 1))
       {
         cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
-        free(line);
        return (0);
       }
 
@@ -2927,7 +3052,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
            (optptr - option) >= (PPD_MAX_NAME - 1))
         {
           cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
-          free(line);
          return (0);
        }
 
@@ -2939,7 +3063,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
       if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
       {
         cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
-        free(line);
        return (0);
       }
 
@@ -2966,7 +3089,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
              (textptr - text) >= (PPD_MAX_LINE - 1))
          {
            cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
-            free(line);
            return (0);
          }
 
@@ -2979,7 +3101,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
        if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
        {
          cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
-          free(line);
          return (0);
        }
            
@@ -2992,7 +3113,6 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
     if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
     {
       cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
-      free(line);
       return (0);
     }
 
@@ -3016,21 +3136,14 @@ ppd_read(cups_file_t    *fp,            /* I - File to read from */
       if (*strptr == '\"')
       {
        /*
-        * Quoted string by itself...
+        * Quoted string by itself, remove quotes...
        */
 
-       *string = malloc(strlen(lineptr) + 1);
-
-       strptr = *string;
-
-       for (; *lineptr != '\0'; lineptr ++)
-         if (*lineptr != '\"')
-           *strptr++ = *lineptr;
-
-       *strptr = '\0';
+        *strptr = '\0';
+       lineptr ++;
       }
-      else
-        *string = strdup(lineptr);
+
+      *string = _cupsStrAlloc(lineptr);
 
 /*      DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
 
@@ -3039,12 +3152,10 @@ ppd_read(cups_file_t    *fp,            /* I - File to read from */
   }
   while (mask == 0);
 
-  free(line);
-
   return (mask);
 }
 
 
 /*
- * End of "$Id: ppd.c 6188 2007-01-10 16:23:06Z mike $".
+ * End of "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $".
  */