#include "ppd.h"
#include <stdlib.h>
#include <ctype.h>
#include "string.h"
#include "language.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 safe_free(p) if (p) free(p)
#define PPD_KEYWORD 1
#define PPD_OPTION 2
#define PPD_TEXT 4
#define PPD_STRING 8
#ifndef __APPLE__
static int compare_strings(char *s, char *t);
static int compare_groups(ppd_group_t *g0, ppd_group_t *g1);
static int compare_options(ppd_option_t *o0, ppd_option_t *o1);
static int compare_choices(ppd_choice_t *c0, ppd_choice_t *c1);
#endif // __APPLE__
static int ppd_read(FILE *fp, char *keyword, char *option,
char *text, char **string);
static void ppd_decode(char *string);
static void ppd_fix(char *string);
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, char *name);
static ppd_option_t *ppd_get_option(ppd_group_t *group, char *name);
static ppd_choice_t *ppd_add_choice(ppd_option_t *option, char *name);
void
ppdClose(ppd_file_t *ppd)
{
int i;
ppd_emul_t *emul;
ppd_group_t *group;
char **font;
char **filter;
if (ppd == NULL)
return;
safe_free(ppd->patches);
safe_free(ppd->jcl_begin);
safe_free(ppd->jcl_ps);
safe_free(ppd->jcl_end);
safe_free(ppd->lang_encoding);
safe_free(ppd->lang_version);
safe_free(ppd->modelname);
safe_free(ppd->ttrasterizer);
safe_free(ppd->manufacturer);
safe_free(ppd->product);
safe_free(ppd->nickname);
safe_free(ppd->shortnickname);
if (ppd->num_emulations > 0)
{
for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
{
safe_free(emul->start);
safe_free(emul->stop);
}
safe_free(ppd->emulations);
}
if (ppd->num_groups > 0)
{
for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
ppd_free_group(group);
safe_free(ppd->groups);
}
if (ppd->num_sizes > 0)
safe_free(ppd->sizes);
if (ppd->num_consts > 0)
safe_free(ppd->consts);
if (ppd->num_filters > 0)
{
for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
safe_free(*filter);
safe_free(ppd->filters);
}
if (ppd->num_fonts > 0)
{
for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
safe_free(*font);
safe_free(ppd->fonts);
}
if (ppd->num_profiles > 0)
safe_free(ppd->profiles);
safe_free(ppd);
}
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);
safe_free(group->options);
}
if (group->num_subgroups > 0)
{
for (i = group->num_subgroups, subgroup = group->subgroups;
i > 0;
i --, subgroup ++)
ppd_free_group(subgroup);
safe_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 ++)
safe_free(choice->code);
safe_free(option->choices);
}
}
static ppd_group_t *
ppd_get_group(ppd_file_t *ppd,
char *name)
{
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->text, name) == 0)
break;
if (i == 0)
{
DEBUG_printf(("Adding group %s...\n", name));
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)
return (NULL);
ppd->groups = group;
group += ppd->num_groups;
ppd->num_groups ++;
memset(group, 0, sizeof(ppd_group_t));
strlcpy(group->text, name, sizeof(group->text));
}
return (group);
}
static ppd_option_t *
ppd_get_option(ppd_group_t *group,
char *name)
{
int i;
ppd_option_t *option;
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 ppd_choice_t *
ppd_add_choice(ppd_option_t *option,
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,
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);
}
ppd_file_t *
ppdOpen(FILE *fp)
{
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;
language = cupsLangDefault();
if (fp == NULL)
return (NULL);
mask = ppd_read(fp, keyword, name, text, &string);
if (mask == 0 ||
strcmp(keyword, "PPD-Adobe") != 0 ||
string == NULL || string[0] != '4')
{
safe_free(string);
return (NULL);
}
DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
safe_free(string);
if ((ppd = calloc(sizeof(ppd_file_t), 1)) == NULL)
return (NULL);
ppd->language_level = 1;
ppd->color_device = 0;
ppd->colorspace = PPD_CS_GRAY;
ppd->landscape = -90;
group = NULL;
subgroup = NULL;
option = NULL;
choice = NULL;
while ((mask = ppd_read(fp, keyword, name, text, &string)) != 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") != 0 &&
strcmp(keyword, "JCLCloseUI") != 0 &&
strcmp(keyword, "CloseGroup") != 0 &&
strcmp(keyword, "CloseSubGroup") != 0 &&
strncmp(keyword, "Default", 7) != 0 &&
string == NULL)
{
ppdClose(ppd);
return (NULL);
}
if (strcmp(keyword, "LanguageLevel") == 0)
ppd->language_level = atoi(string);
else if (strcmp(keyword, "LanguageEncoding") == 0)
{
ppd->lang_encoding = string;
string = NULL;
}
else if (strcmp(keyword, "LanguageVersion") == 0)
{
ppd->lang_version = string;
string = NULL;
}
else if (strcmp(keyword, "Manufacturer") == 0)
{
ppd->manufacturer = string;
string = NULL;
}
else if (strcmp(keyword, "ModelName") == 0)
{
ppd->modelname = string;
string = NULL;
}
else if (strcmp(keyword, "NickName") == 0)
{
ppd->nickname = string;
string = NULL;
}
else if (strcmp(keyword, "Product") == 0)
{
ppd->product = string;
string = NULL;
}
else if (strcmp(keyword, "ShortNickName") == 0)
{
ppd->shortnickname = string;
string = NULL;
}
else if (strcmp(keyword, "TTRasterizer") == 0)
{
ppd->ttrasterizer = string;
string = NULL;
}
else if (strcmp(keyword, "JCLBegin") == 0)
{
ppd_decode(string);
ppd->jcl_begin = string;
string = NULL;
}
else if (strcmp(keyword, "JCLEnd") == 0)
{
ppd_decode(string);
ppd->jcl_end = string;
string = NULL;
}
else if (strcmp(keyword, "JCLToPSInterpreter") == 0)
{
ppd_decode(string);
ppd->jcl_ps = string;
string = NULL;
}
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, "DefaultColorSpace") == 0)
{
if (strcmp(string, "CMY") == 0)
ppd->colorspace = PPD_CS_CMY;
else if (strcmp(string, "CMYK") == 0)
ppd->colorspace = PPD_CS_CMYK;
else if (strcmp(string, "RGB") == 0)
ppd->colorspace = PPD_CS_RGB;
else if (strcmp(string, "RGBK") == 0)
ppd->colorspace = PPD_CS_RGBK;
else if (strcmp(string, "N") == 0)
ppd->colorspace = PPD_CS_N;
else
ppd->colorspace = PPD_CS_GRAY;
}
else if (strcmp(keyword, "cupsFlipDuplex") == 0)
ppd->flip_duplex = strcmp(string, "True") == 0;
else if (strcmp(keyword, "cupsManualCopies") == 0)
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)
{
safe_free(filter);
ppdClose(ppd);
return (NULL);
}
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)
{
safe_free(string);
ppdClose(ppd);
return (NULL);
}
ppd->fonts = tempfonts;
ppd->fonts[ppd->num_fonts] = strdup(name);
ppd->num_fonts ++;
}
else if (strcmp(keyword, "VariablePaperSize") == 0 &&
strcmp(string, "True") == 0 &&
!ppd->variable_sizes)
{
ppd->variable_sizes = 1;
ppd_add_size(ppd, "Custom");
if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
{
ppd_group_t *temp;
if ((temp = ppd_get_group(ppd,
cupsLangString(language,
CUPS_MSG_GENERAL))) == NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
if ((option = ppd_get_option(temp, "PageSize")) == NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
}
if ((choice = ppd_add_choice(option, "Custom")) == NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
strlcpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
sizeof(choice->text));
option = NULL;
}
else if (strcmp(keyword, "MaxMediaWidth") == 0)
ppd->custom_max[0] = (float)atof(string);
else if (strcmp(keyword, "MaxMediaHeight") == 0)
ppd->custom_max[1] = (float)atof(string);
else if (strcmp(keyword, "ParamCustomPageSize") == 0)
{
if (strcmp(name, "Width") == 0)
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)
{
if (!ppd->variable_sizes)
{
ppd->variable_sizes = 1;
ppd_add_size(ppd, "Custom");
if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
{
ppd_group_t *temp;
if ((temp = ppd_get_group(ppd,
cupsLangString(language,
CUPS_MSG_GENERAL))) == NULL)
{
DEBUG_puts("Unable to get general group!");
ppdClose(ppd);
safe_free(string);
return (NULL);
}
if ((option = ppd_get_option(temp, "PageSize")) == NULL)
{
DEBUG_puts("Unable to get PageSize option!");
ppdClose(ppd);
safe_free(string);
return (NULL);
}
}
if ((choice = ppd_add_choice(option, "Custom")) == NULL)
{
DEBUG_puts("Unable to add Custom choice!");
ppdClose(ppd);
safe_free(string);
return (NULL);
}
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!");
ppdClose(ppd);
safe_free(string);
return (NULL);
}
if ((choice = ppdFindChoice(option, "Custom")) == NULL)
{
DEBUG_puts("Unable to find Custom choice!");
ppdClose(ppd);
safe_free(string);
return (NULL);
}
choice->code = string;
string = NULL;
option = 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(sizeof(ppd_emul_t), count);
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 = string;
string = NULL;
}
else
{
temp = realloc(ppd->patches, strlen(ppd->patches) +
strlen(string) + 1);
if (temp == NULL)
{
safe_free(string);
ppdClose(ppd);
return (NULL);
}
ppd->patches = temp;
strcpy(ppd->patches + strlen(ppd->patches), string);
}
}
else if (strcmp(keyword, "OpenUI") == 0)
{
if (name[0] == '*')
strcpy(name, name + 1);
for (i = strlen(name) - 1; i > 0 && isspace(name[i]); 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)
{
if (strcmp(name, "Collate") != 0 &&
strcmp(name, "Duplex") != 0 &&
strcmp(name, "InputSlot") != 0 &&
strcmp(name, "ManualFeed") != 0 &&
strcmp(name, "MediaType") != 0 &&
strcmp(name, "MediaColor") != 0 &&
strcmp(name, "MediaWeight") != 0 &&
strcmp(name, "OutputBin") != 0 &&
strcmp(name, "OutputMode") != 0 &&
strcmp(name, "OutputOrder") != 0 &&
strcmp(name, "PageSize") != 0 &&
strcmp(name, "PageRegion") != 0)
group = ppd_get_group(ppd, cupsLangString(language, CUPS_MSG_EXTRA));
else
group = ppd_get_group(ppd, cupsLangString(language, CUPS_MSG_GENERAL));
if (group == NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
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)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
if (strcmp(string, "PickMany") == 0)
option->ui = PPD_UI_PICKMANY;
else if (strcmp(string, "Boolean") == 0)
option->ui = PPD_UI_BOOLEAN;
else
option->ui = PPD_UI_PICKONE;
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;
}
else if (strcmp(keyword, "JCLOpenUI") == 0)
{
group = ppd_get_group(ppd, "JCL");
if (group == NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
if (name[0] == '*')
strcpy(name, name + 1);
option = ppd_get_option(group, name);
if (option == NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
if (strcmp(string, "PickMany") == 0)
option->ui = PPD_UI_PICKMANY;
else if (strcmp(string, "Boolean") == 0)
option->ui = PPD_UI_BOOLEAN;
else
option->ui = PPD_UI_PICKONE;
strlcpy(option->text, text, sizeof(option->text));
option->section = PPD_ORDER_JCL;
group = NULL;
}
else if (strcmp(keyword, "CloseUI") == 0 ||
strcmp(keyword, "JCLCloseUI") == 0)
option = NULL;
else if (strcmp(keyword, "OpenGroup") == 0)
{
if (group != NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
if (strncasecmp(string, "InstallableOptions", 18) == 0)
{
group = ppd_get_group(ppd, "InstallableOptions");
}
else
{
if (strchr(string, '/') != NULL)
strcpy(string, strchr(string, '/') + 1);
ppd_decode(string);
ppd_fix(string);
group = ppd_get_group(ppd, string);
}
}
else if (strcmp(keyword, "CloseGroup") == 0)
group = NULL;
else if (strcmp(keyword, "OrderDependency") == 0 ||
strcmp(keyword, "NonUIOrderDependency") == 0)
{
if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
if (keyword[0] == '*')
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;
}
}
else if (strncmp(keyword, "Default", 7) == 0)
{
if (string == NULL)
continue;
if (strchr(string, '/') != NULL)
*strchr(string, '/') = '\0';
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)
{
strlcpy(temp->options[i].defchoice, string,
sizeof(temp->options[i].defchoice));
break;
}
}
else if (strcmp(keyword + 7, option->keyword) == 0)
strlcpy(option->defchoice, string, sizeof(option->defchoice));
}
else if (strcmp(keyword, "UIConstraints") == 0 ||
strcmp(keyword, "NonUIConstraints") == 0)
{
if (ppd->num_consts == 0)
constraint = calloc(sizeof(ppd_const_t), 1);
else
constraint = realloc(ppd->consts,
(ppd->num_consts + 1) * sizeof(ppd_const_t));
if (constraint == NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
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 :
ppdClose(ppd);
safe_free(string);
break;
case 2 :
if (constraint->option1[0] == '*')
strcpy(constraint->option1, constraint->option1 + 1);
if (constraint->choice1[0] == '*')
strcpy(constraint->option2, constraint->choice1 + 1);
else
strcpy(constraint->option2, constraint->choice1);
constraint->choice1[0] = '\0';
constraint->choice2[0] = '\0';
break;
case 3 :
if (constraint->option1[0] == '*')
strcpy(constraint->option1, constraint->option1 + 1);
if (constraint->choice1[0] == '*')
{
strcpy(constraint->choice2, constraint->option2);
strcpy(constraint->option2, constraint->choice1 + 1);
constraint->choice1[0] = '\0';
}
else
{
if (constraint->option2[0] == '*')
strcpy(constraint->option2, constraint->option2 + 1);
constraint->choice2[0] = '\0';
}
break;
case 4 :
if (constraint->option1[0] == '*')
strcpy(constraint->option1, constraint->option1 + 1);
if (constraint->option2[0] == '*')
strcpy(constraint->option2, constraint->option2 + 1);
break;
}
}
else if (strcmp(keyword, "PaperDimension") == 0)
{
if ((size = ppdPageSize(ppd, name)) == NULL)
size = ppd_add_size(ppd, name);
if (size == NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
sscanf(string, "%f%f", &(size->width), &(size->length));
}
else if (strcmp(keyword, "ImageableArea") == 0)
{
if ((size = ppdPageSize(ppd, name)) == NULL)
size = ppd_add_size(ppd, name);
if (size == NULL)
{
ppdClose(ppd);
safe_free(string);
return (NULL);
}
sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom),
&(size->right), &(size->top));
}
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;
}
safe_free(string);
}
#ifdef DEBUG
if (!feof(fp))
printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
#endif
#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])
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 // __APPLE__
#ifndef __APPLE__
qsort(ppd->groups, ppd->num_groups, sizeof(ppd_group_t),
(int (*)(const void *, const void *))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 *))compare_options);
#endif
for (j = group->num_options, option = group->options;
j > 0;
j --, option ++)
{
#ifndef __APPLE__
qsort(option->choices, option->num_choices, sizeof(ppd_choice_t),
(int (*)(const void *, const void *))compare_choices);
#endif
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 *))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 *))compare_options);
#endif
for (k = group->num_options, option = group->options;
k > 0;
k --, option ++)
{
#ifndef __APPLE__
qsort(option->choices, option->num_choices, sizeof(ppd_choice_t),
(int (*)(const void *, const void *))compare_choices);
#endif
for (m = 0; m < option->num_choices; m ++)
option->choices[m].option = (void *)option;
}
}
}
return (ppd);
}
ppd_file_t *
ppdOpenFd(int fd)
{
FILE *fp;
ppd_file_t *ppd;
if (fd < 0)
return (NULL);
if ((fp = fdopen(fd, "r")) != NULL)
{
setbuf(fp, NULL);
ppd = ppdOpen(fp);
safe_free(fp);
}
else
ppd = NULL;
return (ppd);
}
ppd_file_t *
ppdOpenFile(const char *filename)
{
FILE *fp;
ppd_file_t *ppd;
if (filename == NULL)
return (NULL);
if ((fp = fopen(filename, "r")) != NULL)
{
ppd = ppdOpen(fp);
fclose(fp);
}
else
ppd = NULL;
return (ppd);
}
#ifndef __APPLE__
static int
compare_strings(char *s,
char *t)
{
int diff,
digits;
while (*s && *t)
{
if (isdigit(*s) && isdigit(*t))
{
while (*s == '0')
s ++;
while (*t == '0')
t ++;
while (isdigit(*s) && *s == *t)
{
s ++;
t ++;
}
if (isdigit(*s) && !isdigit(*t))
return (1);
else if (!isdigit(*s) && isdigit(*t))
return (-1);
else if (!isdigit(*s) || !isdigit(*t))
continue;
if (*s < *t)
diff = -1;
else
diff = 1;
digits = 0;
while (isdigit(*s))
{
digits ++;
s ++;
}
while (isdigit(*t))
{
digits --;
t ++;
}
if (digits < 0)
return (-1);
else if (digits > 0)
return (1);
else
return (diff);
}
else if (tolower(*s) < tolower(*t))
return (-1);
else if (tolower(*s) > tolower(*t))
return (1);
else
{
s ++;
t ++;
}
}
if (*s)
return (1);
else if (*t)
return (-1);
else
return (0);
}
static int
compare_groups(ppd_group_t *g0,
ppd_group_t *g1)
{
return (compare_strings(g0->text, g1->text));
}
static int
compare_options(ppd_option_t *o0,
ppd_option_t *o1)
{
return (compare_strings(o0->text, o1->text));
}
static int
compare_choices(ppd_choice_t *c0,
ppd_choice_t *c1)
{
return (compare_strings(c0->text, c1->text));
}
#endif // __APPLE__
static int
ppd_read(FILE *fp,
char *keyword,
char *option,
char *text,
char **string)
{
int ch,
colon,
endquote,
mask;
char *keyptr,
*optptr,
*textptr,
*strptr,
*lineptr,
line[65536];
if (fp == NULL || keyword == NULL || option == NULL || text == NULL ||
string == NULL)
return (0);
*string = NULL;
do
{
lineptr = line;
endquote = 0;
colon = 0;
while ((ch = getc(fp)) != EOF &&
(lineptr - line) < (sizeof(line) - 1))
{
if (ch == '\r' || ch == '\n')
{
if (lineptr == line)
continue;
if (ch == '\r')
{
if ((ch = getc(fp)) == EOF)
break;
if (ch != 0x0a)
ungetc(ch, fp);
}
ch = '\n';
if (!endquote)
break;
*lineptr++ = '\n';
}
else
{
*lineptr++ = ch;
if (ch == ':' && strncmp(line, "*%", 2) != 0)
colon = 1;
if (ch == '\"' && colon)
{
endquote = !endquote;
if (!endquote)
{
while ((ch = getc(fp)) != EOF)
if (ch == '\n')
break;
else if (ch == '\r')
{
ch = getc(fp);
if (ch != '\n')
ungetc(ch, fp);
ch = '\n';
break;
}
break;
}
}
}
}
if (endquote)
{
while ((ch = getc(fp)) != EOF)
if (ch == '\"')
break;
}
if (ch != '\n')
{
while ((ch = getc(fp)) != EOF)
if (ch == '\r' || ch == '\n')
{
if (ch == '\r')
{
if ((ch = getc(fp)) == EOF)
break;
if (ch != 0x0a)
ungetc(ch, fp);
}
break;
}
}
if (lineptr > line && lineptr[-1] == '\n')
lineptr --;
*lineptr = '\0';
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] != '*')
continue;
if (strcmp(line, "*") == 0 ||
strncmp(line, "*%", 2) == 0 ||
strncmp(line, "*?", 2) == 0 ||
strcmp(line, "*End") == 0)
continue;
keyptr = keyword;
while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr))
if ((keyptr - keyword) < (PPD_MAX_NAME - 1))
*keyptr++ = *lineptr++;
*keyptr = '\0';
if (strcmp(keyword, "End") == 0)
continue;
mask |= PPD_KEYWORD;
if (isspace(*lineptr))
{
while (isspace(*lineptr))
lineptr ++;
optptr = option;
while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
*lineptr != '/')
if ((optptr - option) < (PPD_MAX_NAME - 1))
*optptr++ = *lineptr++;
*optptr = '\0';
mask |= PPD_OPTION;
if (*lineptr == '/')
{
lineptr ++;
textptr = text;
while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
if ((textptr - text) < (PPD_MAX_LINE - 1))
*textptr++ = *lineptr++;
*textptr = '\0';
ppd_decode(text);
mask |= PPD_TEXT;
}
}
if (*lineptr == ':')
{
*string = malloc(strlen(lineptr) + 1);
while (*lineptr == ':' || isspace(*lineptr))
lineptr ++;
strptr = *string;
while (*lineptr != '\0')
{
if (*lineptr != '\"')
*strptr++ = *lineptr++;
else
lineptr ++;
}
*strptr = '\0';
mask |= PPD_STRING;
}
}
while (mask == 0);
return (mask);
}
static void
ppd_decode(char *string)
{
char *inptr,
*outptr;
inptr = string;
outptr = string;
while (*inptr != '\0')
if (*inptr == '<' && isxdigit(inptr[1]))
{
inptr ++;
while (isxdigit(*inptr))
{
if (isalpha(*inptr))
*outptr = (tolower(*inptr) - 'a' + 10) << 4;
else
*outptr = (*inptr - '0') << 4;
inptr ++;
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';
}
static void
ppd_fix(char *string)
{
#ifndef __APPLE__
unsigned char *p;
static 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
}