/*
- * "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $"
+ * "$Id$"
*
- * PPD file routines for the Common UNIX Printing System (CUPS).
+ * PPD file routines for CUPS.
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2012 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* LanguageEncoding.
* ppdLastError() - Return the status from the last ppdOpen*().
* ppdOpen() - Read a PPD file into memory.
+ * _ppdOpen() - Read a PPD file into memory.
* ppdOpen2() - Read a PPD file into memory.
* ppdOpenFd() - Read a PPD file into memory.
+ * _ppdOpenFile() - 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_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_decode() - Decode a string value...
+ * ppd_free_filters() - Free the filters array.
* ppd_free_group() - Free a single UI group.
* ppd_free_option() - Free a single option.
* ppd_get_coption() - Get a custom option record.
* ppd_hash_option() - Generate a hash of the option name...
* ppd_read() - Read a line from a PPD file, skipping comment
* lines as necessary.
+ * ppd_update_filters() - Update the filters array as needed.
*/
/*
* Include necessary headers.
*/
-#include "globals.h"
-#include "debug.h"
-#include <stdlib.h>
+#include "cups-private.h"
+#include "ppd-private.h"
/*
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);
static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b);
static int ppd_decode(char *string);
+static void ppd_free_filters(ppd_file_t *ppd);
static void ppd_free_group(ppd_group_t *group);
static void ppd_free_option(ppd_option_t *option);
static ppd_coption_t *ppd_get_coption(ppd_file_t *ppd, const char *name);
char *keyword, char *option, char *text,
char **string, int ignoreblank,
_cups_globals_t *cg);
+static int ppd_update_filters(ppd_file_t *ppd,
+ _cups_globals_t *cg);
/*
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_coption_t *coption; /* Current custom option */
ppd_cparam_t *cparam; /* Current custom parameter */
_cupsStrFree(ppd->lang_encoding);
_cupsStrFree(ppd->nickname);
- _cupsStrFree(ppd->patches);
+ if (ppd->patches)
+ free(ppd->patches);
_cupsStrFree(ppd->jcl_begin);
_cupsStrFree(ppd->jcl_end);
_cupsStrFree(ppd->jcl_ps);
* Free any filters...
*/
- if (ppd->num_filters > 0)
- {
- for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
- _cupsStrFree(*filter);
-
- ppd_free(ppd->filters);
- }
+ ppd_free_filters(ppd);
/*
* Free any fonts...
cupsArrayDelete(ppd->coptions);
+ /*
+ * Free constraints...
+ */
+
+ if (ppd->cups_uiconstraints)
+ {
+ _ppd_cups_uiconsts_t *consts; /* Current constraints */
+
+
+ for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
+ consts;
+ consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
+ {
+ free(consts->constraints);
+ free(consts);
+ }
+
+ cupsArrayDelete(ppd->cups_uiconstraints);
+ }
+
+ /*
+ * Free any PPD cache/mapping data...
+ */
+
+ if (ppd->cache)
+ _ppdCacheDestroy(ppd->cache);
+
/*
* Free the whole record...
*/
/*
* 'ppdErrorString()' - Returns the text assocated with a status.
*
- * @since CUPS 1.1.19@
+ * @since CUPS 1.1.19/OS X 10.3@
*/
const char * /* O - Status string */
_("Illegal option keyword string"),
_("Illegal translation string"),
_("Illegal whitespace character"),
- _("Bad custom parameter")
+ _("Bad custom parameter"),
+ _("Missing option keyword"),
+ _("Bad value string"),
+ _("Missing CloseGroup")
};
- if (status < PPD_OK || status > PPD_ILLEGAL_WHITESPACE)
+ if (status < PPD_OK || status >= PPD_MAX_STATUS)
return (_cupsLangString(cupsLangDefault(), _("Unknown")));
else
return (_cupsLangString(cupsLangDefault(), messages[status]));
cups_encoding_t /* O - CUPS encoding value */
_ppdGetEncoding(const char *name) /* I - LanguageEncoding string */
{
- if (!strcasecmp(name, "ISOLatin1"))
+ if (!_cups_strcasecmp(name, "ISOLatin1"))
return (CUPS_ISO8859_1);
- else if (!strcasecmp(name, "ISOLatin2"))
+ else if (!_cups_strcasecmp(name, "ISOLatin2"))
return (CUPS_ISO8859_2);
- else if (!strcasecmp(name, "ISOLatin5"))
+ else if (!_cups_strcasecmp(name, "ISOLatin5"))
return (CUPS_ISO8859_5);
- else if (!strcasecmp(name, "JIS83-RKSJ"))
- return (CUPS_WINDOWS_932);
- else if (!strcasecmp(name, "MacStandard"))
+ else if (!_cups_strcasecmp(name, "JIS83-RKSJ"))
+ return (CUPS_JIS_X0213);
+ else if (!_cups_strcasecmp(name, "MacStandard"))
return (CUPS_MAC_ROMAN);
- else if (!strcasecmp(name, "WindowsANSI"))
+ else if (!_cups_strcasecmp(name, "WindowsANSI"))
return (CUPS_WINDOWS_1252);
else
return (CUPS_UTF8);
/*
* 'ppdLastError()' - Return the status from the last ppdOpen*().
*
- * @since CUPS 1.1.19@
+ * @since CUPS 1.1.19/OS X 10.3@
*/
ppd_status_t /* O - Status code */
/*
- * 'ppdOpen()' - Read a PPD file into memory.
- */
-
-ppd_file_t * /* O - PPD file record */
-ppdOpen(FILE *fp) /* I - File to read from */
-{
- ppd_file_t *ppd; /* PPD file record */
- cups_file_t *cf; /* CUPS file */
-
-
- /*
- * Reopen the stdio file as a CUPS file...
- */
-
- if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
- return (NULL);
-
- /*
- * Load the PPD file using the newer API...
- */
-
- ppd = ppdOpen2(cf);
-
- /*
- * Close the CUPS file and return the PPD...
- */
-
- cupsFileClose(cf);
-
- return (ppd);
-}
-
-
-/*
- * 'ppdOpen2()' - Read a PPD file into memory.
+ * '_ppdOpen()' - Read a PPD file into memory.
*
- * @since CUPS 1.2@
+ * @since CUPS 1.2/OS X 10.5@
*/
-ppd_file_t * /* O - PPD file record */
-ppdOpen2(cups_file_t *fp) /* I - File to read from */
+ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
+_ppdOpen(
+ cups_file_t *fp, /* I - File to read from */
+ _ppd_localization_t localization) /* I - Localization to load */
{
int i, j, k; /* Looping vars */
int count; /* Temporary count */
ppd_section_t section; /* Order dependency section */
ppd_profile_t *profile; /* Pointer to color profile */
char **filter; /* Pointer to filter */
- cups_lang_t *language; /* Default language */
struct lconv *loc; /* Locale data */
int ui_keyword; /* Is this line a UI keyword? */
+ cups_lang_t *lang; /* Language data */
cups_encoding_t encoding; /* Encoding of PPD file */
_cups_globals_t *cg = _cupsGlobals();
/* Global data */
+ char custom_name[PPD_MAX_NAME];
+ /* CustomFoo attribute name */
+ ppd_attr_t *custom_attr; /* CustomFoo attribute */
+ char ll[4], /* Language + '.' */
+ ll_CC[7]; /* Language + country + '.' */
+ size_t ll_len = 0, /* Language length */
+ ll_CC_len = 0; /* Language + country length */
static const char * const ui_keywords[] =
{
#ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
"PageSize"
#endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
};
+ static const char * const color_keywords[] = /* Keywords associated with color profiles */
+ {
+ ".cupsICCProfile",
+ ".ColorModel",
+ };
+ DEBUG_printf(("_ppdOpen(fp=%p)", fp));
+
/*
* Default to "OK" status...
*/
return (NULL);
}
+ /*
+ * If only loading a single localization set up the strings to match...
+ */
+
+ if (localization == _PPD_LOCALIZATION_DEFAULT)
+ {
+ if ((lang = cupsLangDefault()) == NULL)
+ return (NULL);
+
+ snprintf(ll_CC, sizeof(ll_CC), "%s.", lang->language);
+ snprintf(ll, sizeof(ll), "%2.2s.", lang->language);
+
+ ll_CC_len = strlen(ll_CC);
+ ll_len = strlen(ll);
+
+ DEBUG_printf(("2_ppdOpen: Loading localizations matching \"%s\" and \"%s\"",
+ ll_CC, ll));
+ }
+
/*
* Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
*/
mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
- DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask, keyword));
+ DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask, keyword));
if (mask == 0 ||
strcmp(keyword, "PPD-Adobe") ||
cg->ppd_status = PPD_MISSING_PPDADOBE4;
_cupsStrFree(string);
+ ppd_free(line.buffer);
return (NULL);
}
- DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
+ DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword, string));
_cupsStrFree(string);
{
cg->ppd_status = PPD_ALLOC_ERROR;
+ _cupsStrFree(string);
+ ppd_free(line.buffer);
+
return (NULL);
}
ppd->language_level = 2;
ppd->color_device = 0;
- ppd->colorspace = PPD_CS_GRAY;
+ ppd->colorspace = PPD_CS_N;
ppd->landscape = -90;
ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
NULL);
- /*
- * Get the default language for the user...
- */
-
- language = cupsLangDefault();
- loc = localeconv();
-
/*
* Read lines from the PPD file and add them to the file record...
*/
choice = NULL;
ui_keyword = 0;
encoding = CUPS_ISO8859_1;
+ loc = localeconv();
while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
{
-#ifdef DEBUG
- printf("mask = %x, keyword = \"%s\"", mask, keyword);
-
- if (name[0] != '\0')
- printf(", name = \"%s\"", name);
-
- if (text[0] != '\0')
- printf(", text = \"%s\"", text);
-
- if (string != NULL)
- {
- if (strlen(string) > 40)
- printf(", string = %p", string);
- else
- printf(", string = \"%s\"", string);
- }
+ DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\", name=\"%s\", "
+ "text=\"%s\", string=%d chars...", mask, keyword, name, text,
+ string ? (int)strlen(string) : 0));
- puts("");
-#endif /* DEBUG */
-
- 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)
+ if (strncmp(keyword, "Default", 7) && !string &&
+ cg->ppd_conform != PPD_CONFORM_RELAXED)
{
/*
* Need a string value!
goto error;
}
+ else if (!string)
+ continue;
/*
* Certain main keywords (as defined by the PPD spec) may be used
ui_keyword = 0;
}
+ /*
+ * If we are filtering out keyword localizations, see if this line needs to
+ * be used...
+ */
+
+ if (localization != _PPD_LOCALIZATION_ALL &&
+ (temp = strchr(keyword, '.')) != NULL &&
+ ((temp - keyword) == 2 || (temp - keyword) == 5) &&
+ _cups_isalpha(keyword[0]) &&
+ _cups_isalpha(keyword[1]) &&
+ (keyword[2] == '.' ||
+ (keyword[2] == '_' && _cups_isalpha(keyword[3]) &&
+ _cups_isalpha(keyword[4]) && keyword[5] == '.')))
+ {
+ if (localization == _PPD_LOCALIZATION_NONE ||
+ (localization == _PPD_LOCALIZATION_DEFAULT &&
+ strncmp(ll_CC, keyword, ll_CC_len) &&
+ strncmp(ll, keyword, ll_len)))
+ {
+ DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword));
+ continue;
+ }
+ else if (localization == _PPD_LOCALIZATION_ICC_PROFILES)
+ {
+ /*
+ * Only load localizations for the color profile related keywords...
+ */
+
+ for (i = 0;
+ i < (int)(sizeof(color_keywords) / sizeof(color_keywords[0]));
+ i ++)
+ {
+ if (!_cups_strcasecmp(temp, color_keywords[i]))
+ break;
+ }
+
+ if (i >= (int)(sizeof(color_keywords) / sizeof(color_keywords[0])))
+ {
+ DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword));
+ continue;
+ }
+ }
+ }
+
if (option == NULL &&
(mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
(PPD_KEYWORD | PPD_OPTION | PPD_STRING))
ui_keyword = 1;
- DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
+ DEBUG_printf(("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
keyword));
if (!group)
encoding)) == NULL)
goto error;
- DEBUG_printf(("Adding to group %s...\n", group->text));
+ DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text));
option = ppd_get_option(group, keyword);
group = NULL;
}
!strcmp(ppd->attrs[j]->name + 7, keyword) &&
ppd->attrs[j]->value)
{
- DEBUG_printf(("Setting Default%s to %s via attribute...\n",
+ DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
option->keyword, ppd->attrs[j]->value));
strlcpy(option->defchoice, ppd->attrs[j]->value,
sizeof(option->defchoice));
profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
(ppd->num_profiles + 1));
+ if (!profile)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
ppd->profiles = profile;
profile += ppd->num_profiles;
ppd->num_profiles ++;
ppd->num_filters ++;
/*
- * Copy filter string and prevent it from being freed below...
+ * Retain a copy of the filter string...
*/
- *filter = string;
- string = NULL;
+ *filter = _cupsStrRetain(string);
}
else if (!strcmp(keyword, "Throughput"))
ppd->throughput = atoi(string);
goto error;
}
-
+
ppd->fonts = tempfonts;
ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
ppd->num_fonts ++;
* Get the parameter data...
*/
- if (sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
+ if (!string ||
+ sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
cmaximum) != 4)
{
cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
}
else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
{
- DEBUG_puts("Processing Custom option...");
+ ppd_option_t *custom_option; /* Custom option */
+
+ DEBUG_puts("2_ppdOpen: Processing Custom option...");
/*
* Get the option and custom option...
*/
- 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)
- {
- DEBUG_puts("Unable to get general group!");
-
- 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));
-
- cg->ppd_status = PPD_ALLOC_ERROR;
-
- goto error;
- }
- }
-
if (!ppd_get_coption(ppd, keyword + 6))
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
- /*
- * Add the "custom" option...
- */
+ if (option && !_cups_strcasecmp(option->keyword, keyword + 6))
+ custom_option = option;
+ else
+ custom_option = ppdFindOption(ppd, keyword + 6);
- if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ if (custom_option)
{
- DEBUG_puts("Unable to add Custom choice!");
+ /*
+ * Add the "custom" option...
+ */
- cg->ppd_status = PPD_ALLOC_ERROR;
+ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+ {
+ DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
- goto error;
- }
+ cg->ppd_status = PPD_ALLOC_ERROR;
- strlcpy(choice->text, text[0] ? text : _("Custom"),
- sizeof(choice->text));
+ goto error;
+ }
- choice->code = string;
- string = NULL; /* Don't add as an attribute below */
- option = NULL;
+ strlcpy(choice->text, text[0] ? text : _("Custom"),
+ sizeof(choice->text));
+
+ choice->code = _cupsStrAlloc(string);
+
+ if (custom_option->section == PPD_ORDER_JCL)
+ ppd_decode(choice->code);
+ }
/*
* Now process custom page sizes specially...
if (!strcmp(keyword, "CustomPageSize"))
{
- ppd->variable_sizes = 1;
-
/*
* Add a "Custom" page size entry...
*/
- 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;
- }
+ ppd->variable_sizes = 1;
- if (group)
- group = ppd->groups + groupidx; /* Restore group pointer */
+ ppd_add_size(ppd, "Custom");
- option = ppd_get_option(gtemp, "PageRegion");
- }
+ if (option && !_cups_strcasecmp(option->keyword, "PageRegion"))
+ custom_option = option;
+ else
+ custom_option = ppdFindOption(ppd, "PageRegion");
- if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ if (custom_option)
{
- DEBUG_puts("Unable to add Custom choice!");
+ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+ {
+ DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
- cg->ppd_status = PPD_ALLOC_ERROR;
+ cg->ppd_status = PPD_ALLOC_ERROR;
- goto error;
- }
+ goto error;
+ }
- strlcpy(choice->text, text[0] ? text : _("Custom"),
- sizeof(choice->text));
- option = NULL;
+ strlcpy(choice->text, text[0] ? text : _("Custom"),
+ sizeof(choice->text));
+ }
}
}
else if (!strcmp(keyword, "LandscapeOrientation"))
else if (!strcmp(string, "Plus90"))
ppd->landscape = 90;
}
- else if (!strcmp(keyword, "Emulators"))
+ else if (!strcmp(keyword, "Emulators") && string)
{
for (count = 1, sptr = string; sptr != NULL;)
if ((sptr = strchr(sptr, ' ')) != NULL)
}
ppd->num_emulations = count;
- ppd->emulations = calloc(count, sizeof(ppd_emul_t));
+ if ((ppd->emulations = calloc(count, sizeof(ppd_emul_t))) == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
for (i = 0, sptr = string; i < count; i ++)
{
}
else if (!strcmp(keyword, "JobPatchFile"))
{
+ /*
+ * CUPS STR #3421: Check for "*JobPatchFile: int: string"
+ */
+
+ if (isdigit(*string & 255))
+ {
+ for (sptr = string + 1; isdigit(*sptr & 255); sptr ++);
+
+ if (*sptr == ':')
+ {
+ /*
+ * Found "*JobPatchFile: int: string"...
+ */
+
+ cg->ppd_status = PPD_BAD_VALUE;
+
+ goto error;
+ }
+ }
+
+ if (!name[0] && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ /*
+ * Found "*JobPatchFile: string"...
+ */
+
+ cg->ppd_status = PPD_MISSING_OPTION_KEYWORD;
+
+ goto error;
+ }
+
if (ppd->patches == NULL)
- ppd->patches = _cupsStrAlloc(string);
+ ppd->patches = strdup(string);
else
{
temp = realloc(ppd->patches, strlen(ppd->patches) +
ppd->patches = temp;
- strcpy(ppd->patches + strlen(ppd->patches), string);
+ memcpy(ppd->patches + strlen(ppd->patches), string, strlen(string) + 1);
}
}
else if (!strcmp(keyword, "OpenUI"))
* Add an option record to the current sub-group, group, or file...
*/
- DEBUG_printf(("name=\"%s\" (%d)\n", name, strlen(name)));
+ DEBUG_printf(("2_ppdOpen: name=\"%s\" (%d)", name, (int)strlen(name)));
if (name[0] == '*')
_cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
- for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
+ for (i = (int)strlen(name) - 1; i > 0 && _cups_isspace(name[i]); i --)
name[i] = '\0'; /* Eliminate trailing spaces */
- DEBUG_printf(("OpenUI of %s in group %s...\n", name,
+ DEBUG_printf(("2_ppdOpen: OpenUI of %s in group %s...", name,
group ? group->text : "(null)"));
if (subgroup != NULL)
encoding)) == NULL)
goto error;
- DEBUG_printf(("Adding to group %s...\n", group->text));
+ DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text));
option = ppd_get_option(group, name);
group = NULL;
}
!strcmp(ppd->attrs[j]->name + 7, name) &&
ppd->attrs[j]->value)
{
- DEBUG_printf(("Setting Default%s to %s via attribute...\n",
+ DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
option->keyword, ppd->attrs[j]->value));
strlcpy(option->defchoice, ppd->attrs[j]->value,
sizeof(option->defchoice));
_cupsStrFree(string);
string = NULL;
+
+ /*
+ * Add a custom option choice if we have already seen a CustomFoo
+ * attribute...
+ */
+
+ if (!_cups_strcasecmp(name, "PageRegion"))
+ strlcpy(custom_name, "CustomPageSize", sizeof(custom_name));
+ else
+ snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
+
+ if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
+ {
+ if ((choice = ppdFindChoice(option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ {
+ DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ strlcpy(choice->text,
+ custom_attr->text[0] ? custom_attr->text : _("Custom"),
+ sizeof(choice->text));
+ choice->code = _cupsStrRetain(custom_attr->value);
+ }
}
else if (!strcmp(keyword, "JCLOpenUI"))
{
!strcmp(ppd->attrs[j]->name + 7, name) &&
ppd->attrs[j]->value)
{
- DEBUG_printf(("Setting Default%s to %s via attribute...\n",
+ DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
option->keyword, ppd->attrs[j]->value));
strlcpy(option->defchoice, ppd->attrs[j]->value,
sizeof(option->defchoice));
_cupsStrFree(string);
string = NULL;
+
+ /*
+ * Add a custom option choice if we have already seen a CustomFoo
+ * attribute...
+ */
+
+ snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
+
+ if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
+ {
+ if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ {
+ DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ strlcpy(choice->text,
+ custom_attr->text[0] ? custom_attr->text : _("Custom"),
+ sizeof(choice->text));
+ choice->code = _cupsStrRetain(custom_attr->value);
+ }
}
else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
{
_cupsStrFree(string);
string = NULL;
}
- else if (!strcmp(keyword, "OrderDependency") ||
- !strcmp(keyword, "NonUIOrderDependency"))
+ else if (!strcmp(keyword, "OrderDependency"))
{
order = (float)_cupsStrScand(string, &sptr, loc);
* Set the default as part of the current option...
*/
- DEBUG_printf(("Setting %s to %s...\n", keyword, string));
+ DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string));
strlcpy(option->defchoice, string, sizeof(option->defchoice));
- DEBUG_printf(("%s is now %s...\n", keyword, option->defchoice));
+ DEBUG_printf(("2_ppdOpen: %s is now %s...", keyword, option->defchoice));
}
else
{
if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
{
- DEBUG_printf(("Setting %s to %s...\n", keyword, string));
+ DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string));
strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
}
}
else if (!strcmp(keyword, "UIConstraints") ||
!strcmp(keyword, "NonUIConstraints"))
{
+ if (!string)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
if (ppd->num_consts == 0)
constraint = calloc(2, sizeof(ppd_const_t));
else
constraint->choice1[0] = '\0';
constraint->choice2[0] = '\0';
break;
-
+
case 3 : /* Two options, one choice... */
/*
* Check for broken constraints like "* Option"...
constraint->choice2[0] = '\0';
}
break;
-
+
case 4 : /* Two options, two choices... */
/*
* Check for broken constraints like "* Option"...
break;
}
- /*
- * For CustomPageSize and InputSlot/ManualFeed, create a duplicate
- * constraint for PageRegion...
- */
-
- if (!strcasecmp(constraint->option1, "CustomPageSize") &&
- (!strcasecmp(constraint->option2, "InputSlot") ||
- !strcasecmp(constraint->option2, "ManualFeed")))
- {
- ppd->num_consts ++;
-
- strcpy(constraint[1].option1, "PageRegion");
- strcpy(constraint[1].choice1, "Custom");
- strcpy(constraint[1].option2, constraint->option2);
- strcpy(constraint[1].choice2, constraint->choice2);
- }
- else if (!strcasecmp(constraint->option2, "CustomPageSize") &&
- (!strcasecmp(constraint->option1, "InputSlot") ||
- !strcasecmp(constraint->option1, "ManualFeed")))
- {
- ppd->num_consts ++;
-
- strcpy(constraint[1].option1, constraint->option1);
- strcpy(constraint[1].choice1, constraint->choice1);
- strcpy(constraint[1].option2, "PageRegion");
- strcpy(constraint[1].choice2, "Custom");
- }
-
- /*
- * Handle CustomFoo option constraints...
- */
-
- if (!strncasecmp(constraint->option1, "Custom", 6) &&
- !strcasecmp(constraint->choice1, "True"))
- {
- _cups_strcpy(constraint->option1, constraint->option1 + 6);
- strcpy(constraint->choice1, "Custom");
- }
-
- if (!strncasecmp(constraint->option2, "Custom", 6) &&
- !strcasecmp(constraint->choice2, "True"))
- {
- _cups_strcpy(constraint->option2, constraint->option2 + 6);
- strcpy(constraint->choice2, "Custom");
- }
-
/*
* Don't add this one as an attribute...
*/
(PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
!strcmp(keyword, option->keyword))
{
- DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
+ DEBUG_printf(("2_ppdOpen: group=%p, subgroup=%p", group, subgroup));
if (!strcmp(keyword, "PageSize"))
{
* Add the option choice...
*/
- choice = ppd_add_choice(option, name);
+ if ((choice = ppd_add_choice(option, name)) == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
if (text[0])
cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
sizeof(choice->text), encoding);
else if (!strcmp(name, "True"))
- strcpy(choice->text, _("Yes"));
+ strlcpy(choice->text, _("Yes"), sizeof(choice->text));
else if (!strcmp(name, "False"))
- strcpy(choice->text, _("No"));
+ strlcpy(choice->text, _("No"), sizeof(choice->text));
else
strlcpy(choice->text, name, sizeof(choice->text));
_cupsStrFree(string);
}
- if (line.buffer)
- free(line.buffer);
+ /*
+ * Check for a missing CloseGroup...
+ */
+
+ if (group && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_MISSING_CLOSE_GROUP;
+ goto error;
+ }
+
+ ppd_free(line.buffer);
/*
* Reset language preferences...
*/
- cupsLangFree(language);
-
#ifdef DEBUG
if (!cupsFileEOF(fp))
- printf("Premature EOF at %lu...\n", (unsigned long)cupsFileTell(fp));
+ DEBUG_printf(("1_ppdOpen: Premature EOF at %lu...\n",
+ (unsigned long)cupsFileTell(fp)));
#endif /* DEBUG */
if (cg->ppd_status != PPD_OK)
return (NULL);
}
+ /*
+ * Update the filters array as needed...
+ */
+
+ if (!ppd_update_filters(ppd, cg))
+ {
+ ppdClose(ppd);
+
+ return (NULL);
+ }
+
/*
* Create the sorted options array and set the option back-pointer for
* each choice and custom option...
}
}
- /*
- * 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...
*/
error:
- if (line.buffer)
- free(line.buffer);
-
_cupsStrFree(string);
+ ppd_free(line.buffer);
ppdClose(ppd);
- cupsLangFree(language);
-
return (NULL);
}
/*
- * 'ppdOpenFd()' - Read a PPD file into memory.
+ * 'ppdOpen()' - Read a PPD file into memory.
*/
ppd_file_t * /* O - PPD file record */
+ppdOpen(FILE *fp) /* I - File to read from */
+{
+ ppd_file_t *ppd; /* PPD file record */
+ cups_file_t *cf; /* CUPS file */
+
+
+ /*
+ * Reopen the stdio file as a CUPS file...
+ */
+
+ if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
+ return (NULL);
+
+ /*
+ * Load the PPD file using the newer API...
+ */
+
+ ppd = _ppdOpen(cf, _PPD_LOCALIZATION_DEFAULT);
+
+ /*
+ * Close the CUPS file and return the PPD...
+ */
+
+ cupsFileClose(cf);
+
+ return (ppd);
+}
+
+
+/*
+ * 'ppdOpen2()' - Read a PPD file into memory.
+ *
+ * @since CUPS 1.2/OS X 10.5@
+ */
+
+ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
+ppdOpen2(cups_file_t *fp) /* I - File to read from */
+{
+ return _ppdOpen(fp, _PPD_LOCALIZATION_DEFAULT);
+}
+
+
+/*
+ * 'ppdOpenFd()' - Read a PPD file into memory.
+ */
+
+ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
ppdOpenFd(int fd) /* I - File to read from */
{
cups_file_t *fp; /* CUPS file pointer */
/*
- * 'ppdOpenFile()' - Read a PPD file into memory.
+ * '_ppdOpenFile()' - Read a PPD file into memory.
*/
-ppd_file_t * /* O - PPD file record */
-ppdOpenFile(const char *filename) /* I - File to read from */
+ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
+_ppdOpenFile(const char *filename, /* I - File to read from */
+ _ppd_localization_t localization) /* I - Localization to load */
{
cups_file_t *fp; /* File pointer */
ppd_file_t *ppd; /* PPD file record */
if ((fp = cupsFileOpen(filename, "r")) != NULL)
{
- ppd = ppdOpen2(fp);
+ ppd = _ppdOpen(fp, localization);
cupsFileClose(fp);
}
}
+/*
+ * 'ppdOpenFile()' - Read a PPD file into memory.
+ */
+
+ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
+ppdOpenFile(const char *filename) /* I - File to read from */
+{
+ return _ppdOpenFile(filename, _PPD_LOCALIZATION_DEFAULT);
+}
+
+
/*
* 'ppdSetConformance()' - Set the conformance level for PPD files.
*
- * @since CUPS 1.1.20@
+ * @since CUPS 1.1.20/OS X 10.4@
*/
void
ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
ppd_attr_t *b) /* I - Second attribute */
{
- int ret; /* Result of comparison */
-
-
- if ((ret = strcasecmp(a->name, b->name)) != 0)
- return (ret);
- else
- return (strcasecmp(a->spec, b->spec));
+ return (_cups_strcasecmp(a->name, b->name));
}
}
-/*
- * '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_compare_coptions(ppd_coption_t *a, /* I - First option */
ppd_coption_t *b) /* I - Second option */
{
- return (strcasecmp(a->keyword, b->keyword));
-}
-
-
-/*
- * 'ppd_compare_cparams()' - Compare two custom parameters.
- */
-
-static int /* O - Result of comparison */
-ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
- ppd_cparam_t *b) /* I - Second parameter */
-{
- return (strcasecmp(a->name, b->name));
+ return (_cups_strcasecmp(a->keyword, b->keyword));
}
ppd_compare_options(ppd_option_t *a, /* I - First option */
ppd_option_t *b) /* I - Second option */
{
- return (strcasecmp(a->keyword, b->keyword));
+ return (_cups_strcasecmp(a->keyword, b->keyword));
}
inptr ++;
while (isxdigit(*inptr & 255))
{
- if (isalpha(*inptr))
+ if (_cups_isalpha(*inptr))
*outptr = (tolower(*inptr) - 'a' + 10) << 4;
else
*outptr = (*inptr - '0') << 4;
if (!isxdigit(*inptr & 255))
break;
- if (isalpha(*inptr))
+ if (_cups_isalpha(*inptr))
*outptr |= tolower(*inptr) - 'a' + 10;
else
*outptr |= *inptr - '0';
}
+/*
+ * 'ppd_free_filters()' - Free the filters array.
+ */
+
+static void
+ppd_free_filters(ppd_file_t *ppd) /* I - PPD file */
+{
+ int i; /* Looping var */
+ char **filter; /* Current filter */
+
+
+ if (ppd->num_filters > 0)
+ {
+ for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
+ _cupsStrFree(*filter);
+
+ ppd_free(ppd->filters);
+
+ ppd->num_filters = 0;
+ ppd->filters = NULL;
+ }
+}
+
+
/*
* 'ppd_free_group()' - Free a single UI group.
*/
strlcpy(copt->keyword, name, sizeof(copt->keyword));
- copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
+ copt->params = cupsArrayNew((cups_array_func_t)NULL, NULL);
cupsArrayAdd(ppd->coptions, copt);
ppd_group_t *group; /* Group */
- DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
+ DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
ppd, name, text, cg));
for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
if (i == 0)
{
- DEBUG_printf(("Adding group %s...\n", name));
+ DEBUG_printf(("8ppd_get_group: Adding group %s...", name));
if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
{
return (NULL);
}
-
+
if (ppd->num_groups == 0)
group = malloc(sizeof(ppd_group_t));
else
ppd_option_t *option; /* Option */
- DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
+ DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
group, group->name, name));
for (i = group->num_options, option = group->options; i > 0; i --, option ++)
if (ch == 0x0a)
cupsFileGetChar(fp);
}
-
- ch = '\n';
}
else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
{
*lineptr = '\0';
- DEBUG_printf(("LINE = \"%s\"\n", line));
+ DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer));
/*
- * The dynamically created PPDs for older style Mac OS X
+ * The dynamically created PPDs for older style OS X
* drivers include a large blob of data inserted as comments
* at the end of the file. As an optimization we can stop
* reading the PPD when we get to the start of this data.
*/
for (lineptr = line->buffer; *lineptr; lineptr ++)
- if (!isspace(*lineptr & 255))
+ if (*lineptr && !_cups_isspace(*lineptr))
break;
if (*lineptr)
keyptr = keyword;
- while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
+ while (*lineptr && *lineptr != ':' && !_cups_isspace(*lineptr))
{
if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
(keyptr - keyword) >= (PPD_MAX_NAME - 1))
mask |= PPD_KEYWORD;
-/* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
-
- if (isspace(*lineptr & 255))
+ if (_cups_isspace(*lineptr))
{
/*
* Get an option name...
*/
- while (isspace(*lineptr & 255))
+ while (_cups_isspace(*lineptr))
lineptr ++;
optptr = option;
- while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
+ while (*lineptr && !_cups_isspace(*lineptr) && *lineptr != ':' &&
*lineptr != '/')
{
if (*lineptr <= ' ' || *lineptr > 126 ||
*optptr = '\0';
- if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
+ if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
return (0);
}
- while (isspace(*lineptr & 255))
+ while (_cups_isspace(*lineptr))
lineptr ++;
mask |= PPD_OPTION;
-/* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
-
if (*lineptr == '/')
{
/*
*/
lineptr ++;
-
+
textptr = text;
while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
return (0);
}
-
+
mask |= PPD_TEXT;
}
-
-/* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
}
- if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
+ if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
return (0);
}
- while (isspace(*lineptr & 255))
+ while (_cups_isspace(*lineptr))
lineptr ++;
if (*lineptr == ':')
*/
lineptr ++;
- while (isspace(*lineptr & 255))
+ while (_cups_isspace(*lineptr))
lineptr ++;
strptr = lineptr + strlen(lineptr) - 1;
- while (strptr >= lineptr && isspace(*strptr & 255))
+ while (strptr >= lineptr && _cups_isspace(*strptr))
*strptr-- = '\0';
if (*strptr == '\"')
*string = _cupsStrAlloc(lineptr);
-/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
-
mask |= PPD_STRING;
}
}
/*
- * End of "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $".
+ * 'ppd_update_filters()' - Update the filters array as needed.
+ *
+ * This function re-populates the filters array with cupsFilter2 entries that
+ * have been stripped of the destination MIME media types and any maxsize hints.
+ *
+ * (All for backwards-compatibility)
+ */
+
+static int /* O - 1 on success, 0 on failure */
+ppd_update_filters(ppd_file_t *ppd,/* I - PPD file */
+ _cups_globals_t *cg) /* I - Global data */
+{
+ ppd_attr_t *attr; /* Current cupsFilter2 value */
+ char srcsuper[16], /* Source MIME media type */
+ srctype[256],
+ dstsuper[16], /* Destination MIME media type */
+ dsttype[256],
+ program[1024], /* Command to run */
+ *ptr, /* Pointer into command to run */
+ buffer[1024], /* Re-written cupsFilter value */
+ **filter; /* Current filter */
+ int cost; /* Cost of filter */
+
+
+ DEBUG_printf(("4ppd_update_filters(ppd=%p, cg=%p)", ppd, cg));
+
+ /*
+ * See if we have any cupsFilter2 lines...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) == NULL)
+ {
+ DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present.");
+ return (1);
+ }
+
+ /*
+ * Yes, free the cupsFilter-defined filters and re-build...
+ */
+
+ ppd_free_filters(ppd);
+
+ do
+ {
+ /*
+ * Parse the cupsFilter2 string:
+ *
+ * src/type dst/type cost program
+ * src/type dst/type cost maxsize(n) program
+ */
+
+ DEBUG_printf(("5ppd_update_filters: cupsFilter2=\"%s\"", attr->value));
+
+ if (sscanf(attr->value, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
+ srcsuper, srctype, dstsuper, dsttype, &cost, program) != 6)
+ {
+ DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line.");
+ cg->ppd_status = PPD_BAD_VALUE;
+
+ return (0);
+ }
+
+ DEBUG_printf(("5ppd_update_filters: srcsuper=\"%s\", srctype=\"%s\", "
+ "dstsuper=\"%s\", dsttype=\"%s\", cost=%d, program=\"%s\"",
+ srcsuper, srctype, dstsuper, dsttype, cost, program));
+
+ if (!strncmp(program, "maxsize(", 8) &&
+ (ptr = strchr(program + 8, ')')) != NULL)
+ {
+ DEBUG_puts("5ppd_update_filters: Found maxsize(nnn).");
+
+ ptr ++;
+ while (_cups_isspace(*ptr))
+ ptr ++;
+
+ _cups_strcpy(program, ptr);
+ DEBUG_printf(("5ppd_update_filters: New program=\"%s\"", program));
+ }
+
+ /*
+ * Convert to cupsFilter format:
+ *
+ * src/type cost program
+ */
+
+ snprintf(buffer, sizeof(buffer), "%s/%s %d %s", srcsuper, srctype, cost,
+ program);
+ DEBUG_printf(("5ppd_update_filters: Adding \"%s\".", buffer));
+
+ /*
+ * Add a cupsFilter-compatible string to the filters array.
+ */
+
+ if (ppd->num_filters == 0)
+ filter = malloc(sizeof(char *));
+ else
+ filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
+
+ if (filter == NULL)
+ {
+ DEBUG_puts("5ppd_update_filters: Out of memory.");
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ return (0);
+ }
+
+ ppd->filters = filter;
+ filter += ppd->num_filters;
+ ppd->num_filters ++;
+
+ *filter = _cupsStrAlloc(buffer);
+ }
+ while ((attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL);
+
+ DEBUG_puts("5ppd_update_filters: Completed OK.");
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
*/