*
* Sorted array routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2006 by Easy Software Products.
+ * Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
* property of Easy Software Products and are protected by Federal
void **elements; /* Array elements */
cups_array_func_t compare; /* Element comparison function */
void *data; /* User data passed to compare */
+ cups_ahash_func_t hashfunc; /* Hash function */
+ int hashsize, /* Size of hash */
+ *hash; /* Hash array */
};
if (a->alloc_elements)
free(a->elements);
+ if (a->hashsize)
+ free(a->hash);
+
free(a);
}
void *e) /* I - Element */
{
int current, /* Current element */
- diff; /* Difference */
+ diff, /* Difference */
+ hash; /* Hash index */
/*
* Yes, look for a match...
*/
- current = cups_array_find(a, e, a->current, &diff);
+ if (a->hash)
+ {
+ hash = (*(a->hashfunc))(e, a->data);
+
+ if (hash < 0 || hash >= a->hashsize)
+ {
+ current = a->current;
+ hash = -1;
+ }
+ else
+ {
+ current = a->hash[hash];
+
+ if (current < 0 || current >= a->num_elements)
+ current = a->current;
+ }
+ }
+ else
+ {
+ current = a->current;
+ hash = -1;
+ }
+
+ current = cups_array_find(a, e, current, &diff);
if (!diff)
{
/*
a->current = current;
+ if (hash >= 0)
+ a->hash[hash] = current;
+
return (a->elements[current]);
}
else
cups_array_t * /* O - Array */
cupsArrayNew(cups_array_func_t f, /* I - Comparison function */
void *d) /* I - User data */
+{
+ return (cupsArrayNew2(f, d, 0, 0));
+}
+
+
+/*
+ * 'cupsArrayNew2()' - Create a new array with hash.
+ *
+ * @since CUPS 1.3@
+ */
+
+cups_array_t * /* O - Array */
+cupsArrayNew2(cups_array_func_t f, /* I - Comparison function */
+ void *d, /* I - User data */
+ cups_ahash_func_t h, /* I - Hash function*/
+ int hsize) /* I - Hash size */
{
cups_array_t *a; /* Array */
a->num_saved = 0;
a->unique = 1;
+ if (hsize > 0 && h)
+ {
+ a->hashfunc = h;
+ a->hashsize = hsize;
+ a->hash = malloc(hsize * sizeof(int));
+
+ if (!a->hash)
+ {
+ free(a);
+ return (NULL);
+ }
+
+ memset(a->hash, -1, hsize * sizeof(int));
+ }
+
return (a);
}
* 'ppdConflicts()' - Check to see if there are any conflicts.
*/
-int /* O - Number of conflicts found */
-ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
+int /* O - Number of conflicts found */
+ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
{
- int i, j, /* Looping variables */
- conflicts; /* Number of conflicts */
- ppd_const_t *c; /* Current constraint */
- ppd_option_t *o1, *o2; /* Options */
- ppd_choice_t *c1, *c2; /* Choices */
+ int i, /* Looping variable */
+ conflicts; /* Number of conflicts */
+ ppd_const_t *c; /* Current constraint */
+ ppd_option_t *o1, *o2; /* Options */
+ ppd_choice_t *c1, *c2; /* Choices */
+ ppd_choice_t key; /* Search key */
if (!ppd)
* that conflict...
*/
- for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+ for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL;
+ i > 0;
+ i --, c ++)
{
/*
* Grab pointers to the first option...
*/
- o1 = ppdFindOption(ppd, c->option1);
+ if (!o1 || strcmp(c->option1, o1->keyword))
+ {
+ o1 = ppdFindOption(ppd, c->option1);
+ c1 = NULL;
+ }
if (!o1)
continue;
- else if (c->choice1[0])
+ else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice)))
{
/*
* This constraint maps to a specific choice.
*/
- c1 = ppdFindChoice(o1, c->choice1);
+ key.option = o1;
+
+ if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
+ !c1->marked)
+ c1 = NULL;
}
- else
+ else if (!c1)
{
/*
* This constraint applies to any choice for this option.
*/
- for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
- if (c1->marked)
- break;
+ key.option = o1;
- if (!j ||
- !strcasecmp(c1->choice, "None") ||
- !strcasecmp(c1->choice, "Off") ||
- !strcasecmp(c1->choice, "False"))
+ if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
+ (!strcasecmp(c1->choice, "None") || !strcasecmp(c1->choice, "Off") ||
+ !strcasecmp(c1->choice, "False")))
c1 = NULL;
}
* Grab pointers to the second option...
*/
- o2 = ppdFindOption(ppd, c->option2);
+ if (!o2 || strcmp(c->option2, o2->keyword))
+ {
+ o2 = ppdFindOption(ppd, c->option2);
+ c2 = NULL;
+ }
if (!o2)
continue;
- else if (c->choice2[0])
+ else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
{
/*
* This constraint maps to a specific choice.
*/
- c2 = ppdFindChoice(o2, c->choice2);
+ key.option = o2;
+
+ if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
+ !c2->marked)
+ c2 = NULL;
}
- else
+ else if (!c2)
{
/*
* This constraint applies to any choice for this option.
*/
- for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
- if (c2->marked)
- break;
+ key.option = o2;
- if (!j ||
- !strcasecmp(c2->choice, "None") ||
- !strcasecmp(c2->choice, "Off") ||
- !strcasecmp(c2->choice, "False"))
+ if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
+ (!strcasecmp(c2->choice, "None") || !strcasecmp(c2->choice, "Off") ||
+ !strcasecmp(c2->choice, "False")))
c2 = NULL;
}
ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */
const char *choice) /* I - Name of choice */
{
- int i; /* Looping var */
- ppd_choice_t *c; /* Current choice */
+ int i; /* Looping var */
+ ppd_choice_t *c; /* Current choice */
if (o == NULL || choice == NULL)
ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
const char *option) /* I - Keyword/option name */
{
- int i; /* Looping var */
- ppd_option_t *o; /* Pointer to option */
- ppd_choice_t *c; /* Pointer to choice */
+ ppd_choice_t key; /* Search key for choice */
- if ((o = ppdFindOption(ppd, option)) == NULL)
+ if ((key.option = ppdFindOption(ppd, option)) == NULL)
return (NULL);
- for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
- if (c->marked)
- return (c);
-
- return (NULL);
+ return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
}
* 'ppdIsMarked()' - Check to see if an option is marked...
*/
-int /* O - Non-zero if option is marked */
-ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
- const char *option, /* I - Option/Keyword name */
- const char *choice) /* I - Choice name */
+int /* O - Non-zero if option is marked */
+ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
+ const char *option, /* I - Option/Keyword name */
+ const char *choice) /* I - Choice name */
{
- ppd_option_t *o; /* Option pointer */
- ppd_choice_t *c; /* Choice pointer */
+ ppd_choice_t key, /* Search key */
+ *c; /* Choice pointer */
- if (ppd == NULL)
+ if (!ppd)
return (0);
- if ((o = ppdFindOption(ppd, option)) == NULL)
+ if ((key.option = ppdFindOption(ppd, option)) == NULL)
return (0);
- if ((c = ppdFindChoice(o, choice)) == NULL)
+ if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
return (0);
- return (c->marked);
+ return (!strcmp(c->choice, choice));
}
*/
void
-ppdMarkDefaults(ppd_file_t *ppd)/* I - PPD file record */
+ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
{
- int i; /* Looping variables */
- ppd_group_t *g; /* Current group */
+ int i; /* Looping variables */
+ ppd_group_t *g; /* Current group */
+ ppd_choice_t *c; /* Current choice */
- if (ppd == NULL)
+ if (!ppd)
return;
+ /*
+ * Clean out the marked array...
+ */
+
+ for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
+ c;
+ c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
+ cupsArrayRemove(ppd->marked, c);
+
+ /*
+ * Then repopulate it with the defaults...
+ */
+
for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
ppd_defaults(ppd, g);
}
{
int i, j; /* Looping vars */
ppd_option_t *o; /* Option pointer */
- ppd_choice_t *c; /* Choice pointer */
+ ppd_choice_t *c, /* Choice pointer */
+ *oldc, /* Old choice pointer */
+ key; /* Search key for choice */
struct lconv *loc; /* Locale data */
if (!strcasecmp(option, "AP_D_InputSlot"))
{
if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
- for (i = 0; i < o->num_choices; i ++)
- o->choices[i].marked = 0;
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+ }
}
/*
* Option found; mark it and then handle unmarking any other options.
*/
- c->marked = 1;
-
if (o->ui != PPD_UI_PICKMANY)
{
/*
* Unmark all other choices...
*/
- for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
- if (strcasecmp(c->choice, choice))
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+
+ if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion"))
+ {
+ /*
+ * Mark current page size...
+ */
+
+ for (j = 0; j < ppd->num_sizes; j ++)
+ ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
+ choice);
+
+ /*
+ * Unmark the current PageSize or PageRegion setting, as
+ * appropriate...
+ */
+
+ if (!strcasecmp(option, "PageSize"))
{
- c->marked = 0;
+ if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+ }
+ }
+ else
+ {
+ if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+ }
+ }
+ }
+ else if (!strcasecmp(option, "InputSlot"))
+ {
+ /*
+ * Unmark ManualFeed True and possibly mark ManualFeed False
+ * option...
+ */
- if (!strcasecmp(option, "PageSize") ||
- !strcasecmp(option, "PageRegion"))
- {
- /*
- * Mark current page size...
- */
-
- for (j = 0; j < ppd->num_sizes; j ++)
- ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
- choice);
-
- /*
- * Unmark the current PageSize or PageRegion setting, as
- * appropriate...
- */
-
- if (!strcasecmp(option, "PageSize"))
- {
- if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
- for (j = 0; j < o->num_choices; j ++)
- o->choices[j].marked = 0;
- }
- else
- {
- if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
- for (j = 0; j < o->num_choices; j ++)
- o->choices[j].marked = 0;
- }
- }
- else if (!strcasecmp(option, "InputSlot"))
- {
- /*
- * Unmark ManualFeed True and possibly mark ManualFeed False
- * option...
- */
-
- if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
- for (j = 0; j < o->num_choices; j ++)
- o->choices[j].marked = !strcasecmp(o->choices[j].choice, "False");
- }
- else if (!strcasecmp(option, "ManualFeed") &&
- !strcasecmp(choice, "True"))
- {
- /*
- * Unmark InputSlot option...
- */
+ if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+ }
+ }
+ else if (!strcasecmp(option, "ManualFeed") &&
+ !strcasecmp(choice, "True"))
+ {
+ /*
+ * Unmark InputSlot option...
+ */
- if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
- for (j = 0; j < o->num_choices; j ++)
- o->choices[j].marked = 0;
- }
+ if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
}
+ }
}
+ c->marked = 1;
+
+ cupsArrayAdd(ppd->marked, c);
+
/*
* Return the number of conflicts...
*/
ppd_group_t *sg; /* Current sub-group */
- if (g == NULL)
- return;
-
for (i = g->num_options, o = g->options; i > 0; i --, o ++)
if (strcasecmp(o->keyword, "PageRegion") != 0)
ppdMarkOption(ppd, o->keyword, o->defchoice);
* 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.
* 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 */
+
/*
* Local functions...
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);
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_hash_option(ppd_option_t *option);
static int ppd_read(cups_file_t *fp, char *keyword, char *option,
char *text, char **string, int ignoreblank,
_cups_globals_t *cg);
}
cupsArrayDelete(ppd->options);
+ cupsArrayDelete(ppd->marked);
/*
* Free any page sizes...
* 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;
}
}
+ /*
+ * 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...
*/
}
+/*
+ * '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 (a->option - b->option);
+}
+
+
+/*
+ * 'ppd_compare_consts()' - Compare two constraints.
+ */
+
+static int /* O - Result of comparison */
+ppd_compare_consts(ppd_const_t *a, /* I - First constraint */
+ ppd_const_t *b) /* I - Second constraint */
+{
+ int ret; /* Result of comparison */
+
+
+ if ((ret = strcmp(a->option1, b->option1)) != 0)
+ return (ret);
+ else if ((ret = strcmp(a->choice1, b->choice1)) != 0)
+ return (ret);
+ else if ((ret = strcmp(a->option2, b->option2)) != 0)
+ return (ret);
+ else
+ return (strcmp(a->choice2, b->choice2));
+}
+
+
/*
* 'ppd_compare_coptions()' - Compare two custom options.
*/
}
+/*
+ * 'ppd_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.