#include "ppd.h"
#include <stdlib.h>
#include <ctype.h>
#include "string.h"
#include "language.h"
#include "globals.h"
#include "debug.h"
#if defined(WIN32) || defined(__EMX__)
# define READ_BINARY "rb"
# define WRITE_BINARY "wb"
#else
# define READ_BINARY "r"
# define WRITE_BINARY "w"
#endif
#define ppd_free(p) if (p) free(p)
#define PPD_KEYWORD 1
#define PPD_OPTION 2
#define PPD_TEXT 4
#define PPD_STRING 8
#define ppd_status (_cups_globals()->ppd_status)
#define ppd_line (_cups_globals()->ppd_line)
#define ppd_conform (_cups_globals()->ppd_conform)
static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
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
static int ppd_decode(char *string);
#ifndef __APPLE__
static void ppd_fix(char *string);
#else
# define ppd_fix(s)
#endif
static void ppd_free_group(ppd_group_t *group);
static void ppd_free_option(ppd_option_t *option);
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, int ignoreblank);
int
_ppd_attr_compare(ppd_attr_t **a,
ppd_attr_t **b)
{
int ret;
if ((ret = strcasecmp((*a)->name, (*b)->name)) != 0)
return (ret);
else if ((*a)->spec[0] && (*b)->spec[0])
return (strcasecmp((*a)->spec, (*b)->spec));
else
return (0);
}
void
ppdClose(ppd_file_t *ppd)
{
int i;
ppd_emul_t *emul;
ppd_group_t *group;
char **font;
char **filter;
ppd_attr_t **attr;
if (ppd == NULL)
return;
ppd_free(ppd->patches);
ppd_free(ppd->jcl_begin);
ppd_free(ppd->jcl_end);
ppd_free(ppd->jcl_ps);
if (ppd->num_emulations > 0)
{
for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
{
ppd_free(emul->start);
ppd_free(emul->stop);
}
ppd_free(ppd->emulations);
}
if (ppd->num_groups > 0)
{
for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
ppd_free_group(group);
ppd_free(ppd->groups);
}
if (ppd->num_sizes > 0)
{
ppd_free(ppd->sizes);
}
if (ppd->num_consts > 0)
{
ppd_free(ppd->consts);
}
if (ppd->num_filters > 0)
{
for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
{
ppd_free(*filter);
}
ppd_free(ppd->filters);
}
if (ppd->num_fonts > 0)
{
for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
{
ppd_free(*font);
}
ppd_free(ppd->fonts);
}
if (ppd->num_profiles > 0)
{
ppd_free(ppd->profiles);
}
if (ppd->num_attrs > 0)
{
for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
{
ppd_free((*attr)->value);
ppd_free(*attr);
}
ppd_free(ppd->attrs);
}
ppd_free(ppd);
}
const char *
ppdErrorString(ppd_status_t status)
{
static const char * const messages[] =
{
"OK",
"Unable to open PPD file",
"NULL PPD file pointer",
"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_ILLEGAL_WHITESPACE)
return ("Unknown");
else
return (messages[status]);
}
ppd_status_t
ppdLastError(int *line)
{
if (line)
*line = ppd_line;
return (ppd_status);
}
ppd_file_t *
ppdOpen(FILE *fp)
{
char *oldlocale;
int i, j, k, m;
int count;
ppd_file_t *ppd;
ppd_group_t *group,
*subgroup;
ppd_option_t *option;
ppd_choice_t *choice;
ppd_const_t *constraint;
ppd_size_t *size;
int mask;
char keyword[PPD_MAX_NAME],
name[PPD_MAX_NAME],
text[PPD_MAX_LINE],
*string,
*sptr,
*nameptr,
*temp,
**tempfonts;
float order;
ppd_section_t section;
ppd_profile_t *profile;
char **filter;
cups_lang_t *language;
int ui_keyword;
static const char * const ui_keywords[] =
{
#ifdef __APPLE__
"PageRegion",
"PageSize"
#else
"BlackSubstitution",
"Booklet",
"Collate",
"ManualFeed",
"MirrorPrint",
"NegativePrint",
"Sorter",
"TraySwitch",
"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"
#endif
};
ppd_status = PPD_OK;
ppd_line = 0;
if (fp == NULL)
{
ppd_status = PPD_NULL_FILE;
return (NULL);
}
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 ||
string == NULL || string[0] != '4')
{
if (ppd_status == PPD_OK)
ppd_status = PPD_MISSING_PPDADOBE4;
ppd_free(string);
return (NULL);
}
DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
ppd_free(string);
if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
{
ppd_status = PPD_ALLOC_ERROR;
return (NULL);
}
ppd->language_level = 1;
ppd->color_device = 0;
ppd->colorspace = PPD_CS_GRAY;
ppd->landscape = -90;
language = cupsLangDefault();
#ifdef LC_NUMERIC
oldlocale = _cupsSaveLocale(LC_NUMERIC, "C");
#else
oldlocale = _cupsSaveLocale(LC_ALL, "C");
#endif
group = NULL;
subgroup = NULL;
option = NULL;
choice = NULL;
ui_keyword = 0;
while ((mask = ppd_read(fp, keyword, name, text, &string, 1)) != 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);
}
puts("");
#endif
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)
{
ppd_status = PPD_MISSING_VALUE;
goto error;
}
if (ui_keyword)
{
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])))
{
ui_keyword = 1;
DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n",
keyword));
if (!group)
{
#ifndef __APPLE__
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
#endif
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;
}
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->lang_encoding = string;
else if (strcmp(keyword, "LanguageVersion") == 0)
ppd->lang_version = string;
else if (strcmp(keyword, "Manufacturer") == 0)
ppd->manufacturer = string;
else if (strcmp(keyword, "ModelName") == 0)
ppd->modelname = string;
else if (strcmp(keyword, "Protocols") == 0)
ppd->protocols = string;
else if (strcmp(keyword, "PCFileName") == 0)
ppd->pcfilename = string;
else if (strcmp(keyword, "NickName") == 0)
ppd->nickname = string;
else if (strcmp(keyword, "Product") == 0)
ppd->product = string;
else if (strcmp(keyword, "ShortNickName") == 0)
ppd->shortnickname = string;
else if (strcmp(keyword, "TTRasterizer") == 0)
ppd->ttrasterizer = string;
else if (strcmp(keyword, "JCLBegin") == 0)
{
ppd->jcl_begin = strdup(string);
ppd_decode(ppd->jcl_begin);
}
else if (strcmp(keyword, "JCLEnd") == 0)
{
ppd->jcl_end = strdup(string);
ppd_decode(ppd->jcl_end);
}
else if (strcmp(keyword, "JCLToPSInterpreter") == 0)
{
ppd->jcl_ps = strdup(string);
ppd_decode(ppd->jcl_ps);
}
else if (strcmp(keyword, "AccurateScreensSupport") == 0)
ppd->accurate_screens = strcmp(string, "True") == 0;
else if (strcmp(keyword, "ColorDevice") == 0)
ppd->color_device = strcmp(string, "True") == 0;
else if (strcmp(keyword, "ContoneOnly") == 0)
ppd->contone_only = strcmp(string, "True") == 0;
else if (strcmp(keyword, "cupsFlipDuplex") == 0)
ppd->flip_duplex = strcmp(string, "True") == 0;
else if (strcmp(keyword, "cupsManualCopies") == 0)
ppd->manual_copies = strcmp(string, "True") == 0;
else if (strcmp(keyword, "cupsModelNumber") == 0)
ppd->model_number = atoi(string);
else if (strcmp(keyword, "cupsColorProfile") == 0)
{
if (ppd->num_profiles == 0)
profile = malloc(sizeof(ppd_profile_t));
else
profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
(ppd->num_profiles + 1));
ppd->profiles = profile;
profile += ppd->num_profiles;
ppd->num_profiles ++;
memset(profile, 0, sizeof(ppd_profile_t));
strlcpy(profile->resolution, name, sizeof(profile->resolution));
strlcpy(profile->media_type, text, sizeof(profile->media_type));
sscanf(string, "%f%f%f%f%f%f%f%f%f%f%f", &(profile->density),
&(profile->gamma),
profile->matrix[0] + 0, profile->matrix[0] + 1,
profile->matrix[0] + 2, profile->matrix[1] + 0,
profile->matrix[1] + 1, profile->matrix[1] + 2,
profile->matrix[2] + 0, profile->matrix[2] + 1,
profile->matrix[2] + 2);
}
else if (strcmp(keyword, "cupsFilter") == 0)
{
if (ppd->num_filters == 0)
filter = malloc(sizeof(char *));
else
filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
if (filter == NULL)
{
ppd_free(filter);
ppd_status = PPD_ALLOC_ERROR;
goto error;
}
ppd->filters = filter;
filter += ppd->num_filters;
ppd->num_filters ++;
*filter = string;
string = NULL;
}
else if (strcmp(keyword, "Throughput") == 0)
ppd->throughput = atoi(string);
else if (strcmp(keyword, "Font") == 0)
{
if (ppd->num_fonts == 0)
tempfonts = (char **)malloc(sizeof(char *));
else
tempfonts = (char **)realloc(ppd->fonts,
sizeof(char *) * (ppd->num_fonts + 1));
if (tempfonts == NULL)
{
ppd_status = PPD_ALLOC_ERROR;
goto error;
}
ppd->fonts = tempfonts;
ppd->fonts[ppd->num_fonts] = strdup(name);
ppd->num_fonts ++;
}
else if (strcmp(keyword, "ParamCustomPageSize") == 0)
{
if (strcmp(name, "Width") == 0)
sscanf(string, "%*s%*s%f%f", ppd->custom_min + 0,
ppd->custom_max + 0);
else if (strcmp(name, "Height") == 0)
sscanf(string, "%*s%*s%f%f", ppd->custom_min + 1,
ppd->custom_max + 1);
}
else if (strcmp(keyword, "HWMargins") == 0)
sscanf(string, "%f%f%f%f", ppd->custom_margins + 0,
ppd->custom_margins + 1, ppd->custom_margins + 2,
ppd->custom_margins + 3);
else if (strcmp(keyword, "CustomPageSize") == 0 &&
strcmp(name, "True") == 0)
{
DEBUG_puts("Processing CustomPageSize...");
if (!ppd->variable_sizes)
{
ppd->variable_sizes = 1;
ppd_add_size(ppd, "Custom");
if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
{
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!");
goto error;
}
if ((option = ppd_get_option(temp, "PageSize")) == NULL)
{
DEBUG_puts("Unable to get PageSize option!");
ppd_status = PPD_ALLOC_ERROR;
goto error;
}
}
if ((choice = ppd_add_choice(option, "Custom")) == NULL)
{
DEBUG_puts("Unable to add Custom choice!");
ppd_status = PPD_ALLOC_ERROR;
goto error;
}
strlcpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
sizeof(choice->text));
option = NULL;
}
if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
{
DEBUG_puts("Unable to find PageSize option!");
ppd_status = PPD_INTERNAL_ERROR;
goto error;
}
if ((choice = ppdFindChoice(option, "Custom")) == NULL)
{
DEBUG_puts("Unable to find Custom choice!");
ppd_status = PPD_INTERNAL_ERROR;
goto error;
}
choice->code = string;
option = NULL;
string = NULL;
}
else if (strcmp(keyword, "LandscapeOrientation") == 0)
{
if (strcmp(string, "Minus90") == 0)
ppd->landscape = -90;
else if (strcmp(string, "Plus90") == 0)
ppd->landscape = 90;
}
else if (strcmp(keyword, "Emulators") == 0)
{
for (count = 1, sptr = string; sptr != NULL;)
if ((sptr = strchr(sptr, ' ')) != NULL)
{
count ++;
while (*sptr == ' ')
sptr ++;
}
ppd->num_emulations = count;
ppd->emulations = calloc(count, sizeof(ppd_emul_t));
for (i = 0, sptr = string; i < count; i ++)
{
for (nameptr = ppd->emulations[i].name;
*sptr != '\0' && *sptr != ' ';
sptr ++)
if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
*nameptr++ = *sptr;
*nameptr = '\0';
while (*sptr == ' ')
sptr ++;
}
}
else if (strncmp(keyword, "StartEmulator_", 14) == 0)
{
ppd_decode(string);
for (i = 0; i < ppd->num_emulations; i ++)
if (strcmp(keyword + 14, ppd->emulations[i].name) == 0)
{
ppd->emulations[i].start = string;
string = NULL;
}
}
else if (strncmp(keyword, "StopEmulator_", 13) == 0)
{
ppd_decode(string);
for (i = 0; i < ppd->num_emulations; i ++)
if (strcmp(keyword + 13, ppd->emulations[i].name) == 0)
{
ppd->emulations[i].stop = string;
string = NULL;
}
}
else if (strcmp(keyword, "JobPatchFile") == 0)
{
if (ppd->patches == NULL)
ppd->patches = strdup(string);
else
{
temp = realloc(ppd->patches, strlen(ppd->patches) +
strlen(string) + 1);
if (temp == NULL)
{
ppd_status = PPD_ALLOC_ERROR;
goto error;
}
ppd->patches = temp;
strcpy(ppd->patches + strlen(ppd->patches), string);
}
}
else if (strcmp(keyword, "OpenUI") == 0)
{
if (option && ppd_conform == PPD_CONFORM_STRICT)
{
ppd_status = PPD_NESTED_OPEN_UI;
goto error;
}
if (name[0] == '*')
cups_strcpy(name, name + 1);
for (i = strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
name[i] = '\0';
DEBUG_printf(("OpenUI of %s in group %s...\n", name,
group ? group->text : "(null)"));
if (subgroup != NULL)
option = ppd_get_option(subgroup, name);
else if (group == NULL)
{
#ifndef __APPLE__
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
#endif
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, name);
group = NULL;
}
else
option = ppd_get_option(group, name);
if (option == NULL)
{
ppd_status = PPD_ALLOC_ERROR;
goto error;
}
if (string && strcmp(string, "PickMany") == 0)
option->ui = PPD_UI_PICKMANY;
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));
ppd_fix(option->text);
}
else
{
if (strcmp(name, "PageSize") == 0)
strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SIZE),
sizeof(option->text));
else if (strcmp(name, "MediaType") == 0)
strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_TYPE),
sizeof(option->text));
else if (strcmp(name, "InputSlot") == 0)
strlcpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SOURCE),
sizeof(option->text));
else if (strcmp(name, "ColorModel") == 0)
strlcpy(option->text, cupsLangString(language, CUPS_MSG_OUTPUT_MODE),
sizeof(option->text));
else if (strcmp(name, "Resolution") == 0)
strlcpy(option->text, cupsLangString(language, CUPS_MSG_RESOLUTION),
sizeof(option->text));
else
strlcpy(option->text, name, sizeof(option->text));
}
option->section = PPD_ORDER_ANY;
ppd_free(string);
string = NULL;
}
else if (strcmp(keyword, "JCLOpenUI") == 0)
{
if (option && ppd_conform == PPD_CONFORM_STRICT)
{
ppd_status = PPD_NESTED_OPEN_UI;
goto error;
}
group = ppd_get_group(ppd, "JCL", "JCL");
if (group == NULL)
goto error;
if (name[0] == '*')
cups_strcpy(name, name + 1);
option = ppd_get_option(group, name);
if (option == NULL)
{
ppd_status = PPD_ALLOC_ERROR;
goto error;
}
if (string && strcmp(string, "PickMany") == 0)
option->ui = PPD_UI_PICKMANY;
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
{
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)
{
if (group != NULL)
{
ppd_status = PPD_NESTED_OPEN_GROUP;
goto error;
}
if (!string)
{
ppd_status = PPD_BAD_OPEN_GROUP;
goto error;
}
if ((sptr = strchr(string, '/')) != NULL)
*sptr++ = '\0';
else
sptr = string;
ppd_decode(sptr);
ppd_fix(sptr);
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)
{
ppd_status = PPD_BAD_ORDER_DEPENDENCY;
goto error;
}
if (keyword[0] == '*')
cups_strcpy(keyword, keyword + 1);
if (strcmp(name, "ExitServer") == 0)
section = PPD_ORDER_EXIT;
else if (strcmp(name, "Prolog") == 0)
section = PPD_ORDER_PROLOG;
else if (strcmp(name, "DocumentSetup") == 0)
section = PPD_ORDER_DOCUMENT;
else if (strcmp(name, "PageSetup") == 0)
section = PPD_ORDER_PAGE;
else if (strcmp(name, "JCLSetup") == 0)
section = PPD_ORDER_JCL;
else
section = PPD_ORDER_ANY;
if (option == NULL)
{
ppd_group_t *temp;
for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
if (temp->text[0] == '\0')
break;
if (i > 0)
for (i = 0; i < temp->num_options; i ++)
if (strcmp(keyword, temp->options[i].keyword) == 0)
{
temp->options[i].section = section;
temp->options[i].order = order;
break;
}
}
else
{
option->section = section;
option->order = order;
}
ppd_free(string);
string = NULL;
}
else if (strncmp(keyword, "Default", 7) == 0)
{
if (string == NULL)
continue;
if (strchr(string, '/') != NULL)
*strchr(string, '/') = '\0';
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 (option && strcmp(keyword + 7, option->keyword) == 0)
{
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
{
ppd_option_t *toption;
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, "UIConstraints") == 0 ||
strcmp(keyword, "NonUIConstraints") == 0)
{
if (ppd->num_consts == 0)
constraint = calloc(1, sizeof(ppd_const_t));
else
constraint = realloc(ppd->consts,
(ppd->num_consts + 1) * sizeof(ppd_const_t));
if (constraint == NULL)
{
ppd_status = PPD_ALLOC_ERROR;
goto error;
}
ppd->consts = constraint;
constraint += ppd->num_consts;
ppd->num_consts ++;
switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
constraint->choice1, constraint->option2,
constraint->choice2))
{
case 0 :
case 1 :
ppd_status = PPD_BAD_UI_CONSTRAINTS;
goto error;
case 2 :
if (constraint->option1[0] == '*')
cups_strcpy(constraint->option1, constraint->option1 + 1);
if (constraint->choice1[0] == '*')
cups_strcpy(constraint->option2, constraint->choice1 + 1);
else
cups_strcpy(constraint->option2, constraint->choice1);
constraint->choice1[0] = '\0';
constraint->choice2[0] = '\0';
break;
case 3 :
if (constraint->option1[0] == '*')
cups_strcpy(constraint->option1, constraint->option1 + 1);
if (constraint->choice1[0] == '*')
{
cups_strcpy(constraint->choice2, constraint->option2);
cups_strcpy(constraint->option2, constraint->choice1 + 1);
constraint->choice1[0] = '\0';
}
else
{
if (constraint->option2[0] == '*')
cups_strcpy(constraint->option2, constraint->option2 + 1);
constraint->choice2[0] = '\0';
}
break;
case 4 :
if (constraint->option1[0] == '*')
cups_strcpy(constraint->option1, constraint->option1 + 1);
if (constraint->option2[0] == '*')
cups_strcpy(constraint->option2, constraint->option2 + 1);
break;
}
ppd_free(string);
string = NULL;
}
else if (strcmp(keyword, "PaperDimension") == 0)
{
if ((size = ppdPageSize(ppd, name)) == NULL)
size = ppd_add_size(ppd, name);
if (size == NULL)
{
ppd_status = PPD_ALLOC_ERROR;
goto error;
}
sscanf(string, "%f%f", &(size->width), &(size->length));
ppd_free(string);
string = NULL;
}
else if (strcmp(keyword, "ImageableArea") == 0)
{
if ((size = ppdPageSize(ppd, name)) == NULL)
size = ppd_add_size(ppd, name);
if (size == NULL)
{
ppd_status = PPD_ALLOC_ERROR;
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)) ==
(PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
strcmp(keyword, option->keyword) == 0)
{
DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
if (strcmp(keyword, "PageSize") == 0)
{
if (ppdPageSize(ppd, name) == NULL)
ppd_add_size(ppd, name);
}
choice = ppd_add_choice(option, name);
if (mask & PPD_TEXT)
{
strlcpy(choice->text, text, sizeof(choice->text));
ppd_fix(choice->text);
}
else if (strcmp(name, "True") == 0)
strcpy(choice->text, "Yes");
else if (strcmp(name, "False") == 0)
strcpy(choice->text, "No");
else
strlcpy(choice->text, name, sizeof(choice->text));
if (option->section == PPD_ORDER_JCL)
ppd_decode(string);
choice->code = string;
string = NULL;
}
if (string &&
(mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
ppd_add_attr(ppd, keyword, name, text, string);
else
{
ppd_free(string);
}
}
cupsLangFree(language);
#ifdef LC_NUMERIC
_cupsRestoreLocale(LC_NUMERIC, oldlocale);
#else
_cupsRestoreLocale(LC_ALL, oldlocale);
#endif
#ifdef DEBUG
if (!feof(fp))
printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
#endif
if (ppd_status != PPD_OK)
{
ppdClose(ppd);
return (NULL);
}
#ifndef __APPLE__
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] ||
!strncasecmp(option->choices[i].choice, "Auto", 4))
break;
if (i >= option->num_choices)
{
choice = ppd_add_choice(option, "Auto");
strlcpy(choice->text, cupsLangString(language, CUPS_MSG_AUTO),
sizeof(choice->text));
choice->code = NULL;
}
}
#endif
#ifndef __APPLE__
qsort(ppd->groups, ppd->num_groups, sizeof(ppd_group_t),
(int (*)(const void *, const void *))ppd_compare_groups);
#endif
for (i = ppd->num_groups, group = ppd->groups;
i > 0;
i --, group ++)
{
#ifndef __APPLE__
qsort(group->options, group->num_options, sizeof(ppd_option_t),
(int (*)(const void *, const void *))ppd_compare_options);
#endif
for (j = group->num_options, option = group->options;
j > 0;
j --, option ++)
{
for (k = 0; k < option->num_choices; k ++)
option->choices[k].option = (void *)option;
}
#ifndef __APPLE__
qsort(group->subgroups, group->num_subgroups, sizeof(ppd_group_t),
(int (*)(const void *, const void *))ppd_compare_groups);
#endif
for (j = group->num_subgroups, subgroup = group->subgroups;
j > 0;
j --, subgroup ++)
{
#ifndef __APPLE__
qsort(subgroup->options, subgroup->num_options, sizeof(ppd_option_t),
(int (*)(const void *, const void *))ppd_compare_options);
#endif
for (k = group->num_options, option = group->options;
k > 0;
k --, option ++)
{
for (m = 0; m < option->num_choices; m ++)
option->choices[m].option = (void *)option;
}
}
}
if (ppd->num_attrs > 1)
#ifndef __APPLE__
qsort(ppd->attrs, ppd->num_attrs, sizeof(ppd_attr_t *),
(int (*)(const void *, const void *))_ppd_attr_compare);
#else
mergesort(ppd->attrs, ppd->num_attrs, sizeof(ppd_attr_t *),
(int (*)(const void *, const void *))_ppd_attr_compare);
#endif
return (ppd);
error:
ppd_free(string);
ppdClose(ppd);
cupsLangFree(language);
#ifdef LC_NUMERIC
_cupsRestoreLocale(LC_NUMERIC, oldlocale);
#else
_cupsRestoreLocale(LC_ALL, oldlocale);
#endif
return (NULL);
}
ppd_file_t *
ppdOpenFd(int fd)
{
FILE *fp;
ppd_file_t *ppd;
ppd_line = 0;
if (fd < 0)
{
ppd_status = PPD_NULL_FILE;
return (NULL);
}
if ((fp = fdopen(fd, "r")) != NULL)
{
setbuf(fp, NULL);
ppd = ppdOpen(fp);
fclose(fp);
}
else
{
ppd_status = PPD_FILE_OPEN_ERROR;
ppd = NULL;
}
return (ppd);
}
ppd_file_t *
ppdOpenFile(const char *filename)
{
FILE *fp;
ppd_file_t *ppd;
ppd_line = 0;
if (filename == NULL)
{
ppd_status = PPD_NULL_FILE;
return (NULL);
}
if ((fp = fopen(filename, "r")) != NULL)
{
ppd = ppdOpen(fp);
fclose(fp);
}
else
{
ppd_status = PPD_FILE_OPEN_ERROR;
ppd = NULL;
}
return (ppd);
}
void
ppdSetConformance(ppd_conform_t c)
{
ppd_conform = c;
}
static ppd_attr_t *
ppd_add_attr(ppd_file_t *ppd,
const char *name,
const char *spec,
const char *text,
const char *value)
{
ppd_attr_t **ptr,
*temp;
if (ppd == NULL || name == NULL || spec == NULL)
return (NULL);
if (ppd->num_attrs == 0)
ptr = malloc(sizeof(ppd_attr_t *));
else
ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
if (ptr == NULL)
return (NULL);
ppd->attrs = ptr;
ptr += ppd->num_attrs;
if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
return (NULL);
*ptr = temp;
ppd->num_attrs ++;
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;
return (temp);
}
static ppd_choice_t *
ppd_add_choice(ppd_option_t *option,
const char *name)
{
ppd_choice_t *choice;
if (option->num_choices == 0)
choice = malloc(sizeof(ppd_choice_t));
else
choice = realloc(option->choices,
sizeof(ppd_choice_t) * (option->num_choices + 1));
if (choice == NULL)
return (NULL);
option->choices = choice;
choice += option->num_choices;
option->num_choices ++;
memset(choice, 0, sizeof(ppd_choice_t));
strlcpy(choice->choice, name, sizeof(choice->choice));
return (choice);
}
static ppd_size_t *
ppd_add_size(ppd_file_t *ppd,
const char *name)
{
ppd_size_t *size;
if (ppd->num_sizes == 0)
size = malloc(sizeof(ppd_size_t));
else
size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
if (size == NULL)
return (NULL);
ppd->sizes = size;
size += ppd->num_sizes;
ppd->num_sizes ++;
memset(size, 0, sizeof(ppd_size_t));
strlcpy(size->name, name, sizeof(size->name));
return (size);
}
#ifndef __APPLE__
static int
ppd_compare_groups(ppd_group_t *g0,
ppd_group_t *g1)
{
return (strcasecmp(g0->text, g1->text));
}
static int
ppd_compare_options(ppd_option_t *o0,
ppd_option_t *o1)
{
return (strcasecmp(o0->text, o1->text));
}
#endif
static int
ppd_decode(char *string)
{
char *inptr,
*outptr;
inptr = string;
outptr = string;
while (*inptr != '\0')
if (*inptr == '<' && isxdigit(inptr[1] & 255))
{
inptr ++;
while (isxdigit(*inptr & 255))
{
if (isalpha(*inptr))
*outptr = (tolower(*inptr) - 'a' + 10) << 4;
else
*outptr = (*inptr - '0') << 4;
inptr ++;
if (!isxdigit(*inptr & 255))
break;
if (isalpha(*inptr))
*outptr |= tolower(*inptr) - 'a' + 10;
else
*outptr |= *inptr - '0';
inptr ++;
outptr ++;
}
while (*inptr != '>' && *inptr != '\0')
inptr ++;
while (*inptr == '>')
inptr ++;
}
else
*outptr++ = *inptr++;
*outptr = '\0';
return (outptr - string);
}
#ifndef __APPLE__
static void
ppd_fix(char *string)
{
unsigned char *p;
static const unsigned char lut[32] =
{
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
'l',
'`',
'\'',
'^',
'~',
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
'\"',
0x20,
0x20
};
for (p = (unsigned char *)string; *p; p ++)
if (*p >= 0x80 && *p < 0xa0)
*p = lut[*p - 0x80];
}
#endif
static void
ppd_free_group(ppd_group_t *group)
{
int i;
ppd_option_t *option;
ppd_group_t *subgroup;
if (group->num_options > 0)
{
for (i = group->num_options, option = group->options;
i > 0;
i --, option ++)
ppd_free_option(option);
ppd_free(group->options);
}
if (group->num_subgroups > 0)
{
for (i = group->num_subgroups, subgroup = group->subgroups;
i > 0;
i --, subgroup ++)
ppd_free_group(subgroup);
ppd_free(group->subgroups);
}
}
static void
ppd_free_option(ppd_option_t *option)
{
int i;
ppd_choice_t *choice;
if (option->num_choices > 0)
{
for (i = option->num_choices, choice = option->choices;
i > 0;
i --, choice ++)
{
ppd_free(choice->code);
}
ppd_free(option->choices);
}
}
static ppd_group_t *
ppd_get_group(ppd_file_t *ppd,
const char *name,
const char *text)
{
int i;
ppd_group_t *group;
DEBUG_printf(("ppd_get_group(%p, \"%s\")\n", ppd, name));
for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
if (strcmp(group->name, name) == 0)
break;
if (i == 0)
{
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
group = realloc(ppd->groups,
(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;
ppd->num_groups ++;
memset(group, 0, sizeof(ppd_group_t));
strlcpy(group->name, name, sizeof(group->name));
strlcpy(group->text, text, sizeof(group->text));
}
return (group);
}
static ppd_option_t *
ppd_get_option(ppd_group_t *group,
const char *name)
{
int i;
ppd_option_t *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;
if (i == 0)
{
if (group->num_options == 0)
option = malloc(sizeof(ppd_option_t));
else
option = realloc(group->options,
(group->num_options + 1) * sizeof(ppd_option_t));
if (option == NULL)
return (NULL);
group->options = option;
option += group->num_options;
group->num_options ++;
memset(option, 0, sizeof(ppd_option_t));
strlcpy(option->keyword, name, sizeof(option->keyword));
}
return (option);
}
static int
ppd_read(FILE *fp,
char *keyword,
char *option,
char *text,
char **string,
int ignoreblank)
{
int ch,
col,
colon,
endquote,
mask,
startline,
textlen;
char *keyptr,
*optptr,
*textptr,
*strptr,
*lineptr,
line[65536];
if (fp == NULL || keyword == NULL || option == NULL || text == NULL ||
string == NULL)
return (0);
*string = NULL;
col = 0;
startline = ppd_line + 1;
do
{
lineptr = line;
endquote = 0;
colon = 0;
while ((ch = getc(fp)) != EOF &&
(lineptr - line) < (sizeof(line) - 1))
{
if (ch == '\r' || ch == '\n')
{
ppd_line ++;
col = 0;
if (ch == '\r')
{
if ((ch = getc(fp)) == EOF)
break;
if (ch != 0x0a)
ungetc(ch, fp);
}
if (lineptr == line && ignoreblank)
continue;
ch = '\n';
if (!endquote)
break;
*lineptr++ = '\n';
}
else if (ch < ' ' && ch != '\t' && ppd_conform == PPD_CONFORM_STRICT)
{
ppd_line = startline;
ppd_status = PPD_ILLEGAL_CHARACTER;
return (0);
}
else if (ch != 0x1a)
{
*lineptr++ = ch;
col ++;
if (col > (PPD_MAX_LINE - 1))
{
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)
{
while ((ch = getc(fp)) != EOF)
if (ch == '\"')
break;
else if (ch == '\r' || ch == '\n')
{
ppd_line ++;
col = 0;
if (ch == '\r')
{
if ((ch = getc(fp)) == EOF)
break;
if (ch != 0x0a)
ungetc(ch, fp);
}
ch = '\n';
}
else if (ch < ' ' && ch != '\t' && ppd_conform == PPD_CONFORM_STRICT)
{
ppd_line = startline;
ppd_status = PPD_ILLEGAL_CHARACTER;
return (0);
}
else if (ch != 0x1a)
{
col ++;
if (col > (PPD_MAX_LINE - 1))
{
ppd_line = startline;
ppd_status = PPD_LINE_TOO_LONG;
return (0);
}
}
}
if (ch != '\n')
{
while ((ch = getc(fp)) != EOF)
if (ch == '\r' || ch == '\n')
{
ppd_line ++;
col = 0;
if (ch == '\r')
{
if ((ch = getc(fp)) == EOF)
break;
if (ch != 0x0a)
ungetc(ch, fp);
}
break;
}
else if (ch < ' ' && ch != '\t' && ppd_conform == PPD_CONFORM_STRICT)
{
ppd_line = startline;
ppd_status = PPD_ILLEGAL_CHARACTER;
return (0);
}
else if (ch != 0x1a)
{
col ++;
if (col > (PPD_MAX_LINE - 1))
{
ppd_line = startline;
ppd_status = PPD_LINE_TOO_LONG;
return (0);
}
}
}
if (lineptr > line && lineptr[-1] == '\n')
lineptr --;
*lineptr = '\0';
DEBUG_printf(("LINE = \"%s\"\n", line));
#ifdef __APPLE__
if (!strcmp(line, "*%APLWORKSET START"))
return (0);
#endif
if (ch == EOF && lineptr == line)
return (0);
mask = 0;
lineptr = line + 1;
keyword[0] = '\0';
option[0] = '\0';
text[0] = '\0';
*string = NULL;
if ((!line[0] ||
strncmp(line, "*%", 2) == 0 ||
strcmp(line, "*End") == 0) &&
ignoreblank)
{
startline = ppd_line + 1;
continue;
}
if (strcmp(line, "*") == 0)
{
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] != '*')
{
#ifndef __APPLE__
if (ppd_conform == PPD_CONFORM_STRICT)
{
ppd_status = PPD_MISSING_ASTERISK;
return (0);
}
#endif
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);
}
keyptr = keyword;
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';
if (strcmp(keyword, "End") == 0)
continue;
mask |= PPD_KEYWORD;
if (isspace(*lineptr & 255))
{
while (isspace(*lineptr & 255))
lineptr ++;
optptr = option;
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;
if (*lineptr == '/')
{
lineptr ++;
textptr = text;
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';
textlen = ppd_decode(text);
if (textlen > PPD_MAX_TEXT && ppd_conform == PPD_CONFORM_STRICT)
{
ppd_status = PPD_ILLEGAL_TRANSLATION;
return (0);
}
mask |= PPD_TEXT;
}
}
if (isspace(*lineptr & 255) && ppd_conform == PPD_CONFORM_STRICT)
{
ppd_status = PPD_ILLEGAL_WHITESPACE;
return (0);
}
while (isspace(*lineptr & 255))
lineptr ++;
if (*lineptr == ':')
{
lineptr ++;
while (isspace(*lineptr & 255))
lineptr ++;
strptr = lineptr + strlen(lineptr) - 1;
while (strptr >= lineptr && isspace(*strptr & 255))
*strptr-- = '\0';
if (*strptr == '\"')
{
*string = malloc(strlen(lineptr) + 1);
strptr = *string;
for (; *lineptr != '\0'; lineptr ++)
if (*lineptr != '\"')
*strptr++ = *lineptr;
*strptr = '\0';
}
else
*string = strdup(lineptr);
mask |= PPD_STRING;
}
}
while (mask == 0);
return (mask);
}