ppd_file_t * /* O - PPD file */ SetCommonOptions( int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ int change_size) /* I - Change page size? */ { ppd_file_t *ppd; /* PPD file */ ppd_size_t *pagesize; /* Current page size */ const char *val; /* Option value */ #ifdef LC_TIME setlocale(LC_TIME, ""); #endif /* LC_TIME */ ppd = ppdOpenFile(getenv("PPD")); ppdMarkDefaults(ppd); cupsMarkOptions(ppd, num_options, options); if ((pagesize = ppdPageSize(ppd, NULL)) != NULL) { PageWidth = pagesize->width; PageLength = pagesize->length; PageTop = pagesize->top; PageBottom = pagesize->bottom; PageLeft = pagesize->left; PageRight = pagesize->right; fprintf(stderr, "DEBUG: Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n", PageWidth, PageLength, PageLeft, PageBottom, PageRight, PageTop); } if (ppd != NULL) { ColorDevice = ppd->color_device; LanguageLevel = ppd->language_level; } if ((val = cupsGetOption("landscape", num_options, options)) != NULL) { if (_cups_strcasecmp(val, "no") != 0 && _cups_strcasecmp(val, "off") != 0 && _cups_strcasecmp(val, "false") != 0) { if (ppd && ppd->landscape > 0) Orientation = 1; else Orientation = 3; } } else if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL) { /* * Map IPP orientation values to 0 to 3: * * 3 = 0 degrees = 0 * 4 = 90 degrees = 1 * 5 = -90 degrees = 3 * 6 = 180 degrees = 2 */ Orientation = atoi(val) - 3; if (Orientation >= 2) Orientation ^= 1; } if ((val = cupsGetOption("page-left", num_options, options)) != NULL) { switch (Orientation & 3) { case 0 : PageLeft = (float)atof(val); break; case 1 : PageBottom = (float)atof(val); break; case 2 : PageRight = PageWidth - (float)atof(val); break; case 3 : PageTop = PageLength - (float)atof(val); break; } } if ((val = cupsGetOption("page-right", num_options, options)) != NULL) { switch (Orientation & 3) { case 0 : PageRight = PageWidth - (float)atof(val); break; case 1 : PageTop = PageLength - (float)atof(val); break; case 2 : PageLeft = (float)atof(val); break; case 3 : PageBottom = (float)atof(val); break; } } if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL) { switch (Orientation & 3) { case 0 : PageBottom = (float)atof(val); break; case 1 : PageLeft = (float)atof(val); break; case 2 : PageTop = PageLength - (float)atof(val); break; case 3 : PageRight = PageWidth - (float)atof(val); break; } } if ((val = cupsGetOption("page-top", num_options, options)) != NULL) { switch (Orientation & 3) { case 0 : PageTop = PageLength - (float)atof(val); break; case 1 : PageRight = PageWidth - (float)atof(val); break; case 2 : PageBottom = (float)atof(val); break; case 3 : PageLeft = (float)atof(val); break; } } if (change_size) UpdatePageVars(); if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") || ppdIsMarked(ppd, "Duplex", "DuplexTumble") || ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") || ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") || ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") || ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") || ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") || ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble")) Duplex = 1; return (ppd); }
int /* O - 1 if conflicts exist, 0 otherwise */ cupsMarkOptions( ppd_file_t *ppd, /* I - PPD file */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { int i, j; /* Looping vars */ char *ptr, /* Pointer into string */ s[255]; /* Temporary string */ const char *val, /* Pointer into value */ *media, /* media option */ *output_bin, /* output-bin option */ *page_size, /* PageSize option */ *ppd_keyword, /* PPD keyword */ *print_color_mode, /* print-color-mode option */ *print_quality, /* print-quality option */ *sides; /* sides option */ cups_option_t *optptr; /* Current option */ ppd_attr_t *attr; /* PPD attribute */ _ppd_cache_t *cache; /* PPD cache and mapping data */ /* * Check arguments... */ if (!ppd || num_options <= 0 || !options) return (0); ppd_debug_marked(ppd, "Before..."); /* * Do special handling for finishings, media, output-bin, output-mode, * print-color-mode, print-quality, and PageSize... */ media = cupsGetOption("media", num_options, options); output_bin = cupsGetOption("output-bin", num_options, options); page_size = cupsGetOption("PageSize", num_options, options); print_quality = cupsGetOption("print-quality", num_options, options); sides = cupsGetOption("sides", num_options, options); if ((print_color_mode = cupsGetOption("print-color-mode", num_options, options)) == NULL) print_color_mode = cupsGetOption("output-mode", num_options, options); if ((media || output_bin || print_color_mode || print_quality || sides) && !ppd->cache) { /* * Load PPD cache and mapping data as needed... */ ppd->cache = _ppdCacheCreateWithPPD(ppd); } cache = ppd->cache; if (media) { /* * Loop through the option string, separating it at commas and marking each * individual option as long as the corresponding PPD option (PageSize, * InputSlot, etc.) is not also set. * * For PageSize, we also check for an empty option value since some versions * of MacOS X use it to specify auto-selection of the media based solely on * the size. */ for (val = media; *val;) { /* * Extract the sub-option from the string... */ for (ptr = s; *val && *val != ',' && (size_t)(ptr - s) < (sizeof(s) - 1);) *ptr++ = *val++; *ptr++ = '\0'; if (*val == ',') val ++; /* * Mark it... */ if (!page_size || !page_size[0]) { if (!_cups_strncasecmp(s, "Custom.", 7) || ppdPageSize(ppd, s)) ppd_mark_option(ppd, "PageSize", s); else if ((ppd_keyword = _ppdCacheGetPageSize(cache, NULL, s, NULL)) != NULL) ppd_mark_option(ppd, "PageSize", ppd_keyword); } if (cache && cache->source_option && !cupsGetOption(cache->source_option, num_options, options) && (ppd_keyword = _ppdCacheGetInputSlot(cache, NULL, s)) != NULL) ppd_mark_option(ppd, cache->source_option, ppd_keyword); if (!cupsGetOption("MediaType", num_options, options) && (ppd_keyword = _ppdCacheGetMediaType(cache, NULL, s)) != NULL) ppd_mark_option(ppd, "MediaType", ppd_keyword); } } if (cache) { if (!cupsGetOption("com.apple.print.DocumentTicket.PMSpoolFormat", num_options, options) && !cupsGetOption("APPrinterPreset", num_options, options) && (print_color_mode || print_quality)) { /* * Map output-mode and print-quality to a preset... */ _pwg_print_color_mode_t pwg_pcm;/* print-color-mode index */ _pwg_print_quality_t pwg_pq; /* print-quality index */ cups_option_t *preset;/* Current preset option */ if (print_color_mode && !strcmp(print_color_mode, "monochrome")) pwg_pcm = _PWG_PRINT_COLOR_MODE_MONOCHROME; else pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR; if (print_quality) { pwg_pq = (_pwg_print_quality_t)(atoi(print_quality) - IPP_QUALITY_DRAFT); if (pwg_pq < _PWG_PRINT_QUALITY_DRAFT) pwg_pq = _PWG_PRINT_QUALITY_DRAFT; else if (pwg_pq > _PWG_PRINT_QUALITY_HIGH) pwg_pq = _PWG_PRINT_QUALITY_HIGH; } else pwg_pq = _PWG_PRINT_QUALITY_NORMAL; if (cache->num_presets[pwg_pcm][pwg_pq] == 0) { /* * Try to find a preset that works so that we maximize the chances of us * getting a good print using IPP attributes. */ if (cache->num_presets[pwg_pcm][_PWG_PRINT_QUALITY_NORMAL] > 0) pwg_pq = _PWG_PRINT_QUALITY_NORMAL; else if (cache->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_pq] > 0) pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR; else { pwg_pq = _PWG_PRINT_QUALITY_NORMAL; pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR; } } if (cache->num_presets[pwg_pcm][pwg_pq] > 0) { /* * Copy the preset options as long as the corresponding names are not * already defined in the IPP request... */ for (i = cache->num_presets[pwg_pcm][pwg_pq], preset = cache->presets[pwg_pcm][pwg_pq]; i > 0; i --, preset ++) { if (!cupsGetOption(preset->name, num_options, options)) ppd_mark_option(ppd, preset->name, preset->value); } } } if (output_bin && !cupsGetOption("OutputBin", num_options, options) && (ppd_keyword = _ppdCacheGetOutputBin(cache, output_bin)) != NULL) { /* * Map output-bin to OutputBin... */ ppd_mark_option(ppd, "OutputBin", ppd_keyword); } if (sides && cache->sides_option && !cupsGetOption(cache->sides_option, num_options, options)) { /* * Map sides to duplex option... */ if (!strcmp(sides, "one-sided") && cache->sides_1sided) ppd_mark_option(ppd, cache->sides_option, cache->sides_1sided); else if (!strcmp(sides, "two-sided-long-edge") && cache->sides_2sided_long) ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_long); else if (!strcmp(sides, "two-sided-short-edge") && cache->sides_2sided_short) ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_short); } } /* * Mark other options... */ for (i = num_options, optptr = options; i > 0; i --, optptr ++) if (!_cups_strcasecmp(optptr->name, "media") || !_cups_strcasecmp(optptr->name, "output-bin") || !_cups_strcasecmp(optptr->name, "output-mode") || !_cups_strcasecmp(optptr->name, "print-quality") || !_cups_strcasecmp(optptr->name, "sides")) continue; else if (!_cups_strcasecmp(optptr->name, "resolution") || !_cups_strcasecmp(optptr->name, "printer-resolution")) { ppd_mark_option(ppd, "Resolution", optptr->value); ppd_mark_option(ppd, "SetResolution", optptr->value); /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */ ppd_mark_option(ppd, "JCLResolution", optptr->value); /* HP */ ppd_mark_option(ppd, "CNRes_PGP", optptr->value); /* Canon */ } else if (!_cups_strcasecmp(optptr->name, "multiple-document-handling")) { if (!cupsGetOption("Collate", num_options, options) && ppdFindOption(ppd, "Collate")) { if (_cups_strcasecmp(optptr->value, "separate-documents-uncollated-copies")) ppd_mark_option(ppd, "Collate", "True"); else ppd_mark_option(ppd, "Collate", "False"); } } else if (!_cups_strcasecmp(optptr->name, "finishings")) { /* * Lookup cupsIPPFinishings attributes for each value... */ for (ptr = optptr->value; *ptr;) { /* * Get the next finishings number... */ if (!isdigit(*ptr & 255)) break; if ((j = (int)strtol(ptr, &ptr, 10)) < 3) break; /* * Skip separator as needed... */ if (*ptr == ',') ptr ++; /* * Look it up in the PPD file... */ sprintf(s, "%d", j); if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL) continue; /* * Apply "*Option Choice" settings from the attribute value... */ ppd_mark_choices(ppd, attr->value); } } else if (!_cups_strcasecmp(optptr->name, "APPrinterPreset")) { /* * Lookup APPrinterPreset value... */ if ((attr = ppdFindAttr(ppd, "APPrinterPreset", optptr->value)) != NULL) { /* * Apply "*Option Choice" settings from the attribute value... */ ppd_mark_choices(ppd, attr->value); } } else if (!_cups_strcasecmp(optptr->name, "mirror")) ppd_mark_option(ppd, "MirrorPrint", optptr->value); else ppd_mark_option(ppd, optptr->name, optptr->value); ppd_debug_marked(ppd, "After..."); return (ppdConflicts(ppd) > 0); }
int /* O - 1 on success, 0 on failure */ cupsResolveConflicts( ppd_file_t *ppd, /* I - PPD file */ const char *option, /* I - Newly selected option or @code NULL@ for none */ const char *choice, /* I - Newly selected choice or @code NULL@ for none */ int *num_options, /* IO - Number of additional selected options */ cups_option_t **options) /* IO - Additional selected options */ { int i, /* Looping var */ tries, /* Number of tries */ num_newopts; /* Number of new options */ cups_option_t *newopts; /* New options */ cups_array_t *active = NULL, /* Active constraints */ *pass, /* Resolvers for this pass */ *resolvers, /* Resolvers we have used */ *test; /* Test array for conflicts */ _ppd_cups_uiconsts_t *consts; /* Current constraints */ _ppd_cups_uiconst_t *constptr; /* Current constraint */ ppd_attr_t *resolver; /* Current resolver */ const char *resval; /* Pointer into resolver value */ char resoption[PPD_MAX_NAME], /* Current resolver option */ reschoice[PPD_MAX_NAME], /* Current resolver choice */ *resptr, /* Pointer into option/choice */ firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ const char *value; /* Selected option value */ int changed; /* Did we change anything? */ ppd_choice_t *marked; /* Marked choice */ /* * Range check input... */ if (!ppd || !num_options || !options || (option == NULL) != (choice == NULL)) return (0); /* * Build a shadow option array... */ num_newopts = 0; newopts = NULL; for (i = 0; i < *num_options; i ++) num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value, num_newopts, &newopts); if (option && _cups_strcasecmp(option, "Collate")) num_newopts = cupsAddOption(option, choice, num_newopts, &newopts); /* * Loop until we have no conflicts... */ cupsArraySave(ppd->sorted_attrs); resolvers = NULL; pass = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); tries = 0; while (tries < 100 && (active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts, _PPD_ALL_CONSTRAINTS)) != NULL) { tries ++; if (!resolvers) resolvers = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0; consts; consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(active)) { if (consts->resolver[0]) { /* * Look up the resolver... */ if (cupsArrayFind(pass, consts->resolver)) continue; /* Already applied this resolver... */ if (cupsArrayFind(resolvers, consts->resolver)) { /* * Resolver loop! */ DEBUG_printf(("1cupsResolveConflicts: Resolver loop with %s!", consts->resolver)); goto error; } if ((resolver = ppdFindAttr(ppd, "cupsUIResolver", consts->resolver)) == NULL) { DEBUG_printf(("1cupsResolveConflicts: Resolver %s not found!", consts->resolver)); goto error; } if (!resolver->value) { DEBUG_printf(("1cupsResolveConflicts: Resolver %s has no value!", consts->resolver)); goto error; } /* * Add the options from the resolver... */ cupsArrayAdd(pass, consts->resolver); cupsArrayAdd(resolvers, consts->resolver); for (resval = resolver->value; *resval && !changed;) { while (_cups_isspace(*resval)) resval ++; if (*resval != '*') break; for (resval ++, resptr = resoption; *resval && !_cups_isspace(*resval); resval ++) if (resptr < (resoption + sizeof(resoption) - 1)) *resptr++ = *resval; *resptr = '\0'; while (_cups_isspace(*resval)) resval ++; for (resptr = reschoice; *resval && !_cups_isspace(*resval); resval ++) if (resptr < (reschoice + sizeof(reschoice) - 1)) *resptr++ = *resval; *resptr = '\0'; if (!resoption[0] || !reschoice[0]) break; /* * Is this the option we are changing? */ snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption); if (option && (!_cups_strcasecmp(resoption, option) || !_cups_strcasecmp(firstpage, option) || (!_cups_strcasecmp(option, "PageSize") && !_cups_strcasecmp(resoption, "PageRegion")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") && !_cups_strcasecmp(resoption, "PageSize")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") && !_cups_strcasecmp(resoption, "PageRegion")) || (!_cups_strcasecmp(option, "PageRegion") && !_cups_strcasecmp(resoption, "PageSize")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && !_cups_strcasecmp(resoption, "PageSize")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && !_cups_strcasecmp(resoption, "PageRegion")))) continue; /* * Try this choice... */ if ((test = ppd_test_constraints(ppd, resoption, reschoice, num_newopts, newopts, _PPD_ALL_CONSTRAINTS)) == NULL) { /* * That worked... */ changed = 1; } else cupsArrayDelete(test); /* * Add the option/choice from the resolver regardless of whether it * worked; this makes sure that we can cascade several changes to * make things resolve... */ num_newopts = cupsAddOption(resoption, reschoice, num_newopts, &newopts); } } else { /* * Try resolving by choosing the default values for non-installable * options, then by iterating through the possible choices... */ int j; /* Looping var */ ppd_choice_t *cptr; /* Current choice */ ppd_size_t *size; /* Current page size */ for (i = consts->num_constraints, constptr = consts->constraints; i > 0 && !changed; i --, constptr ++) { /* * Can't resolve by changing an installable option... */ if (constptr->installable) continue; /* * Is this the option we are changing? */ if (option && (!_cups_strcasecmp(constptr->option->keyword, option) || (!_cups_strcasecmp(option, "PageSize") && !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) || (!_cups_strcasecmp(option, "PageRegion") && !_cups_strcasecmp(constptr->option->keyword, "PageSize")))) continue; /* * Get the current option choice... */ if ((value = cupsGetOption(constptr->option->keyword, num_newopts, newopts)) == NULL) { if (!_cups_strcasecmp(constptr->option->keyword, "PageSize") || !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) { if ((value = cupsGetOption("PageSize", num_newopts, newopts)) == NULL) value = cupsGetOption("PageRegion", num_newopts, newopts); if (!value) { if ((size = ppdPageSize(ppd, NULL)) != NULL) value = size->name; else value = ""; } } else { marked = ppdFindMarkedChoice(ppd, constptr->option->keyword); value = marked ? marked->choice : ""; } } if (!_cups_strncasecmp(value, "Custom.", 7)) value = "Custom"; /* * Try the default choice... */ test = NULL; if (_cups_strcasecmp(value, constptr->option->defchoice) && (test = ppd_test_constraints(ppd, constptr->option->keyword, constptr->option->defchoice, num_newopts, newopts, _PPD_OPTION_CONSTRAINTS)) == NULL) { /* * That worked... */ num_newopts = cupsAddOption(constptr->option->keyword, constptr->option->defchoice, num_newopts, &newopts); changed = 1; } else { /* * Try each choice instead... */ for (j = constptr->option->num_choices, cptr = constptr->option->choices; j > 0; j --, cptr ++) { cupsArrayDelete(test); test = NULL; if (_cups_strcasecmp(value, cptr->choice) && _cups_strcasecmp(constptr->option->defchoice, cptr->choice) && _cups_strcasecmp("Custom", cptr->choice) && (test = ppd_test_constraints(ppd, constptr->option->keyword, cptr->choice, num_newopts, newopts, _PPD_OPTION_CONSTRAINTS)) == NULL) { /* * This choice works... */ num_newopts = cupsAddOption(constptr->option->keyword, cptr->choice, num_newopts, &newopts); changed = 1; break; } } cupsArrayDelete(test); } } } } if (!changed) { DEBUG_puts("1cupsResolveConflicts: Unable to automatically resolve " "constraint!"); goto error; } cupsArrayClear(pass); cupsArrayDelete(active); active = NULL; } if (tries >= 100) goto error; /* * Free the caller's option array... */ cupsFreeOptions(*num_options, *options); /* * If Collate is the option we are testing, add it here. Otherwise, remove * any Collate option from the resolve list since the filters automatically * handle manual collation... */ if (option && !_cups_strcasecmp(option, "Collate")) num_newopts = cupsAddOption(option, choice, num_newopts, &newopts); else num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts); /* * Return the new list of options to the caller... */ *num_options = num_newopts; *options = newopts; cupsArrayDelete(pass); cupsArrayDelete(resolvers); cupsArrayRestore(ppd->sorted_attrs); DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts)); #ifdef DEBUG for (i = 0; i < num_newopts; i ++) DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i, newopts[i].name, newopts[i].value)); #endif /* DEBUG */ return (1); /* * If we get here, we failed to resolve... */ error: cupsFreeOptions(num_newopts, newopts); cupsArrayDelete(active); cupsArrayDelete(pass); cupsArrayDelete(resolvers); cupsArrayRestore(ppd->sorted_attrs); DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!"); return (0); }
static cups_array_t * /* O - Array of active constraints */ ppd_test_constraints( ppd_file_t *ppd, /* I - PPD file */ const char *option, /* I - Current option */ const char *choice, /* I - Current choice */ int num_options, /* I - Number of additional options */ cups_option_t *options, /* I - Additional options */ int which) /* I - Which constraints to test */ { int i; /* Looping var */ _ppd_cups_uiconsts_t *consts; /* Current constraints */ _ppd_cups_uiconst_t *constptr; /* Current constraint */ ppd_choice_t key, /* Search key */ *marked; /* Marked choice */ cups_array_t *active = NULL; /* Active constraints */ const char *value, /* Current value */ *firstvalue; /* AP_FIRSTPAGE_Keyword value */ char firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ DEBUG_printf(("7ppd_test_constraints(ppd=%p, option=\"%s\", choice=\"%s\", " "num_options=%d, options=%p, which=%d)", ppd, option, choice, num_options, options, which)); if (!ppd->cups_uiconstraints) ppd_load_constraints(ppd); DEBUG_printf(("9ppd_test_constraints: %d constraints!", cupsArrayCount(ppd->cups_uiconstraints))); cupsArraySave(ppd->marked); for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints); consts; consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints)) { DEBUG_printf(("9ppd_test_constraints: installable=%d, resolver=\"%s\", " "num_constraints=%d option1=\"%s\", choice1=\"%s\", " "option2=\"%s\", choice2=\"%s\", ...", consts->installable, consts->resolver, consts->num_constraints, consts->constraints[0].option->keyword, consts->constraints[0].choice ? consts->constraints[0].choice->choice : "", consts->constraints[1].option->keyword, consts->constraints[1].choice ? consts->constraints[1].choice->choice : "")); if (consts->installable && which < _PPD_INSTALLABLE_CONSTRAINTS) continue; /* Skip installable option constraint */ if (!consts->installable && which == _PPD_INSTALLABLE_CONSTRAINTS) continue; /* Skip non-installable option constraint */ if (which == _PPD_OPTION_CONSTRAINTS && option) { /* * Skip constraints that do not involve the current option... */ for (i = consts->num_constraints, constptr = consts->constraints; i > 0; i --, constptr ++) { if (!_cups_strcasecmp(constptr->option->keyword, option)) break; if (!_cups_strncasecmp(option, "AP_FIRSTPAGE_", 13) && !_cups_strcasecmp(constptr->option->keyword, option + 13)) break; } if (!i) continue; } DEBUG_puts("9ppd_test_constraints: Testing..."); for (i = consts->num_constraints, constptr = consts->constraints; i > 0; i --, constptr ++) { DEBUG_printf(("9ppd_test_constraints: %s=%s?", constptr->option->keyword, constptr->choice ? constptr->choice->choice : "")); if (constptr->choice && (!_cups_strcasecmp(constptr->option->keyword, "PageSize") || !_cups_strcasecmp(constptr->option->keyword, "PageRegion"))) { /* * PageSize and PageRegion are used depending on the selected input slot * and manual feed mode. Validate against the selected page size instead * of an individual option... */ if (option && choice && (!_cups_strcasecmp(option, "PageSize") || !_cups_strcasecmp(option, "PageRegion"))) { value = choice; } else if ((value = cupsGetOption("PageSize", num_options, options)) == NULL) if ((value = cupsGetOption("PageRegion", num_options, options)) == NULL) if ((value = cupsGetOption("media", num_options, options)) == NULL) { ppd_size_t *size = ppdPageSize(ppd, NULL); if (size) value = size->name; } if (value && !_cups_strncasecmp(value, "Custom.", 7)) value = "Custom"; if (option && choice && (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") || !_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion"))) { firstvalue = choice; } else if ((firstvalue = cupsGetOption("AP_FIRSTPAGE_PageSize", num_options, options)) == NULL) firstvalue = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options, options); if (firstvalue && !_cups_strncasecmp(firstvalue, "Custom.", 7)) firstvalue = "Custom"; if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) && (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice))) { DEBUG_puts("9ppd_test_constraints: NO"); break; } } else if (constptr->choice) { /* * Compare against the constrained choice... */ if (option && choice && !_cups_strcasecmp(option, constptr->option->keyword)) { if (!_cups_strncasecmp(choice, "Custom.", 7)) value = "Custom"; else value = choice; } else if ((value = cupsGetOption(constptr->option->keyword, num_options, options)) != NULL) { if (!_cups_strncasecmp(value, "Custom.", 7)) value = "Custom"; } else if (constptr->choice->marked) value = constptr->choice->choice; else value = NULL; /* * Now check AP_FIRSTPAGE_option... */ snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", constptr->option->keyword); if (option && choice && !_cups_strcasecmp(option, firstpage)) { if (!_cups_strncasecmp(choice, "Custom.", 7)) firstvalue = "Custom"; else firstvalue = choice; } else if ((firstvalue = cupsGetOption(firstpage, num_options, options)) != NULL) { if (!_cups_strncasecmp(firstvalue, "Custom.", 7)) firstvalue = "Custom"; } else firstvalue = NULL; DEBUG_printf(("9ppd_test_constraints: value=%s, firstvalue=%s", value, firstvalue)); if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) && (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice))) { DEBUG_puts("9ppd_test_constraints: NO"); break; } } else if (option && choice && !_cups_strcasecmp(option, constptr->option->keyword)) { if (!_cups_strcasecmp(choice, "None") || !_cups_strcasecmp(choice, "Off") || !_cups_strcasecmp(choice, "False")) { DEBUG_puts("9ppd_test_constraints: NO"); break; } } else if ((value = cupsGetOption(constptr->option->keyword, num_options, options)) != NULL) { if (!_cups_strcasecmp(value, "None") || !_cups_strcasecmp(value, "Off") || !_cups_strcasecmp(value, "False")) { DEBUG_puts("9ppd_test_constraints: NO"); break; } } else { key.option = constptr->option; if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL || (!_cups_strcasecmp(marked->choice, "None") || !_cups_strcasecmp(marked->choice, "Off") || !_cups_strcasecmp(marked->choice, "False"))) { DEBUG_puts("9ppd_test_constraints: NO"); break; } } } if (i <= 0) { if (!active) active = cupsArrayNew(NULL, NULL); cupsArrayAdd(active, consts); DEBUG_puts("9ppd_test_constraints: Added..."); } } cupsArrayRestore(ppd->marked); DEBUG_printf(("8ppd_test_constraints: Found %d active constraints!", cupsArrayCount(active))); return (active); }
char * /* O - String containing option code or @code NULL@ if there is no option code */ ppdEmitString(ppd_file_t *ppd, /* I - PPD file record */ ppd_section_t section, /* I - Section to write */ float min_order) /* I - Lowest OrderDependency */ { int i, j, /* Looping vars */ count; /* Number of choices */ ppd_choice_t **choices; /* Choices */ ppd_size_t *size; /* Custom page size */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ size_t bufsize; /* Size of string buffer needed */ char *buffer, /* String buffer */ *bufptr, /* Pointer into buffer */ *bufend; /* End of buffer */ struct lconv *loc; /* Locale data */ DEBUG_printf(("ppdEmitString(ppd=%p, section=%d, min_order=%f)", ppd, section, min_order)); /* * Range check input... */ if (!ppd) return (NULL); /* * Use PageSize or PageRegion as required... */ ppd_handle_media(ppd); /* * Collect the options we need to emit... */ if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0) return (NULL); /* * Count the number of bytes that are required to hold all of the * option code... */ for (i = 0, bufsize = 1; i < count; i ++) { if (section == PPD_ORDER_JCL) { if (!_cups_strcasecmp(choices[i]->choice, "Custom") && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { /* * Add space to account for custom parameter substitution... */ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : case PPD_CUSTOM_INT : bufsize += 10; break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) bufsize += strlen(cparam->current.custom_string); break; } } } } else if (section != PPD_ORDER_EXIT) { bufsize += 3; /* [{\n */ if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") || !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) && !_cups_strcasecmp(choices[i]->choice, "Custom")) { DEBUG_puts("2ppdEmitString: Custom size set!"); bufsize += 37; /* %%BeginFeature: *CustomPageSize True\n */ bufsize += 50; /* Five 9-digit numbers + newline */ } else if (!_cups_strcasecmp(choices[i]->choice, "Custom") && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { bufsize += 23 + strlen(choices[i]->option->keyword) + 6; /* %%BeginFeature: *Customkeyword True\n */ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : case PPD_CUSTOM_INT : bufsize += 10; break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : bufsize += 3; if (cparam->current.custom_string) bufsize += 4 * strlen(cparam->current.custom_string); break; } } } else bufsize += 17 + strlen(choices[i]->option->keyword) + 1 + strlen(choices[i]->choice) + 1; /* %%BeginFeature: *keyword choice\n */ bufsize += 13; /* %%EndFeature\n */ bufsize += 22; /* } stopped cleartomark\n */ } if (choices[i]->code) bufsize += strlen(choices[i]->code) + 1; else bufsize += strlen(ppd_custom_code); } /* * Allocate memory... */ DEBUG_printf(("2ppdEmitString: Allocating %d bytes for string...", (int)bufsize)); if ((buffer = calloc(1, bufsize)) == NULL) { free(choices); return (NULL); } bufend = buffer + bufsize - 1; loc = localeconv(); /* * Copy the option code to the buffer... */ for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr)) if (section == PPD_ORDER_JCL) { if (!_cups_strcasecmp(choices[i]->choice, "Custom") && choices[i]->code && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { /* * Handle substitutions in custom JCL options... */ char *cptr; /* Pointer into code */ int pnum; /* Parameter number */ for (cptr = choices[i]->code; *cptr && bufptr < bufend;) { if (*cptr == '\\') { cptr ++; if (isdigit(*cptr & 255)) { /* * Substitute parameter... */ pnum = *cptr++ - '0'; while (isdigit(*cptr & 255)) pnum = pnum * 10 + *cptr++ - '0'; for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) if (cparam->order == pnum) break; if (cparam) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : bufptr = _cupsStrFormatd(bufptr, bufend, cparam->current.custom_real, loc); break; case PPD_CUSTOM_INT : snprintf(bufptr, bufend - bufptr, "%d", cparam->current.custom_int); bufptr += strlen(bufptr); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) { strlcpy(bufptr, cparam->current.custom_string, bufend - bufptr); bufptr += strlen(bufptr); } break; } } } else if (*cptr) *bufptr++ = *cptr++; } else *bufptr++ = *cptr++; } } else { /* * Otherwise just copy the option code directly... */ strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1); bufptr += strlen(bufptr); } } else if (section != PPD_ORDER_EXIT) { /* * Add wrapper commands to prevent printer errors for unsupported * options... */ strlcpy(bufptr, "[{\n", bufend - bufptr + 1); bufptr += 3; /* * Send DSC comments with option... */ DEBUG_printf(("2ppdEmitString: Adding code for %s=%s...", choices[i]->option->keyword, choices[i]->choice)); if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") || !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) && !_cups_strcasecmp(choices[i]->choice, "Custom")) { /* * Variable size; write out standard size options, using the * parameter positions defined in the PPD file... */ ppd_attr_t *attr; /* PPD attribute */ int pos, /* Position of custom value */ orientation; /* Orientation to use */ float values[5]; /* Values for custom command */ strlcpy(bufptr, "%%BeginFeature: *CustomPageSize True\n", bufend - bufptr + 1); bufptr += 37; size = ppdPageSize(ppd, "Custom"); memset(values, 0, sizeof(values)); if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL) { pos = atoi(attr->value) - 1; if (pos < 0 || pos > 4) pos = 0; } else pos = 0; values[pos] = size->width; if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL) { pos = atoi(attr->value) - 1; if (pos < 0 || pos > 4) pos = 1; } else pos = 1; values[pos] = size->length; /* * According to the Adobe PPD specification, an orientation of 1 * will produce a print that comes out upside-down with the X * axis perpendicular to the direction of feed, which is exactly * what we want to be consistent with non-PS printers. * * We could also use an orientation of 3 to produce output that * comes out rightside-up (this is the default for many large format * printer PPDs), however for consistency we will stick with the * value 1. * * If we wanted to get fancy, we could use orientations of 0 or * 2 and swap the width and length, however we don't want to get * fancy, we just want it to work consistently. * * The orientation value is range limited by the Orientation * parameter definition, so certain non-PS printer drivers that * only support an Orientation of 0 will get the value 0 as * expected. */ orientation = 1; if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Orientation")) != NULL) { int min_orient, max_orient; /* Minimum and maximum orientations */ if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient, &max_orient) != 3) pos = 4; else { pos --; if (pos < 0 || pos > 4) pos = 4; if (orientation > max_orient) orientation = max_orient; else if (orientation < min_orient) orientation = min_orient; } } else pos = 4; values[pos] = (float)orientation; for (pos = 0; pos < 5; pos ++) { bufptr = _cupsStrFormatd(bufptr, bufend, values[pos], loc); *bufptr++ = '\n'; } if (!choices[i]->code) { /* * This can happen with certain buggy PPD files that don't include * a CustomPageSize command sequence... We just use a generic * Level 2 command sequence... */ strlcpy(bufptr, ppd_custom_code, bufend - bufptr + 1); bufptr += strlen(bufptr); } } else if (!_cups_strcasecmp(choices[i]->choice, "Custom") && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { /* * Custom option... */ const char *s; /* Pointer into string value */ cups_array_t *params; /* Parameters in the correct output order */ params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL); for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) cupsArrayAdd(params, cparam); snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *Custom%s True\n", coption->keyword); bufptr += strlen(bufptr); for (cparam = (ppd_cparam_t *)cupsArrayFirst(params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : bufptr = _cupsStrFormatd(bufptr, bufend, cparam->current.custom_real, loc); *bufptr++ = '\n'; break; case PPD_CUSTOM_INT : snprintf(bufptr, bufend - bufptr + 1, "%d\n", cparam->current.custom_int); bufptr += strlen(bufptr); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : *bufptr++ = '('; if (cparam->current.custom_string) { for (s = cparam->current.custom_string; *s; s ++) { if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127) { snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *s & 255); bufptr += strlen(bufptr); } else *bufptr++ = *s; } } *bufptr++ = ')'; *bufptr++ = '\n'; break; } } cupsArrayDelete(params); } else { snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *%s %s\n", choices[i]->option->keyword, choices[i]->choice); bufptr += strlen(bufptr); } if (choices[i]->code && choices[i]->code[0]) { j = (int)strlen(choices[i]->code); memcpy(bufptr, choices[i]->code, j); bufptr += j; if (choices[i]->code[j - 1] != '\n') *bufptr++ = '\n'; } strlcpy(bufptr, "%%EndFeature\n" "} stopped cleartomark\n", bufend - bufptr + 1); bufptr += strlen(bufptr); DEBUG_printf(("2ppdEmitString: Offset in string is %d...", (int)(bufptr - buffer))); } else { strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1); bufptr += strlen(bufptr); } /* * Nul-terminate, free, and return... */ *bufptr = '\0'; free(choices); return (buffer); }
bool PrinterUtil::getPrinterMarginValues(const QString& printerName, const QString& pageSize, double& ptsTopMargin, double& ptsBottomMargin, double& ptsLeftMargin, double& ptsRightMargin) { bool retVal=false; #if defined(HAVE_CUPS) const char *filename; // tmp PPD filename filename=cupsGetPPD(printerName.toLocal8Bit().constData()); if (filename!=NULL) { ppd_file_t *ppd; // PPD data ppd = ppdOpenFile(filename); if (ppd!=NULL) { ppd_size_t *size; // page size data, null if printer doesnt support selected size size = ppdPageSize(ppd, pageSize.toLocal8Bit().constData()); if (size!=NULL) { //Store in pts for returning via getNewPrinterMargins in pts retVal=true; ptsTopMargin=size->length-size->top; ptsBottomMargin=size->bottom; ptsLeftMargin=size->left; ptsRightMargin=size->width-size->right; } ppdClose(ppd); } } #elif defined(_WIN32) DWORD nPaper; DWORD nPaperNames; typedef WCHAR wchar64[64]; nPaper = DeviceCapabilitiesW( (LPCWSTR) printerName.utf16(), NULL, DC_PAPERS, NULL, NULL ); nPaperNames = DeviceCapabilitiesW( (LPCWSTR) printerName.utf16(), NULL, DC_PAPERNAMES, NULL, NULL ); if ( (nPaper > 0) && (nPaperNames > 0) && (nPaper == nPaperNames) ) { int paperIndex = -1; DWORD *papers = new DWORD[nPaper]; wchar64 *paperNames = new wchar64[nPaperNames]; DWORD s1 = DeviceCapabilitiesW( (LPCWSTR) printerName.utf16(), NULL, DC_PAPERS, (LPWSTR) papers, NULL ); DWORD s2 = DeviceCapabilitiesW( (LPCWSTR) printerName.utf16(), NULL, DC_PAPERNAMES, (LPWSTR) paperNames, NULL ); for ( uint i = 0; i < nPaperNames; i++ ) { if ( pageSize == QString::fromUtf16((const ushort*) paperNames[i]) ) { paperIndex = i; break; } } if ( paperIndex >= 0 ) { Qt::HANDLE handle = NULL; if( OpenPrinterW( (LPWSTR) printerName.utf16(), &handle, NULL ) ) { // Retrieve DEVMODE structure for selected device uint size = DocumentPropertiesW( ScCore->primaryMainWindow()->winId(), handle, (LPWSTR) printerName.utf16(), NULL, NULL, 0); QByteArray devModeW(size, 0); DEVMODEW* devMode = (DEVMODEW*) devModeW.data(); DocumentPropertiesW( ScCore->primaryMainWindow()->winId(), handle, (LPWSTR) printerName.utf16(), devMode, NULL, DM_OUT_BUFFER); ClosePrinter( handle ); // Set paper size devMode->dmPaperSize = papers[paperIndex]; // Create device context HDC printerDC = CreateDCW( NULL, (LPWSTR) printerName.utf16(), NULL, devMode ); if( printerDC ) { retVal = true; int logPixelsX = GetDeviceCaps( printerDC, LOGPIXELSX ); int logPixelsY = GetDeviceCaps( printerDC, LOGPIXELSY ); int physicalOffsetX = GetDeviceCaps( printerDC, PHYSICALOFFSETX ); int physicalOffsetY = GetDeviceCaps( printerDC, PHYSICALOFFSETY ); ptsLeftMargin = ptsRightMargin = ( physicalOffsetX / (double) logPixelsX * 72 ); ptsTopMargin = ptsBottomMargin = ( physicalOffsetY / (double) logPixelsY * 72 ); DeleteDC(printerDC); } } } delete[] papers; delete[] paperNames; } #endif return retVal; }
static void ppd_handle_media(ppd_file_t *ppd) /* I - PPD file */ { ppd_choice_t *manual_feed, /* ManualFeed choice, if any */ *input_slot; /* InputSlot choice, if any */ ppd_size_t *size; /* Current media size */ ppd_attr_t *rpr; /* RequiresPageRegion value */ /* * This function determines what page size code to use, if any, for the * current media size, InputSlot, and ManualFeed selections. * * We use the PageSize code if: * * 1. A custom media size is selected. * 2. ManualFeed and InputSlot are not selected (or do not exist). * 3. ManualFeed is selected but is False and InputSlot is not selected or * the selection has no code - the latter check done to support "auto" or * "printer default" InputSlot options. * * We use the PageRegion code if: * * 4. RequiresPageRegion does not exist and the PPD contains cupsFilter * keywords, indicating this is a CUPS-based driver. * 5. RequiresPageRegion exists for the selected InputSlot (or "All" for any * InputSlot or ManualFeed selection) and is True. * * If none of the 5 conditions are true, no page size code is used and we * unmark any existing PageSize or PageRegion choices. */ if ((size = ppdPageSize(ppd, NULL)) == NULL) return; manual_feed = ppdFindMarkedChoice(ppd, "ManualFeed"); input_slot = ppdFindMarkedChoice(ppd, "InputSlot"); if (input_slot != NULL) rpr = ppdFindAttr(ppd, "RequiresPageRegion", input_slot->choice); else rpr = NULL; if (!rpr) rpr = ppdFindAttr(ppd, "RequiresPageRegion", "All"); if (!_cups_strcasecmp(size->name, "Custom") || (!manual_feed && !input_slot) || (manual_feed && !_cups_strcasecmp(manual_feed->choice, "False") && (!input_slot || (input_slot->code && !input_slot->code[0]))) || (!rpr && ppd->num_filters > 0)) { /* * Use PageSize code... */ ppdMarkOption(ppd, "PageSize", size->name); } else if (rpr && rpr->value && !_cups_strcasecmp(rpr->value, "True")) { /* * Use PageRegion code... */ ppdMarkOption(ppd, "PageRegion", size->name); } else { /* * Do not use PageSize or PageRegion code... */ ppd_choice_t *page; /* PageSize/Region choice, if any */ if ((page = ppdFindMarkedChoice(ppd, "PageSize")) != NULL) { /* * Unmark PageSize... */ page->marked = 0; cupsArrayRemove(ppd->marked, page); } if ((page = ppdFindMarkedChoice(ppd, "PageRegion")) != NULL) { /* * Unmark PageRegion... */ page->marked = 0; cupsArrayRemove(ppd->marked, page); } } }
static char* make_cmd_param(cups_option_t *p_cups_opt, int num_opt, ParamList *p_param, char *p_product, int len) { #ifdef DEBUG_PPD char *p_ppd_name = "debug.ppd"; #else char *p_ppd_name = getenv("PPD"); #endif ppd_file_t *p_ppd; char *cmd_buf = NULL; ppd_choice_t *p_choice; ppd_size_t *p_size; ppd_size_t *p_default_size; int reso; char gs_exec_buf[256]; char gs_cmd_buf[1024]; char *flt_cmd_buf = NULL; //For InkJet long minw_mm, maxw_mm; long minl_mm, maxl_mm; PpdToOptKey *p_opt_key_table = alloc_opt_key_table(p_ppd_name); PpdToOptKey *p_table = p_opt_key_table; ParamList *p_list = NULL; if( (p_ppd = ppdOpenFile(p_ppd_name)) == NULL ) return NULL; if( p_opt_key_table == NULL) return NULL; ppdMarkDefaults(p_ppd); // Obtain default page size setting. p_choice = ppdFindMarkedChoice(p_ppd, "PageSize"); p_default_size = ppdPageSize(p_ppd, p_choice->choice); mark_ps_param_options(p_ppd, p_param); cupsMarkOptions(p_ppd, num_opt, p_cups_opt); // Obtain page size setting. p_choice = ppdFindMarkedChoice(p_ppd, "PageSize"); p_size = ppdPageSize(p_ppd, p_choice->choice); if (!p_size || ((int)(p_size->width == 0)) || ((int)(p_size->length == 0))) { p_size = p_default_size; } // Obtain resolution setting. p_choice = ppdFindMarkedChoice(p_ppd, "Resolution"); reso = atoi(p_choice->choice); //Obtain product name. parse_product_name(p_ppd->product, p_product, len); get_min_max_width_length(p_opt_key_table, p_cups_opt, num_opt, &minw_mm, &maxw_mm, &minl_mm, &maxl_mm); // gs command strncpy(gs_exec_buf, GS_PATH, 256); strncat(gs_exec_buf, "/", 1); strncat(gs_exec_buf, GS_BIN, strlen(GS_BIN)); snprintf(gs_cmd_buf, 1023, "%s -r%d -g%dx%d -q -dNOPROMPT -dSAFER -sDEVICE=ppmraw -sOutputFile=- -| ", gs_exec_buf, reso, (int)(p_size->width * (float)reso / 72.0), (int)(p_size->length * (float)reso / 72.0)); // For InkJet bjfilter Command while( p_table->ppd_key != NULL ) { p_choice = ppdFindMarkedChoice(p_ppd, p_table->ppd_key); if( p_choice != NULL ) { char choice[256]; strncpy(choice, p_choice->choice, 256); if( !strcmp(p_table->ppd_key, "PageSize") && !strcmp(choice, "Custom") ) { char pw[256]; char pl[256]; long pw_mm, pl_mm; pw_mm = (long)((double)p_size->width * 2540.0 / 72.0); pl_mm = (long)((double)p_size->length * 2540.0 / 72.0); if( minw_mm != -1 && pw_mm < minw_mm ) pw_mm = minw_mm; if( maxw_mm != -1 && pw_mm > maxw_mm ) pw_mm = maxw_mm; if( minl_mm != -1 && pl_mm < minl_mm ) pl_mm = minl_mm; if( maxl_mm != -1 && pl_mm > maxl_mm ) pl_mm = maxw_mm; snprintf(pw, 255, "%ld", pw_mm); snprintf(pl, 255, "%ld", pl_mm); param_list_add(&p_list, p_table->opt_key, "user", 5); param_list_add(&p_list, "--paperwidth", pw, strlen(pw) + 1); param_list_add(&p_list, "--paperheight", pl, strlen(pl) + 1); } else { if( !strcmp(p_table->ppd_key, "PageSize") && is_borderless(choice) ) { param_list_add(&p_list, "--borderless", "", 1); } param_list_add(&p_list, p_table->opt_key, choice, strlen(choice) + 1); } } p_table++; } while( num_opt-- > 0 ) { char *opt_key = ppd_to_opt_key(p_opt_key_table, p_cups_opt->name); if( opt_key != NULL ) { char *value = p_cups_opt->value; param_list_add(&p_list, opt_key, value, strlen(value) + 1); } p_cups_opt++; } { char bbox_buf[256]; float dd = 1.0 - 36.0 / (float)reso; int left = (int)p_size->left; int top = (int)(p_size->top + dd); int right = left + (int)(p_size->right - p_size->left + dd); int bottom = top - (int)(p_size->top - p_size->bottom + dd); snprintf(bbox_buf, 255, "%-d,%-d,%-d,%-d", left, bottom, right, top); param_list_add(&p_list, "--bbox", bbox_buf, strlen(bbox_buf) + 1); } flt_cmd_buf = make_filter_param_line(p_product, reso, p_list); if( p_list != NULL ){ param_list_free(p_list); free_opt_key_table(p_opt_key_table); } ppdClose(p_ppd); if( flt_cmd_buf ) { int buf_len; buf_len = strlen(gs_cmd_buf) + strlen(flt_cmd_buf) + 1; if( (cmd_buf = (char*)malloc(buf_len)) != NULL ) { strcpy(cmd_buf, gs_cmd_buf); strcat(cmd_buf, flt_cmd_buf); } free(flt_cmd_buf); fprintf(stderr, "pstocanonbj: %s\n", cmd_buf); return cmd_buf; } else return NULL; }
static void ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */ const char *option, /* I - Option name */ const char *choice) /* I - Choice name */ { int i, j; /* Looping vars */ ppd_option_t *o; /* Option pointer */ ppd_choice_t *c, /* Choice pointer */ *oldc, /* Old choice pointer */ key; /* Search key for choice */ struct lconv *loc; /* Locale data */ DEBUG_printf(("7ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")", ppd, option, choice)); /* * AP_D_InputSlot is the "default input slot" on MacOS X, and setting * it clears the regular InputSlot choices... */ if (!_cups_strcasecmp(option, "AP_D_InputSlot")) { cupsArraySave(ppd->options); if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } cupsArrayRestore(ppd->options); } /* * Check for custom options... */ cupsArraySave(ppd->options); o = ppdFindOption(ppd, option); cupsArrayRestore(ppd->options); if (!o) return; loc = localeconv(); if (!_cups_strncasecmp(choice, "Custom.", 7)) { /* * Handle a custom option... */ if ((c = ppdFindChoice(o, "Custom")) == NULL) return; if (!_cups_strcasecmp(option, "PageSize")) { /* * Handle custom page sizes... */ ppdPageSize(ppd, choice); } else { /* * Handle other custom options... */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ char *units; /* Custom points units */ if ((coption = ppdFindCustomOption(ppd, option)) != NULL) { if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL) return; switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_REAL : cparam->current.custom_real = (float)_cupsStrScand(choice + 7, NULL, loc); break; case PPD_CUSTOM_POINTS : cparam->current.custom_points = (float)_cupsStrScand(choice + 7, &units, loc); if (units) { if (!_cups_strcasecmp(units, "cm")) cparam->current.custom_points *= 72.0f / 2.54f; else if (!_cups_strcasecmp(units, "mm")) cparam->current.custom_points *= 72.0f / 25.4f; else if (!_cups_strcasecmp(units, "m")) cparam->current.custom_points *= 72.0f / 0.0254f; else if (!_cups_strcasecmp(units, "in")) cparam->current.custom_points *= 72.0f; else if (!_cups_strcasecmp(units, "ft")) cparam->current.custom_points *= 12.0f * 72.0f; } break; case PPD_CUSTOM_INT : cparam->current.custom_int = atoi(choice + 7); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) _cupsStrFree(cparam->current.custom_string); cparam->current.custom_string = _cupsStrAlloc(choice + 7); break; } } } /* * Make sure that we keep the option marked below... */ choice = "Custom"; } else if (choice[0] == '{') { /* * Handle multi-value custom options... */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ char *units; /* Custom points units */ int num_vals; /* Number of values */ cups_option_t *vals, /* Values */ *val; /* Value */ if ((c = ppdFindChoice(o, "Custom")) == NULL) return; if ((coption = ppdFindCustomOption(ppd, option)) != NULL) { num_vals = cupsParseOptions(choice, 0, &vals); for (i = 0, val = vals; i < num_vals; i ++, val ++) { if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL) continue; switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_REAL : cparam->current.custom_real = (float)_cupsStrScand(val->value, NULL, loc); break; case PPD_CUSTOM_POINTS : cparam->current.custom_points = (float)_cupsStrScand(val->value, &units, loc); if (units) { if (!_cups_strcasecmp(units, "cm")) cparam->current.custom_points *= 72.0f / 2.54f; else if (!_cups_strcasecmp(units, "mm")) cparam->current.custom_points *= 72.0f / 25.4f; else if (!_cups_strcasecmp(units, "m")) cparam->current.custom_points *= 72.0f / 0.0254f; else if (!_cups_strcasecmp(units, "in")) cparam->current.custom_points *= 72.0f; else if (!_cups_strcasecmp(units, "ft")) cparam->current.custom_points *= 12.0f * 72.0f; } break; case PPD_CUSTOM_INT : cparam->current.custom_int = atoi(val->value); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) _cupsStrFree(cparam->current.custom_string); cparam->current.custom_string = _cupsStrRetain(val->value); break; } } cupsFreeOptions(num_vals, vals); } } else { for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) if (!_cups_strcasecmp(c->choice, choice)) break; if (!i) return; } /* * Option found; mark it and then handle unmarking any other options. */ if (o->ui != PPD_UI_PICKMANY) { /* * Unmark all other choices... */ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } if (!_cups_strcasecmp(option, "PageSize") || !_cups_strcasecmp(option, "PageRegion")) { /* * Mark current page size... */ for (j = 0; j < ppd->num_sizes; j ++) ppd->sizes[j].marked = !_cups_strcasecmp(ppd->sizes[j].name, choice); /* * Unmark the current PageSize or PageRegion setting, as * appropriate... */ cupsArraySave(ppd->options); if (!_cups_strcasecmp(option, "PageSize")) { if ((o = ppdFindOption(ppd, "PageRegion")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } } else { if ((o = ppdFindOption(ppd, "PageSize")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } } cupsArrayRestore(ppd->options); } else if (!_cups_strcasecmp(option, "InputSlot")) { /* * Unmark ManualFeed option... */ cupsArraySave(ppd->options); if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } cupsArrayRestore(ppd->options); } else if (!_cups_strcasecmp(option, "ManualFeed") && !_cups_strcasecmp(choice, "True")) { /* * Unmark InputSlot option... */ cupsArraySave(ppd->options); if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } cupsArrayRestore(ppd->options); } } c->marked = 1; cupsArrayAdd(ppd->marked, c); }
int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i, j, k, m; /* Looping vars */ const char *filename; /* File to load */ FILE *ppdfile; // Temporary file name (for reading from stdin) char tmpfile[19] = "/tmp/lphelp.XXXXXX"; const int blocksize = 1024; char buffer[blocksize]; int bytesread; // variables for parsing PPD file for usual options (boolean, enumerated) ppd_file_t *ppd; /* PPD file record */ ppd_size_t *size; /* Size record */ ppd_group_t *group; /* UI group */ ppd_option_t *option; /* Standard UI option */ ppd_choice_t *choice; /* Standard UI option choice */ static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" }; static char *sections[] = { "ANY", "DOCUMENT", "EXIT", "JCL", "PAGE", "PROLOG" }; // variables for parsing CUPS-O-MATIC info for numerical options (float, int) char line[1024], /* buffer for reading PPD file line by line to search numerical options */ item[1024], /* item to be defined (left of "=>") */ value[1024], /* value for item (right of "=>") */ argname[1024], /* name of the current argument */ comment[1024]; /* human-readable argument name */ const char *line_contents; /* contents of line */ const char *scan; /* pointer scanning the line */ char *writepointer; double min, max, defvalue; /* Range of numerical CUPS-O-MATIC option */ int opttype; /* 0 = other, 1 = int, 2 = float */ int openbrackets; /* How many curled brackets are open? */ int inquotes; /* are we in quotes now? */ int inargspart; /* are we in the arguments part now? */ /* * Display PPD files for each file listed on the command-line... */ if (argc == 1) { fputs("Usage: lphelp <filename1>.ppd [<filename2>.ppd ...]\n lphelp <printername1> [<printername2> ...]\n lphelp -\n", stderr); return (1); } for (i = 1; i < argc; i ++) { if ((strstr(argv[i], ".ppd")) || (strstr(argv[i], "-"))) filename = argv[i]; else filename = cupsGetPPD(argv[i]); if (strcmp(filename,"-") == 0) { if ((ppdfile = fdopen(mkstemp(tmpfile), "w")) == NULL) { fprintf(stderr, "Unable to generate temporary file!\n"); } while ((bytesread = fread(buffer, 1, blocksize, stdin)) > 0) { fwrite(buffer, 1, bytesread, ppdfile); } fclose(ppdfile); filename = tmpfile; } if ((ppd = ppdOpenFile(filename)) == NULL) { fprintf(stderr, "Unable to open \'%s\' as a PPD file!\n", filename); continue; } printf("==============================================================================\n\n"); printf("%s\n\n", ppd->modelname); printf("==============================================================================\n\n"); printf(" %s printer\n\n", ppd->color_device ? "Colour" : "Black & white"); printf(" Printer-specific options\n"); printf(" ------------------------\n\n"); printf(" Besides the options described in the CUPS software users manual\n"); printf(" (http://localhost:631/sum.html) you can use also the following options\n"); printf(" when you print on this printer with the \"lp\" or \"lpr\" command (a choice\n"); printf(" with the \"default\" mark represents the behaviour of the printer when the\n"); printf(" appropriate option is not given on the command line):\n\n"); for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) { for (k = 0, option = group->options; k < group->num_options; k ++, option ++) { if (strcmp(option->keyword, "PageRegion") != 0) { if ((strcmp(uis[option->ui],"BOOLEAN") == 0) || (strcmp(uis[option->ui],"PICKONE") == 0)) { printf(" %s: -o %s=<choice>\n\n", option->text, option->keyword); printf(" <choice> can be one of the following:\n\n"); } else { printf(" %s: -o %s=<choice1>,<choice2>,...\n\n", option->text, option->keyword); printf(" <choice1>, <choice2>, and so on can be out of the following:\n\n"); } if (strcmp(option->keyword, "PageSize") == 0) { for (m = option->num_choices, choice = option->choices; m > 0; m --, choice ++) { size = ppdPageSize(ppd, choice->choice); if (size == NULL) printf(" %s (%s, size unknown", choice->choice, choice->text); else printf(" %s (%s, size: %.2fx%.2fin", choice->choice, choice->text, size->width / 72.0, size->length / 72.0); if (strcmp(option->defchoice, choice->choice) == 0) puts(", default)"); else puts(")"); } } else { for (m = option->num_choices, choice = option->choices; m > 0; m --, choice ++) { printf(" %s (%s", choice->choice, choice->text); if (strcmp(option->defchoice, choice->choice) == 0) puts(", default)"); else puts(")"); } } printf("\n"); } } } ppdClose(ppd); // Search for numerical options of CUPS-O-MATIC if ((ppdfile = fopen(filename,"r")) == NULL) { fprintf(stderr, "Unable to open \'%s\' as a PPD file!\n", filename); continue; } // Reset all variables opttype = 0; min = 0.0; max = 0.0; defvalue = 0.0; openbrackets = 0; inquotes = 0; writepointer = item; inargspart = 0; // Read the PPD file again, line by line. while (fgets(line,sizeof(line),ppdfile)) { // evaluate only lines with CUPS-O-MATIC info if (line_contents = strstr(line,"*% COMDATA #")) { line_contents += 12; // Go to the text after // "*% COMDATA #" for (scan = line_contents; (*scan != '\n') && (*scan != '\0'); scan ++) { switch(*scan) { case '[': // open square bracket case '{': // open curled bracket if (!inquotes) { openbrackets ++; // we are on the left hand side now *writepointer = '\0'; writepointer = item; // in which type of block are we now? if ((openbrackets == 2) && (strncasecmp(item,"args",4) == 0)) { // we are entering the arguments section now inargspart = 1; } if ((openbrackets == 3) && (inargspart == 1)) { // new argument, get its name strcpy(argname,item); } // item already evaluated now item[0] = '\0'; } else {*writepointer = *scan; writepointer ++;} break; case ',': // end of logical line case ']': // close square bracket case '}': // close curled bracket if (!inquotes) { // right hand side completed, go to left hand side *writepointer = '\0'; writepointer = item; // evaluate logical line if (item[0]) { // Machine-readable argument name if ((openbrackets == 3) && (inargspart == 1) && (strcasecmp(item,"name") == 0)) { strcpy(argname,value); } // Human-readable argument name if ((openbrackets == 3) && (inargspart == 1) && (strcasecmp(item,"comment") == 0)) { strcpy(comment,value); } // argument type if ((openbrackets == 3) && (inargspart == 1) && (strcasecmp(item,"type") == 0)) { if (strcasecmp(value,"int") == 0) opttype = 1; if (strcasecmp(value,"float") == 0) opttype = 2; } // minimum value if ((openbrackets == 3) && (inargspart == 1) && (strcasecmp(item,"min") == 0)) { min = atof(value); } // maximum value if ((openbrackets == 3) && (inargspart == 1) && (strcasecmp(item,"max") == 0)) { max = atof(value); } // default value if ((openbrackets == 3) && (inargspart == 1) && (strcasecmp(item,"default") == 0)) { defvalue = atof(value); } // item already evaluated now item[0] = '\0'; } // close bracket if ((*scan == '}') || (*scan == ']')) { // which block did we complete now? if ((openbrackets == 2) && (inargspart == 1)) { // We are leaving the arguments part now inargspart = 0; } if ((openbrackets == 3) && (inargspart == 1)) { // The current option is completely parsed // Is the option a valid numerical option? if ((opttype > 0) && (min != max) && (argname[0])) { // Correct the default value, if necessary if (min < max) { if (defvalue < min) defvalue = min; if (defvalue > max) defvalue = max; } else { if (defvalue < max) defvalue = max; if (defvalue > min) defvalue = min; } // Show the found argument printf(" %s: -o %s=<value>\n\n", comment, argname); if (opttype == 1) { printf( " <value> must be an integer number in the range %d..%d\n", (int)(min),(int)(max)); printf( " The default value is %d\n\n", (int)(defvalue)); } else { printf( " <value> must be a decimal number in the range %.2f..%.2f\n", min,max); printf( " The default value is %.2f\n\n", defvalue); } } // reset the values argname[0] = '\0'; opttype = 0; min = 0.0; max = 0.0; defvalue = 0.0; } openbrackets --; } } else {*writepointer = *scan; writepointer ++;} break; case '\'': // quote if (!inquotes) { // open quote pair inquotes = 1; } else { // close quote pair inquotes = 0; } break; case '=': // "=>" if ((!inquotes) && (*(scan + 1) == '>')) { scan ++; // left hand side completed, go to right hand side *writepointer = '\0'; writepointer = value; } else {*writepointer = *scan; writepointer ++;} break; case ' ': // white space case '\t': if (!inquotes) { // ignore white space outside quotes } else {*writepointer = *scan; writepointer ++;} break; default: // write all other characters *writepointer = *scan; writepointer ++; break; } } inquotes = 0; // quote pairs cannot enclose more // than one line } } fclose(ppdfile); printf("\n\n\n"); } if (!(strstr(tmpfile, "XXXXXX"))) { unlink(tmpfile); } return (0); }
int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ ppd_file_t *ppd; /* PPD file loaded from disk */ int status; /* Status of tests (0 = success, 1 = fail) */ int conflicts; /* Number of conflicts */ char *s; /* String */ char buffer[8192]; /* String buffer */ const char *text, /* Localized text */ *val; /* Option value */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ ppd_size_t minsize, /* Minimum size */ maxsize, /* Maximum size */ *size; /* Current size */ ppd_attr_t *attr; /* Current attribute */ _ppd_cache_t *pc; /* PPD cache */ status = 0; if (argc == 1) { /* * Setup directories for locale stuff... */ if (access("locale", 0)) { mkdir("locale", 0777); mkdir("locale/fr", 0777); symlink("../../../locale/cups_fr.po", "locale/fr/cups_fr.po"); mkdir("locale/zh_TW", 0777); symlink("../../../locale/cups_zh_TW.po", "locale/zh_TW/cups_zh_TW.po"); } putenv("LOCALEDIR=locale"); putenv("SOFTWARE=CUPS"); /* * Do tests with test.ppd... */ fputs("ppdOpenFile(test.ppd): ", stdout); if ((ppd = _ppdOpenFile("test.ppd", _PPD_LOCALIZATION_ALL)) != NULL) puts("PASS"); else { ppd_status_t err; /* Last error in file */ int line; /* Line number in file */ status ++; err = ppdLastError(&line); printf("FAIL (%s on line %d)\n", ppdErrorString(err), line); } fputs("ppdFindAttr(wildcard): ", stdout); if ((attr = ppdFindAttr(ppd, "cupsTest", NULL)) == NULL) { status ++; puts("FAIL (not found)"); } else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo")) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdFindNextAttr(wildcard): ", stdout); if ((attr = ppdFindNextAttr(ppd, "cupsTest", NULL)) == NULL) { status ++; puts("FAIL (not found)"); } else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Bar")) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdFindAttr(Foo): ", stdout); if ((attr = ppdFindAttr(ppd, "cupsTest", "Foo")) == NULL) { status ++; puts("FAIL (not found)"); } else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo")) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdFindNextAttr(Foo): ", stdout); if ((attr = ppdFindNextAttr(ppd, "cupsTest", "Foo")) != NULL) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdMarkDefaults: ", stdout); ppdMarkDefaults(ppd); if ((conflicts = ppdConflicts(ppd)) == 0) puts("PASS"); else { status ++; printf("FAIL (%d conflicts)\n", conflicts); } fputs("ppdEmitString (defaults): ", stdout); if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL && !strcmp(s, default_code)) puts("PASS"); else { status ++; printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0, (int)strlen(default_code)); if (s) puts(s); } if (s) free(s); fputs("ppdEmitString (custom size and string): ", stdout); ppdMarkOption(ppd, "PageSize", "Custom.400x500"); ppdMarkOption(ppd, "StringOption", "{String1=\"value 1\" String2=value(2)}"); if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL && !strcmp(s, custom_code)) puts("PASS"); else { status ++; printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0, (int)strlen(custom_code)); if (s) puts(s); } if (s) free(s); /* * Test constraints... */ fputs("cupsGetConflicts(InputSlot=Envelope): ", stdout); ppdMarkOption(ppd, "PageSize", "Letter"); num_options = cupsGetConflicts(ppd, "InputSlot", "Envelope", &options); if (num_options != 2 || (val = cupsGetOption("PageRegion", num_options, options)) == NULL || _cups_strcasecmp(val, "Letter") || (val = cupsGetOption("PageSize", num_options, options)) == NULL || _cups_strcasecmp(val, "Letter")) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else puts("PASS"); fputs("ppdConflicts(): ", stdout); ppdMarkOption(ppd, "InputSlot", "Envelope"); if ((conflicts = ppdConflicts(ppd)) == 2) puts("PASS (2)"); else { printf("FAIL (%d)\n", conflicts); status ++; } fputs("cupsResolveConflicts(InputSlot=Envelope): ", stdout); num_options = 0; options = NULL; if (!cupsResolveConflicts(ppd, "InputSlot", "Envelope", &num_options, &options)) { puts("FAIL (Unable to resolve)"); status ++; } else if (num_options != 2 || !cupsGetOption("PageSize", num_options, options)) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else puts("PASS (Resolved by changing PageSize)"); cupsFreeOptions(num_options, options); fputs("cupsResolveConflicts(No option/choice): ", stdout); num_options = 0; options = NULL; if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) && num_options == 1 && !_cups_strcasecmp(options[0].name, "InputSlot") && !_cups_strcasecmp(options[0].value, "Tray")) puts("PASS (Resolved by changing InputSlot)"); else if (num_options > 0) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else { puts("FAIL (Unable to resolve)"); status ++; } cupsFreeOptions(num_options, options); fputs("ppdInstallableConflict(): ", stdout); if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") && !ppdInstallableConflict(ppd, "Duplex", "None")) puts("PASS"); else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble")) { puts("FAIL (Duplex=DuplexNoTumble did not conflict)"); status ++; } else { puts("FAIL (Duplex=None conflicted)"); status ++; } /* * ppdPageSizeLimits */ fputs("ppdPageSizeLimits: ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 36 || minsize.length != 36 || maxsize.width != 1080 || maxsize.length != 86400) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=36x36, max=1080x86400)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } /* * cupsMarkOptions with PWG and IPP size names. */ fputs("cupsMarkOptions(media=iso-a4): ", stdout); num_options = cupsAddOption("media", "iso-a4", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "A4")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); fputs("cupsMarkOptions(media=na_letter_8.5x11in): ", stdout); num_options = cupsAddOption("media", "na_letter_8.5x11in", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "Letter")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); fputs("cupsMarkOptions(media=oe_letter-fullbleed_8.5x11in): ", stdout); num_options = cupsAddOption("media", "oe_letter-fullbleed_8.5x11in", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "Letter.Fullbleed")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); fputs("cupsMarkOptions(media=A4): ", stdout); num_options = cupsAddOption("media", "A4", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "A4")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); /* * Custom sizes... */ fputs("cupsMarkOptions(media=Custom.8x10in): ", stdout); num_options = cupsAddOption("media", "Custom.8x10in", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "Custom") || size->width != 576 || size->length != 720) { printf("FAIL (%s - %gx%g)\n", size ? size->name : "unknown", size ? size->width : 0.0, size ? size->length : 0.0); status ++; } else puts("PASS"); /* * Test localization... */ fputs("ppdLocalizeIPPReason(text): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) && !strcmp(buffer, "Foo Reason")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Foo Reason\")\n", buffer); } fputs("ppdLocalizeIPPReason(http): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", "http", buffer, sizeof(buffer)) && !strcmp(buffer, "http://foo/bar.html")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"http://foo/bar.html\")\n", buffer); } fputs("ppdLocalizeIPPReason(help): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", "help", buffer, sizeof(buffer)) && !strcmp(buffer, "help:anchor='foo'%20bookID=Vendor%20Help")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"help:anchor='foo'%%20bookID=Vendor%%20Help\")\n", buffer); } fputs("ppdLocalizeIPPReason(file): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", "file", buffer, sizeof(buffer)) && !strcmp(buffer, "/help/foo/bar.html")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"/help/foo/bar.html\")\n", buffer); } putenv("LANG=fr"); putenv("LC_ALL=fr"); putenv("LC_CTYPE=fr"); putenv("LC_MESSAGES=fr"); fputs("ppdLocalizeIPPReason(fr text): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) && !strcmp(buffer, "La Long Foo Reason")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"La Long Foo Reason\")\n", buffer); } putenv("LANG=zh_TW"); putenv("LC_ALL=zh_TW"); putenv("LC_CTYPE=zh_TW"); putenv("LC_MESSAGES=zh_TW"); fputs("ppdLocalizeIPPReason(zh_TW text): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) && !strcmp(buffer, "Number 1 Foo Reason")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Number 1 Foo Reason\")\n", buffer); } /* * cupsMarkerName localization... */ putenv("LANG=en"); putenv("LC_ALL=en"); putenv("LC_CTYPE=en"); putenv("LC_MESSAGES=en"); fputs("ppdLocalizeMarkerName(bogus): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "bogus")) != NULL) { status ++; printf("FAIL (\"%s\" instead of NULL)\n", text); } else puts("PASS"); fputs("ppdLocalizeMarkerName(cyan): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL && !strcmp(text, "Cyan Toner")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Cyan Toner\")\n", text ? text : "(null)"); } putenv("LANG=fr"); putenv("LC_ALL=fr"); putenv("LC_CTYPE=fr"); putenv("LC_MESSAGES=fr"); fputs("ppdLocalizeMarkerName(fr cyan): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL && !strcmp(text, "La Toner Cyan")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"La Toner Cyan\")\n", text ? text : "(null)"); } putenv("LANG=zh_TW"); putenv("LC_ALL=zh_TW"); putenv("LC_CTYPE=zh_TW"); putenv("LC_MESSAGES=zh_TW"); fputs("ppdLocalizeMarkerName(zh_TW cyan): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL && !strcmp(text, "Number 1 Cyan Toner")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Number 1 Cyan Toner\")\n", text ? text : "(null)"); } ppdClose(ppd); /* * Test new constraints... */ fputs("ppdOpenFile(test2.ppd): ", stdout); if ((ppd = ppdOpenFile("test2.ppd")) != NULL) puts("PASS"); else { ppd_status_t err; /* Last error in file */ int line; /* Line number in file */ status ++; err = ppdLastError(&line); printf("FAIL (%s on line %d)\n", ppdErrorString(err), line); } fputs("ppdMarkDefaults: ", stdout); ppdMarkDefaults(ppd); if ((conflicts = ppdConflicts(ppd)) == 0) puts("PASS"); else { status ++; printf("FAIL (%d conflicts)\n", conflicts); } fputs("ppdEmitString (defaults): ", stdout); if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL && !strcmp(s, default2_code)) puts("PASS"); else { status ++; printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0, (int)strlen(default2_code)); if (s) puts(s); } if (s) free(s); fputs("ppdConflicts(): ", stdout); ppdMarkOption(ppd, "PageSize", "Env10"); ppdMarkOption(ppd, "InputSlot", "Envelope"); ppdMarkOption(ppd, "Quality", "Photo"); if ((conflicts = ppdConflicts(ppd)) == 1) puts("PASS (1)"); else { printf("FAIL (%d)\n", conflicts); status ++; } fputs("cupsResolveConflicts(Quality=Photo): ", stdout); num_options = 0; options = NULL; if (cupsResolveConflicts(ppd, "Quality", "Photo", &num_options, &options)) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else puts("PASS (Unable to resolve)"); cupsFreeOptions(num_options, options); fputs("cupsResolveConflicts(No option/choice): ", stdout); num_options = 0; options = NULL; if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) && num_options == 1 && !_cups_strcasecmp(options->name, "Quality") && !_cups_strcasecmp(options->value, "Normal")) puts("PASS"); else if (num_options > 0) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else { puts("FAIL (Unable to resolve!)"); status ++; } cupsFreeOptions(num_options, options); fputs("cupsResolveConflicts(loop test): ", stdout); ppdMarkOption(ppd, "PageSize", "A4"); ppdMarkOption(ppd, "InputSlot", "Tray"); ppdMarkOption(ppd, "Quality", "Photo"); num_options = 0; options = NULL; if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options)) puts("PASS"); else if (num_options > 0) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); } else puts("FAIL (No conflicts!)"); fputs("ppdInstallableConflict(): ", stdout); if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") && !ppdInstallableConflict(ppd, "Duplex", "None")) puts("PASS"); else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble")) { puts("FAIL (Duplex=DuplexNoTumble did not conflict)"); status ++; } else { puts("FAIL (Duplex=None conflicted)"); status ++; } /* * ppdPageSizeLimits */ ppdMarkDefaults(ppd); fputs("ppdPageSizeLimits(default): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 36 || minsize.length != 36 || maxsize.width != 1080 || maxsize.length != 86400) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=36x36, max=1080x86400)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } ppdMarkOption(ppd, "InputSlot", "Manual"); fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 100 || minsize.length != 100 || maxsize.width != 1000 || maxsize.length != 1000) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=100x100, max=1000x1000)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } ppdMarkOption(ppd, "Quality", "Photo"); fputs("ppdPageSizeLimits(Quality=Photo): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 200 || minsize.length != 200 || maxsize.width != 1000 || maxsize.length != 1000) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=200x200, max=1000x1000)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } ppdMarkOption(ppd, "InputSlot", "Tray"); fputs("ppdPageSizeLimits(Quality=Photo): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 300 || minsize.length != 300 || maxsize.width != 1080 || maxsize.length != 86400) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=300x300, max=1080x86400)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } } else { const char *filename; /* PPD filename */ struct stat fileinfo; /* File information */ if (!strncmp(argv[1], "-d", 2)) { const char *printer; /* Printer name */ if (argv[1][2]) printer = argv[1] + 2; else if (argv[2]) printer = argv[2]; else { puts("Usage: ./testppd -d printer"); return (1); } filename = cupsGetPPD(printer); if (!filename) { printf("%s: %s\n", printer, cupsLastErrorString()); return (1); } } else filename = argv[1]; if (lstat(filename, &fileinfo)) { printf("%s: %s\n", filename, strerror(errno)); return (1); } if (S_ISLNK(fileinfo.st_mode)) { char realfile[1024]; /* Real file path */ ssize_t realsize; /* Size of real file path */ if ((realsize = readlink(filename, realfile, sizeof(realfile) - 1)) < 0) strlcpy(realfile, "Unknown", sizeof(realfile)); else realfile[realsize] = '\0'; if (stat(realfile, &fileinfo)) printf("%s: symlink to \"%s\", %s\n", filename, realfile, strerror(errno)); else printf("%s: symlink to \"%s\", %ld bytes\n", filename, realfile, (long)fileinfo.st_size); } else printf("%s: regular file, %ld bytes\n", filename, (long)fileinfo.st_size); if ((ppd = ppdOpenFile(filename)) == NULL) { ppd_status_t err; /* Last error in file */ int line; /* Line number in file */ status ++; err = ppdLastError(&line); printf("%s: %s on line %d\n", argv[1], ppdErrorString(err), line); } else { int j, k; /* Looping vars */ ppd_group_t *group; /* Option group */ ppd_option_t *option; /* Option */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ ppd_const_t *c; /* UIConstraints */ char lang[255], /* LANG environment variable */ lc_all[255], /* LC_ALL environment variable */ lc_ctype[255], /* LC_CTYPE environment variable */ lc_messages[255];/* LC_MESSAGES environment variable */ if (argc > 2) { snprintf(lang, sizeof(lang), "LANG=%s", argv[2]); putenv(lang); snprintf(lc_all, sizeof(lc_all), "LC_ALL=%s", argv[2]); putenv(lc_all); snprintf(lc_ctype, sizeof(lc_ctype), "LC_CTYPE=%s", argv[2]); putenv(lc_ctype); snprintf(lc_messages, sizeof(lc_messages), "LC_MESSAGES=%s", argv[2]); putenv(lc_messages); } ppdLocalize(ppd); ppdMarkDefaults(ppd); if (argc > 3) { text = ppdLocalizeIPPReason(ppd, argv[3], NULL, buffer, sizeof(buffer)); printf("ppdLocalizeIPPReason(%s)=%s\n", argv[3], text ? text : "(null)"); return (text == NULL); } for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) { printf("%s (%s):\n", group->name, group->text); for (j = group->num_options, option = group->options; j > 0; j --, option ++) { printf(" %s (%s):\n", option->keyword, option->text); for (k = 0; k < option->num_choices; k ++) printf(" - %s%s (%s)\n", option->choices[k].marked ? "*" : "", option->choices[k].choice, option->choices[k].text); if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL) { for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : printf(" %s(%s): PPD_CUSTOM_CURVE (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_curve, cparam->maximum.custom_curve); break; case PPD_CUSTOM_INT : printf(" %s(%s): PPD_CUSTOM_INT (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_int, cparam->maximum.custom_int); break; case PPD_CUSTOM_INVCURVE : printf(" %s(%s): PPD_CUSTOM_INVCURVE (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_invcurve, cparam->maximum.custom_invcurve); break; case PPD_CUSTOM_PASSCODE : printf(" %s(%s): PPD_CUSTOM_PASSCODE (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_passcode, cparam->maximum.custom_passcode); break; case PPD_CUSTOM_PASSWORD : printf(" %s(%s): PPD_CUSTOM_PASSWORD (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_password, cparam->maximum.custom_password); break; case PPD_CUSTOM_POINTS : printf(" %s(%s): PPD_CUSTOM_POINTS (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_points, cparam->maximum.custom_points); break; case PPD_CUSTOM_REAL : printf(" %s(%s): PPD_CUSTOM_REAL (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_real, cparam->maximum.custom_real); break; case PPD_CUSTOM_STRING : printf(" %s(%s): PPD_CUSTOM_STRING (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_string, cparam->maximum.custom_string); break; } } } } } puts("\nSizes:"); for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++) printf(" %s = %gx%g, [%g %g %g %g]\n", size->name, size->width, size->length, size->left, size->bottom, size->right, size->top); puts("\nConstraints:"); for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++) printf(" *UIConstraints: *%s %s *%s %s\n", c->option1, c->choice1, c->option2, c->choice2); if (ppd->num_consts == 0) puts(" NO CONSTRAINTS"); puts("\nFilters:"); for (i = 0; i < ppd->num_filters; i ++) printf(" %s\n", ppd->filters[i]); if (ppd->num_filters == 0) puts(" NO FILTERS"); puts("\nAttributes:"); for (attr = (ppd_attr_t *)cupsArrayFirst(ppd->sorted_attrs); attr; attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) printf(" *%s %s/%s: \"%s\"\n", attr->name, attr->spec, attr->text, attr->value ? attr->value : ""); puts("\nPPD Cache:"); if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL) printf(" Unable to create: %s\n", cupsLastErrorString()); else { _ppdCacheWriteFile(pc, "t.cache", NULL); puts(" Wrote t.cache."); } } if (!strncmp(argv[1], "-d", 2)) unlink(filename); } #ifdef __APPLE__ if (getenv("MallocStackLogging") && getenv("MallocStackLoggingNoCompact")) { char command[1024]; /* malloc_history command */ snprintf(command, sizeof(command), "malloc_history %d -all_by_size", getpid()); fflush(stdout); system(command); } #endif /* __APPLE__ */ ppdClose(ppd); return (status); }