/* * ppd.c: PPD file routines * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * * See the AUTHORS file for a list of people who have hacked on * this code. * See the ChangeLog file for a list of changes. * * Contents: * * ppd_file_free() - Free all memory used by the PPD * file. * ppd_file_new() - Initialize the PpdFile struct. * ppd_file_new_from_filep() - Initialize the PpdFile struct, * use a FILE* reference to the ppd * ppd_file_new_from_fd() - Initialize the PpdFile struct, * use a file descriptor to the ppd * ppd_free_group() - Free a single UI group. * ppd_free_option() - Free a single option. * ppd_free_choice() - Free a single choice * */ #include "ppd.h" #include #include #include #include #include "ppd.h" //#include "exstring.h" #include "debug.h" #define _(String) (String) #define N_(String) (String) #define textdomain(Domain) #define bindtextdomain(Package, Directory) #define PPD_LINE_KEYWORD 1 // Line contained a keyword #define PPD_LINE_OPTION 2 // Line contained an option name #define PPD_LINE_TEXT 4 // Line contained human-readable text #define PPD_LINE_STRING 8 // Line contained a string or code // Local functions... 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(PpdGroup * group); static void ppd_free_option(PpdOption * option); static void ppd_free_choice(PpdChoice * choice); static PpdGroup *ppd_get_group(PpdFile * ppd, const char *name); static PpdOption *ppd_get_option(PpdGroup * group, const char *name); static PpdChoice *ppd_add_choice(PpdOption * option, const char *ch_name, const char *ch_text); static GString *ppd_strncpy(GString * gstring, const char *text); static void chomp(char *str); static PpdSize *ppd_add_size(PpdFile * ppd, const char *name); inline static char *str_rep(const GString * gs); static GString *ppd_strncpy(GString * gstring, const char *text) { if (gstring != NULL) gstring = g_string_assign(gstring, text); else gstring = g_string_new(text); return (gstring); } static void chomp(char *str) { int i; for (i = strlen(str) - 1; i >= 0; i--) if (isspace(str[i])) str[i] = 0; else return; } // 'ppd_free()' - Free all memory used by the PPD file. void ppd_file_free(PpdFile * ppd) { // I - PPD file record PpdEmulator *emul; // Current emulation PpdGroup *group; // Current group GSList *list; // List enumeration var PpdSize *size; // Current size PpdConstraint *cons; // Current constraint char *font; // Current font PpdProfile *profile; // Current profile char *filter; // Current filter // Range check the PPD file record... if (ppd == NULL) return; // Free all strings at the top level... // g_string_free(ppd->patches, TRUE); // It appears to be alright to not have a jcl_begin if (ppd->jcl_begin) g_string_free(ppd->jcl_begin, TRUE); if (ppd->jcl_ps) g_string_free(ppd->jcl_ps, TRUE); if (ppd->jcl_end) g_string_free(ppd->jcl_end, TRUE); g_string_free(ppd->lang_encoding, TRUE); if (ppd->lang_version) g_string_free(ppd->lang_version, TRUE); if (ppd->modelname) g_string_free(ppd->modelname, TRUE); if (ppd->ttrasterizer) g_string_free(ppd->ttrasterizer, TRUE); if (ppd->manufacturer) g_string_free(ppd->manufacturer, TRUE); if (ppd->product) g_string_free(ppd->product, TRUE); if (ppd->nickname) g_string_free(ppd->nickname, TRUE); if (ppd->shortnickname) g_string_free(ppd->shortnickname, TRUE); // Free any emulations... list = (GSList *) ppd->emulations; while (list != NULL) { emul = PPD_EMULATOR(list->data); list = g_slist_next(list); g_string_free(emul->name, TRUE); g_free(emul->start); g_free(emul->stop); } g_slist_free(ppd->emulations); // Free any UI groups, subgroups, and options... list = ppd->groups; while (list) { group = PPD_GROUP(list->data); list = g_slist_next(list); ppd_free_group(group); } g_slist_free(ppd->groups); // Free any page sizes... list = ppd->sizes; while (list) { size = PPD_SIZE(list->data); list = g_slist_next(list); g_string_free(size->name, TRUE); g_free(size); } g_slist_free(ppd->sizes); // Free any constraints... list = ppd->consts; while (list) { cons = PPD_CONSTRAINT(list->data); list = g_slist_next(list); g_string_free(cons->option1, TRUE); g_string_free(cons->option2, TRUE); // See below I guess it is also alright to leave the first // constraint blank. if (cons->choice1) g_string_free(cons->choice1, TRUE); // Some PPD files don't specify the whole constraint they // leave the last choice blank. I guess that means that any // value for that option is illegal. if (cons->choice2) g_string_free(cons->choice2, TRUE); g_free(cons); } g_slist_free(ppd->consts); // Free any fonts... list = ppd->fonts; while (list) { font = (char *)list->data; list = g_slist_next(list); g_free(font); } g_slist_free(ppd->fonts); // Free any profiles... list = ppd->profiles; while (list) { profile = PPD_PROFILE(list->data); list = g_slist_next(list); g_string_free(profile->resolution, TRUE); g_string_free(profile->media_type, TRUE); g_free(profile); } g_slist_free(ppd->profiles); // Free any filters... list = ppd->filters; while (list) { filter = (char *)list->data; list = g_slist_next(list); g_free(filter); } g_slist_free(ppd->filters); // ADD: // Free any patches // Free the whole record... g_free(ppd); } // 'ppd_free_group()' - Free a single UI group. static void ppd_free_group(PpdGroup * group) { GSList *c; // List traversing variable PpdOption *option; // Current option PpdGroup *subgroup; // Current sub-group /* free all the string members of this class */ g_string_free(group->text, TRUE); /* free all the options in this group */ c = group->options; while (c) { option = PPD_OPTION(c->data); c = g_slist_next(c); ppd_free_option(option); } /* free the options GSList */ g_slist_free(group->options); /* free all the subgroups in this group */ c = group->subgroups; while (c) { subgroup = PPD_GROUP(c->data); c = g_slist_next(c); ppd_free_group(subgroup); } /* free the subgroup GSList */ g_slist_free(group->subgroups); /* free what's left of the group struct */ g_free(group); return; } // 'ppd_free_option()' - Free a single option. static void ppd_free_option(PpdOption * option) { PpdChoice *choice; // Current choice GSList *c; /* free all the string members of this class */ g_string_free(option->keyword, TRUE); if (option->defchoice) g_string_free(option->defchoice, TRUE); if (option->text) g_string_free(option->text, TRUE); /* free all the data in our GSList */ c = option->choices; while (c) { choice = PPD_CHOICE(c->data); c = g_slist_next(c); ppd_free_choice(choice); } /* now free the actual GSList, and then the whole struct */ g_slist_free(option->choices); g_free(option); return; } // 'ppd_free_choice()' - Free a single choice. static void ppd_free_choice(PpdChoice * choice) { /* free all the string members if this class */ g_string_free(choice->choice, TRUE); g_string_free(choice->text, TRUE); g_free(choice->code); /* free the actual struct now, and point it to NULL */ g_free(choice); return; } // 'ppd_get_group()' - Find or create the named group as needed. static PpdGroup *ppd_get_group(PpdFile * ppd, const char *name) { PpdGroup *group; // Group GSList *list; // list iteration variable. list = ppd->groups; while (list) { group = PPD_GROUP(list->data); /* make sure it's not empty, and the 'text' string isn't either */ /* then compare... */ if ((group->text != NULL) && (group->text->str != NULL)) if (strcmp(group->text->str, name) == 0) break; list = g_slist_next(list); } /* if we went through the linked list, and didn't find anything */ /* create a new group, and add it */ if (list == NULL) { group = ppd_group_new(); // g_malloc0(sizeof(PpdGroup)); ppd->groups = g_slist_append(ppd->groups, group); group->text = ppd_strncpy(group->text, name); } return (group); } // 'ppd_get_option()' - Find or create the named option as needed. static PpdOption *ppd_get_option(PpdGroup * group, const char *name) { PpdOption *option = NULL; // Option GSList *c; // List traversal var /* traverse the linked list, looking for a matching option */ for (c = group->options; c; c = g_slist_next(c)) { option = PPD_OPTION(c->data); if ((option != NULL) && (option->keyword != NULL)) { /* sanity check */ /* check option->keyword against name parameter */ if (strcmp(option->keyword->str, name) == 0) break; } } /* This causes a problem with handling PPD files which have VariablePageSize before the enumeration of page sizes. However, removing it causes lots of problems. */ if (c == NULL) /* we didn't find an option, create a new one */ option = ppd_option_new(group, name); return (option); } // 'ppd_add_choice()' - Add a choice to an option. // NOTE: char*name is NOT g_free'd in this function static PpdChoice *ppd_add_choice(PpdOption * option, const char *ch_name, const char *ch_text) { PpdChoice *choice = ppd_choice_new(option, ch_name, ch_text); option->choices = g_slist_append(option->choices, choice); return (choice); } // 'ppd_add_size()' - Add a page size. // NOTE: char*name is NOT g_free'd in this function static PpdSize *ppd_add_size(PpdFile * ppd, const char *name) { PpdSize *size = ppd_size_new(name); // g_malloc0(sizeof(PpdSize)); ppd->sizes = g_slist_append(ppd->sizes, size); return (size); } // 'ppd_file_new_from_filep()' - Read a PPD file into memory. PpdFile *ppd_file_new_from_filep(FILE * fp) { // I - File to read from int m; // Looping vars PpdFile *ppd; // PPD file record PpdGroup *group, // Current group *subgroup; // Current sub-group PpdOption *option, // Current option *tmpopt; PpdChoice *choice; // Current choice PpdConstraint *constraint; // Current constraint PpdSize *size; // Current page size int mask; // Line data mask char keyword[41], // Keyword from file name[41], // Option from file text[81], // Human-readable text from file *string = NULL, // Code/text from file *sptr, // Pointer into string *nameptr, // Pointer into name *tmp; // temporary pointer float order; // Order dependency number PpdSectionOrder section; // Order dependency section PpdProfile *profile; // Pointer to color profile char **filter; // Pointer to filter PpdEmulator *emul; // Pointer to emulator class GSList *list; // Generic list enumerator char copt1[41], // These temporarily hold copt2[41], // data that will be put in cchoice1[41], // a PpdConstraint cchoice2[41]; // // cups_lang_t *language; // Default language // Get the default language for the user... // language=cupsLangDefault(); // Range check input... if (fp == NULL) { errno = ENODEV; return (NULL); } /* Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'... */ mask = ppd_read(fp, keyword, name, text, &string); if (mask == 0 || strcmp(keyword, "PPD-Adobe") != 0 || string == NULL || string[0] != '4') { // Either this is not a PPD file, or it is not a 4.x PPD file. g_free(string); errno = EBADF; return (NULL); } DEBUG_printf(("ppd_file_new: keyword=%s, string=%p\n", keyword, string)); g_free(string); // Allocate memory for the PPD file record, and zero it out if ((ppd = g_malloc0(sizeof(PpdFile))) == NULL) { errno = ENOMEM; return (NULL); } // setup defaults? ppd->language_level = 1; ppd->color_device = FALSE; ppd->colorspace = PPD_CS_GRAY; ppd->landscape = 90; // Read lines from the PPD file & add them to the file record... 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 // DEBUG if (strcmp(keyword, "LanguageLevel") == 0) ppd->language_level = atoi(string); else if (strcmp(keyword, "LanguageEncoding") == 0) { ppd->lang_encoding = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "LanguageVersion") == 0) { ppd->lang_version = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "Manufacturer") == 0) { ppd->manufacturer = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "ModelName") == 0) { ppd->modelname = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "NickName") == 0) { ppd->nickname = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "Product") == 0) { ppd->product = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "ShortNickName") == 0) { ppd->shortnickname = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "TTRasterizer") == 0) { ppd->ttrasterizer = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "JCLBegin") == 0) { ppd_decode(string); // Decode quoted string ppd->jcl_begin = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "JCLEnd") == 0) { ppd_decode(string); // Decode quoted string ppd->jcl_end = g_string_new(string); g_free(string); // Don't free this string below string = NULL; } else if (strcmp(keyword, "JCLToPSInterpreter") == 0) { ppd_decode(string); // Decode quoted string ppd->jcl_ps = g_string_new(string); g_free(string); // Don't free this string below 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, "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) { profile = ppd_profile_new(); // g_malloc0(sizeof(PpdProfile)); ppd->profiles = g_slist_append(ppd->profiles, (gpointer) profile); profile->resolution = ppd_strncpy(profile->resolution, name); profile->media_type = ppd_strncpy(profile->media_type, text); /* tmp = g_malloc0(41); strncpy(tmp, name, 40); profile->resolution = g_string_new(tmp); strncpy(tmp, text, 40); profile->media_type = g_string_new(tmp); g_free(tmp); */ 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) { filter = g_malloc(sizeof(char *)); ppd->filters = g_slist_append(ppd->filters, (gpointer) filter); // Copy filter string & prevent it from being freed below... *filter = string; string = NULL; } else if (strcmp(keyword, "VariablePaperSize") == 0 && strcmp(string, "True") == 0 && !ppd->variable_sizes) { ppd->variable_sizes = TRUE; size = ppd_size_new("Custom"); // g_malloc0(sizeof(PpdSize)); // Add a "Custom" page size entry... ppd->sizes = g_slist_append(ppd->sizes, (gpointer) size); // Add a "Custom" page size option... if ((group = ppd_get_group(ppd, _("General"))) == NULL) goto failout; if ((option = ppd_get_option(group, "PageSize")) == NULL) { /* not finding the group at this stage isn't a problem it could just mean that "VariablePageSize" comes before the media size definition in ppd file */ option = ppd_option_new(group, name); option->text = g_string_new("Media Size"); option->ui = PPD_UI_PICKONE; option->section = PPD_ORDER_ANY; } if ((choice = ppd_add_choice(option, "Custom", _("Custom Size"))) == NULL) goto failout; group = NULL; 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 = TRUE; // Add a "Custom" page size entry... ppd_add_size(ppd, "Custom"); // Add a "Custom" page size option... if ((group = ppd_get_group(ppd, _("General"))) == NULL) goto failout; if ((option = ppd_get_option(group, "PageSize")) == NULL) goto failout; if ((choice = ppd_add_choice(option, "Custom", _("Custom Size"))) == NULL) goto failout; group = NULL; option = NULL; } if ((option = ppd_find_option_by_keyword(ppd, "PageSize")) == NULL) { /* X - This piece of code confused me. I am guessing what to do here. -- Ben Sept 1 2000 */ if ((group = ppd_get_group(ppd, _("General"))) == NULL) goto failout; option = ppd_option_new(group, name); option->text = g_string_new("PageSize"); option->ui = PPD_UI_PICKONE; option->section = PPD_ORDER_ANY; if ((choice = ppd_add_choice(option, "Custom", _("Custom Size"))) == NULL) goto failout; group = NULL; } if ((choice = ppd_find_choice(option, "Custom")) == NULL) goto failout; choice->code = string; string = NULL; option = NULL; } else if (strcmp(keyword, "LandscapeOrientation") == 0) { if (strcmp(string, "Minus90") == 0) ppd->landscape = -90; else ppd->landscape = 90; } else if (strcmp(keyword, "Emulators") == 0) { sptr = string; while (sptr != NULL) { /* skip all leading whitespace, to get to the next name */ while (*sptr == ' ') sptr++; nameptr = sptr; /* set to the begining of the current working name */ emul = ppd_emulator_new(); if ((sptr = strchr(sptr, ' ')) != NULL) { *sptr = '\0'; sptr++; } emul->name = g_string_new(nameptr); ppd->emulations = g_slist_append(ppd->emulations, emul); } } else if (strncmp(keyword, "StartEmulator_", 14) == 0) { ppd_decode(string); /* find the emulator whose name field matches the keyword. */ /* if found, use string as a new start code */ list = ppd->emulations; while (list) { emul = PPD_EMULATOR(list->data); list = g_slist_next(list); if ((emul != NULL) && (emul->name != NULL) && (strcmp(keyword + 14, emul->name->str) == 0)) { emul->start = string; string = NULL; } } } else if (strncmp(keyword, "StopEmulator_", 13) == 0) { ppd_decode(string); /* find the emulator whose name field matches the keyword. */ /* if found, use string as a new stop code */ list = ppd->emulations; while (list) { emul = PPD_EMULATOR(list->data); list = g_slist_next(list); if ((emul != NULL) && (emul->name != NULL) && (strcmp(keyword + 13, emul->name->str) == 0)) { emul->stop = string; string = NULL; } } } else if (strcmp(keyword, "JobPatchFile") == 0) { ppd->patches = g_slist_append(ppd->patches, string); string = NULL; } else if (strcmp(keyword, "OpenUI") == 0) { /* Add an option record to the current sub-group, group, or file... */ if (name[0] == '*') strcpy(name, name + 1); if (string == NULL) goto failout1; 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, _("Extra")); else group = ppd_get_group(ppd, _("General")); if (group == NULL) goto failout; option = ppd_get_option(group, name); group = NULL; } else option = ppd_get_option(group, name); if (option == NULL) option = ppd_option_new(group, name); // Now fill in the initial information for the option... 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]) { ppd_fix(text); option->text = ppd_strncpy(option->text, text); } else { if (strcmp(name, "PageSize") == 0) option->text = ppd_strncpy(option->text, _("Media Size")); else if (strcmp(name, "MediaType") == 0) option->text = ppd_strncpy(option->text, _("Media Type")); else if (strcmp(name, "InputSlot") == 0) option->text = ppd_strncpy(option->text, _("Media Source")); else if (strcmp(name, "ColorModel") == 0) option->text = ppd_strncpy(option->text, _("Output Mode")); else if (strcmp(name, "Resolution") == 0) option->text = ppd_strncpy(option->text, _("Resolution")); else option->text = ppd_strncpy(option->text, name); } option->section = PPD_ORDER_ANY; } else if (strcmp(keyword, "JCLOpenUI") == 0) { // Find the JCL group, and add if needed... group = ppd_get_group(ppd, "JCL"); if (group == NULL) goto failout; // Add an option record to the current JCLs... if (name[0] == '*') strcpy(name, name + 1); if ((option = ppd_get_option(group, name)) == NULL) option = ppd_option_new(group, keyword); // Now fill in the initial information for the option... 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; option->text = ppd_strncpy(option->text, 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) { // Open a new group... if (group != NULL) goto failout; if (strchr(string, '/') != NULL) // Just show human readable text 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, "OpenSubGroup") == 0) { // Open a new sub-group... if (group == NULL || subgroup != NULL) goto failout; subgroup = ppd_group_new(); // g_malloc0(sizeof(PpdGroup)); ppd_decode(string); ppd_fix(string); subgroup->text = ppd_strncpy(subgroup->text, string); group->subgroups = g_slist_append(group->subgroups, subgroup); } else if (strcmp(keyword, "CloseSubGroup") == 0) subgroup = NULL; else if (strcmp(keyword, "OrderDependency") == 0 || strcmp(keyword, "NonUIOrderDependency") == 0) { if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3) goto failout; 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) { // Only valid for Non-UI options... /* note: here, the previous author tests whether group->text[0] == '\0' I'm going to just test whether group->text == NULL */ list = ppd->groups; while (list) { group = PPD_GROUP(list->data); list = g_slist_next(list); if (group->text == NULL) break; } /* If we found a group previously, traverse the list of options and check if the option keyword and keyword var match. if so, set the option->section = section; and option->order = order; */ if ((group != NULL) && (group->text == NULL)) { list = group->options; while (list) { tmpopt = PPD_OPTION(list->data); list = g_slist_next(list); if ((tmpopt->keyword != NULL) && (strcmp(tmpopt->keyword->str, keyword) == 0)) { tmpopt->section = section; tmpopt->order = order; break; } } } group = NULL; } else { option->section = section; option->order = order; } } else if (strncmp(keyword, "Default", 7) == 0) { if (string == NULL) continue; if ((tmp = strchr(string, '/')) != NULL) (*tmp) = '\0'; // / *strchr(string, '/') = '\0'; /* enumerate through the group clist, finding a group whose 'text' member is empty. Assign this one to group* if an empty group->text was found, enumerate through the options list, looking for an option keyword that matches the keyword var if found, copy the values in string var to the defchoice member in the option */ if (option == NULL) { /* enumerate through the group clist, finding a group whose 'text' member is empty. Assign this one to group* if an empty group->text was found, enumerate through the options list, looking for an option keyword that matches the keyword var if found, copy the values in string var to the defchoice member in the option */ // Only valid for Non-UI options... list = ppd->groups; while (list) { group = PPD_GROUP(list->data); list = g_slist_next(list); if (group->text == NULL) break; } if ((group != NULL) && (group->text == NULL)) { list = group->options; while (list) { option = PPD_OPTION(list->data); list = g_slist_next(list); if ((option->keyword != NULL) && (strcmp(option->keyword->str, keyword))) { option->defchoice = ppd_strncpy(option->defchoice, string); break; } } } /* for (i = ppd->num_groups, group = ppd->groups; i > 0; i--, group++) if (group->text[0] == '\0') break; if (i > 0) for (i = 0; i < group->num_options; i++) if (strcmp(keyword, group->options[i].keyword) == 0) { strncpy(group->options[i].defchoice, string, sizeof(group->options[i].defchoice) - 1); break; } */ group = NULL; } /* Check that the back half of "DefaultWhatever" is actually "Whatever" and not some other string. This handles cases where like this one: *OpenUI *OutputBin/Output Bin: PickOne *OrderDependency: 40 AnySetup *OutputBin *DefaultOutputBin: Upper ^^^^^^^^^ <-- correct default *DefaultOutputOrder: Normal ^^^^^^^^^^^ <-- incorrect default */ else if (! strcmp (option->keyword->str, (char *) (keyword + 7))) { option->defchoice = ppd_strncpy(option->defchoice, string); } } else if (strcmp(keyword, "UIConstraints") == 0 || strcmp(keyword, "NonUIConstraints") == 0) { constraint = ppd_constraint_new(); // g_malloc0(sizeof(PpdConstraint)); if (constraint == NULL) goto failout; ppd->consts = g_slist_append(ppd->consts, constraint); m = sscanf(string, "%40s%40s%40s%40s", copt1, cchoice1, copt2, cchoice2); switch (m) { case 0: // Error case 1: // Error ppd_file_free(ppd); g_free(string); errno = ENOTTY; break; case 2: // Two options... if (copt1[0] == '*') strcpy(copt1, copt1 + 1); if (cchoice1[0] == '*') strcpy(copt2, cchoice1 + 1); else strcpy(copt2, cchoice1); constraint->option1 = g_string_new(copt1); constraint->option2 = g_string_new(copt2); break; case 3: // Two options, one choice... if (copt1[0] == '*') strcpy(copt1, copt1 + 1); constraint->option1 = g_string_new(copt1); if (cchoice1[0] == '*') { strcpy(cchoice2, copt2); strcpy(copt2, cchoice1 + 1); cchoice1[0] = '\0'; constraint->choice2 = g_string_new(cchoice2); constraint->option2 = g_string_new(copt2); } else { if (copt2[0] == '*') strcpy(copt2, copt2 + 1); constraint->option2 = g_string_new(copt2); cchoice2[0] = '\0'; } break; case 4: // Two options, two choices... if (copt1[0] == '*') strcpy(copt1, copt1 + 1); if (copt2[0] == '*') strcpy(copt2, copt2 + 1); constraint->option1 = g_string_new(copt1); constraint->option2 = g_string_new(copt2); constraint->choice1 = g_string_new(cchoice1); constraint->choice2 = g_string_new(cchoice2); break; } } else if (strcmp(keyword, "PaperDimension") == 0) { if ((size = ppd_get_page_size(ppd, name)) != NULL) sscanf(string, "%f%f", &(size->width), &(size->length)); } else if (strcmp(keyword, "ImageableArea") == 0) { if ((size = ppd_get_page_size(ppd, name)) != NULL) sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom), &(size->right), &(size->top)); } else if (option != NULL && (mask & (PPD_LINE_KEYWORD | PPD_LINE_OPTION | PPD_LINE_STRING)) == (PPD_LINE_KEYWORD | PPD_LINE_OPTION | PPD_LINE_STRING)) { if (strcmp(keyword, "PageSize") == 0) { // Add a page size... ppd_add_size(ppd, name); } // Add the option choice... if (mask & PPD_LINE_TEXT) { ppd_fix(text); choice = ppd_add_choice(option, name, text); } else if (strcmp(name, "True") == 0) choice = ppd_add_choice(option, name, "Yes"); else if (strcmp(name, "False") == 0) choice = ppd_add_choice(option, name, "Yes"); else choice = ppd_add_choice(option, name, name); if (strncmp(keyword, "JCL", 3) == 0) ppd_decode(string); // Decode quoted string if (choice->code != NULL) g_free(choice->code); choice->code = string; string = NULL; } g_free(string); } #ifdef DEBUG if (!feof(fp)) printf("Premature EOF at %ld ...\n", ftell(fp)); #endif // DEBUG return (ppd); failout: g_free(string); failout1: ppd_file_free(ppd); errno = ENOTTY; return (NULL); } // 'ppd_file_new_from_fd()' - Read a PPD file into memory. PpdFile *ppd_file_new_from_fd(int fd) { // I - File to read from FILE *fp; // File pointer PpdFile *ppd; // PPD file record // Range check input... if (fd < 0) return (NULL); // Try to open the file and parse it... if ((fp = fdopen(fd, "r")) != NULL) { setbuf(fp, NULL); ppd = ppd_file_new_from_filep(fp); fclose(fp); } else ppd = NULL; return (ppd); } // 'ppd_file_new()' - Read a PPD file into memory. PpdFile *ppd_file_new(const char *filename) { FILE *fp; // File pointer PpdFile *ppd; // PPD file record // Range check input... if (filename == NULL) return (NULL); // Try to open the file and parse it... if ((fp = fopen(filename, "r")) != NULL) { ppd = ppd_file_new_from_filep(fp); fclose(fp); } else ppd = NULL; return (ppd); } /* 'ppd_read()' - Read a line from a PPD file, skipping comment lines as necessary. return value -Bitmask of fields read from a PPD file,skipping comment lines as necessary I fp - File to read from O keyword - Keyword from line O option - Option from line O text - Human-readable text from line O string - Code/string data */ int ppd_read(FILE * fp, char *keyword, char *option, char *text, char **string) { int ch, // Character from file endquote, // Waiting for an end quote mask; // Mask to be returned char *keyptr, // Keyword pointer *optptr, // Option pointer *textptr, // Text pointer *strptr, // Pointer into string *lineptr, // Current position in line buffer line[262144]; // Line buffer (256k) /* Range check everything... */ if (fp == NULL || keyword == NULL || option == NULL || text == NULL || string == NULL) return (0); /* Now loop until we have a valid line... */ do { /* Read the line... */ lineptr = line; endquote = 0; while ((ch = getc(fp)) != EOF && (lineptr - line) < (signed)(sizeof(line) - 1)) { if (ch == '\r' || ch == '\n') { /* Line feed or carriage return... */ if (lineptr == line) // Skip blank lines continue; if (ch == '\r') { /* Check for a trailing line feed... */ if ((ch = getc(fp)) == EOF) break; if (ch != 0x0a) ungetc(ch, fp); } *lineptr++ = '\n'; if (!endquote) // Continue for multi-line text break; } else { /* Any other character... */ *lineptr++ = ch; if (ch == '\"') endquote = !endquote; } } if (lineptr > line && lineptr[-1] == '\n') lineptr--; *lineptr = '\0'; if (ch == EOF && lineptr == line) return (0); /* Now parse it... */ mask = 0; lineptr = line + 1; keyword[0] = '\0'; option[0] = '\0'; text[0] = '\0'; *string = NULL; if (line[0] != '*') // All lines start with an asterisk continue; if (strncmp(line, "*%", 2) == 0 || // Comment line strncmp(line, "*?", 2) == 0 || // Query line strcmp(line, "*End") == 0) // End of multi-line string continue; /* Get a keyword... */ keyptr = keyword; while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr) && (keyptr - keyword) < 40) *keyptr++ = *lineptr++; *keyptr = '\0'; mask |= PPD_LINE_KEYWORD; if (*lineptr == ' ' || *lineptr == '\t') { /* Get an option name... */ while (*lineptr == ' ' || *lineptr == '\t') lineptr++; optptr = option; while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' && *lineptr != '/' && (optptr - option) < 40) *optptr++ = *lineptr++; *optptr = '\0'; chomp(option); mask |= PPD_LINE_OPTION; if (*lineptr == '/') { /* Get human-readable text... */ lineptr++; textptr = text; while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' && (textptr - text) < 80) *textptr++ = *lineptr++; *textptr = '\0'; chomp(text); ppd_decode(text); mask |= PPD_LINE_TEXT; } } if (*lineptr == ':') { /* Get string... */ *string = g_malloc(strlen(lineptr) + 1); while (*lineptr == ':' || isspace(*lineptr)) lineptr++; strptr = *string; while (*lineptr != '\0') { if (*lineptr != '\"') *strptr++ = *lineptr++; else lineptr++; } *strptr = '\0'; chomp(*string); mask |= PPD_LINE_STRING; } } while (mask == 0); return (mask); } /* 'ppd_decode()' - Decode a string value... */ static void ppd_decode(char *string) // I - String to decode { char *inptr = string; // Input pointer char *outptr = string; // Output pointer while (*inptr != '\0') if (*inptr == '<' && isxdigit(inptr[1])) { /* Convert hex to 8-bit values... */ 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'; } /* * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f * to be valid ISO-8859-1 characters... */ static void ppd_fix(char *string) // IO - String to fix { unsigned char *p; // Pointer into string static unsigned char lut[32] = // Lookup table for characters { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 'l', '`', '\'', '^', '~', 0x20, // bar 0x20, // circumflex 0x20, // dot 0x20, // double dot 0x20, 0x20, // circle 0x20, // ??? 0x20, '\"', // should be right quotes 0x20, // ??? 0x20 // accent }; for (p = (unsigned char *)string; *p; p++) if (*p >= 0x80 && *p < 0xa0) *p = lut[*p - 0x80]; } inline static char *str_rep(const GString * gs) { if (gs == NULL) g_string_new(""); return (gs->str); } void ppd_debug_dump_ppd(PpdFile * ppd) { const char *cs; unsigned int i; GSList *list, *olist, *clist; PpdEmulator *emul; PpdGroup *group; PpdOption *option; PpdChoice *choice; PpdSize *size; PpdConstraint *cons; PpdProfile *profile; if (ppd == NULL) { printf("ppd=NULL\n"); return; } switch (ppd->colorspace) { case PPD_CS_CMYK: cs = "PPD_CS_CMYK"; break; case PPD_CS_CMY: cs = "PPD_CS_CMY"; break; case PPD_CS_GRAY: cs = "PPD_CS_GRAY"; break; case PPD_CS_RGB: cs = "PPD_CS_RGB"; break; case PPD_CS_RGBK: cs = "PPD_CS_RGBK"; break; case PPD_CS_N: cs = "PPD_CS_N"; break; } printf("language_level=%d\n" "color_device=%d\n" "variable_sizes=%d\n" "accurate_screens=%d\n" "contone_only=%d\n" "landscape=%d\n" "model_number=%d\n" "manual_copies=%d\n" "*patches=\"", // "jcl_begin=\"%s\"\n" "jcl_ps=\"%s\"\n" // "jcl_end=\"%s\"\n", ppd->language_level, ppd->color_device, ppd->variable_sizes, ppd->accurate_screens, ppd->contone_only, ppd->landscape, ppd->model_number, ppd->manual_copies); // ppd->patches, // ppd->jcl_begin, ppd->jcl_ps, ppd->jcl_end, /* I'm lazy, and will take the quick (inefficient) route to dumping the patch info */ for (i = 0; i < g_slist_length(ppd->patches); i++) printf("%s", (char *)g_slist_nth_data(ppd->patches, i)); if (i == 0) printf("(null)"); /* I do this to preserve compatibility with the previous version of this function */ printf("\"\n"); printf("lang_encoding=\"%s\"\n" "lang_version=\"%s\"\n" "modelname=\"%s\"\n" "ttrasterizer=\"%s\"\n" "manufacturer=\"%s\"\n" "product=\"%s\"\n" "nickname=\"%s\"\n" "shortnickname=\"%s\"\n" "custom_min=[%f %f]\n" "custom_max=[%f %f]\n" "custom_margins=[%f %f %f %f]\n" "colorspace=%s\n" "---Emulations---\n", str_rep(ppd->lang_encoding), str_rep(ppd->lang_version), str_rep(ppd->modelname), str_rep(ppd->ttrasterizer), str_rep(ppd->manufacturer), str_rep(ppd->product), str_rep(ppd->nickname), str_rep(ppd->shortnickname), ppd->custom_min[0], ppd->custom_min[1], ppd->custom_max[0], ppd->custom_max[1], ppd->custom_margins[0], ppd->custom_margins[1], ppd->custom_margins[2], ppd->custom_margins[3], cs); list = ppd->emulations; i = 0; /* if (!list) printf("NULL\n\n"); */ while (list) { emul = PPD_EMULATOR(list->data); printf("%d = \"%s\"\n" "\tstart=\"%s\"\n" "\tstop=\"%s\"\n\n", i, str_rep(emul->name), emul->start, emul->stop); i++; list = g_slist_next(list); } printf("---Groups---\n"); list = ppd->groups; i = 0; /* if (list == NULL) printf("NULL\n"); */ while (list) { int j; group = PPD_GROUP(list->data); printf("%d = \"%s\"\n" "\t---Options---\n", i, group->text->str); list = g_slist_next(list); olist = group->options; j = 0; /* if (olist == NULL) printf("NULL\n"); */ while (olist) { const char *sec; int k; option = PPD_OPTION(olist->data); olist = g_slist_next(olist); switch (option->ui) { case PPD_UI_BOOLEAN: cs = "PPD_UI_BOOLEAN"; break; case PPD_UI_PICKONE: cs = "PPD_UI_PICKONE"; break; case PPD_UI_PICKMANY: cs = "PPD_UI_PICKMANY"; break; } switch (option->section) { case PPD_ORDER_ANY: sec = "PPD_ORDER_ANY"; break; case PPD_ORDER_DOCUMENT: sec = "PPD_ORDER_DOCUMENT"; break; case PPD_ORDER_EXIT: sec = "PPD_ORDER_EXIT"; break; case PPD_ORDER_JCL: sec = "PPD_ORDER_JCL"; break; case PPD_ORDER_PAGE: sec = "PPD_ORDER_PAGE"; break; case PPD_ORDER_PROLOG: sec = "PPD_ORDER_PROLOG"; break; } printf("\t%d = \"%s\"\n" "\t\tkeyword=\"%s\"\n" "\t\tdefchoice=\"%s\"\n" "\t\ttext=\"%s\"\n" "\t\tui=%s\n" "\t\tsection=%s\n" "\t\torder=%f\n", j, str_rep(option->text), str_rep(option->keyword), str_rep(option->defchoice), str_rep(option->text), cs, sec, option->order); printf("\t\t---choices---\n"); clist = option->choices; k = 0; /* if (clist == NULL) printf("NULL"); */ while (clist) { choice = PPD_CHOICE(clist->data); printf("\t\t%d = \"%s\" choice=\"%s\"\n", k, str_rep(choice->text), str_rep(choice->choice)); k++; clist = g_slist_next(clist); } j++; } i++; } printf("---Sizes---\n"); list = ppd->sizes; i = 0; /* if (list == NULL) printf("NULL\n"); */ while (list) { size = PPD_SIZE(list->data); printf("%d = \"%s\"\n" "\tsize=[ %f %f ]\n" "\tmargins=[ %f %f %f %f ]\n", i, str_rep(size->name), size->width, size->length, size->left, size->top, size->right, size->bottom); i++; list = g_slist_next(list); } printf("---Constraints---\n"); list = ppd->consts; i = 0; /* if (list == NULL) printf("NULL\n"); */ while (list) { cons = PPD_CONSTRAINT(list->data); printf("\"%s\"=\"%s\" conflicts with \"%s\"=\"%s\"\n", str_rep(cons->option1), str_rep(cons->choice1), str_rep(cons->option2), str_rep(cons->choice2)); i++; list = g_slist_next(list); } printf("---Fonts---\n"); for (list = ppd->fonts; list != NULL; list = g_slist_next(list)) printf("%s\n", ((char *)list->data)); printf("---Profiles---\n"); list = ppd->profiles; /* if (list == NULL) printf("NULL\n"); */ i = 0; while (list) { profile = PPD_PROFILE(list->data); printf("\tresolution=\"%s\"\n" "\tmedia_type=\"%s\"\n" "\tdensiy=%f\n" "\tgamma=%f\n" "matrix=[%f %f %f] [%f %f %f] [%f %f %f]\n", str_rep(profile->resolution), str_rep(profile->media_type), 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]); i++; list = g_slist_next(list); } printf("---Filters---\n"); for (list = ppd->filters; list != NULL; list = g_slist_next(list)) printf("%s\n", (char *)list->data); } /* * End */