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); }
static void ppd_load_constraints(ppd_file_t *ppd) /* I - PPD file */ { int i; /* Looping var */ ppd_const_t *oldconst; /* Current UIConstraints data */ ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */ _ppd_cups_uiconsts_t *consts; /* Current cupsUIConstraints data */ _ppd_cups_uiconst_t *constptr; /* Current constraint */ ppd_group_t *installable; /* Installable options group */ const char *vptr; /* Pointer into constraint value */ char option[PPD_MAX_NAME], /* Option name/MainKeyword */ choice[PPD_MAX_NAME], /* Choice/OptionKeyword */ *ptr; /* Pointer into option or choice */ DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd)); /* * Create an array to hold the constraint data... */ ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL); /* * Find the installable options group if it exists... */ for (i = ppd->num_groups, installable = ppd->groups; i > 0; i --, installable ++) if (!_cups_strcasecmp(installable->name, "InstallableOptions")) break; if (i <= 0) installable = NULL; /* * Load old-style [Non]UIConstraints data... */ for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++) { /* * Weed out nearby duplicates, since the PPD spec requires that you * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"... */ if (i > 1 && !_cups_strcasecmp(oldconst[0].option1, oldconst[1].option2) && !_cups_strcasecmp(oldconst[0].choice1, oldconst[1].choice2) && !_cups_strcasecmp(oldconst[0].option2, oldconst[1].option1) && !_cups_strcasecmp(oldconst[0].choice2, oldconst[1].choice1)) continue; /* * Allocate memory... */ if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) { DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "UIConstraints!"); return; } if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL) { free(consts); DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "UIConstraints!"); return; } /* * Fill in the information... */ consts->num_constraints = 2; consts->constraints = constptr; if (!_cups_strncasecmp(oldconst->option1, "Custom", 6) && !_cups_strcasecmp(oldconst->choice1, "True")) { constptr[0].option = ppdFindOption(ppd, oldconst->option1 + 6); constptr[0].choice = ppdFindChoice(constptr[0].option, "Custom"); constptr[0].installable = 0; } else { constptr[0].option = ppdFindOption(ppd, oldconst->option1); constptr[0].choice = ppdFindChoice(constptr[0].option, oldconst->choice1); constptr[0].installable = ppd_is_installable(installable, oldconst->option1); } if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0])) { DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", oldconst->option1, oldconst->choice1)); free(consts->constraints); free(consts); continue; } if (!_cups_strncasecmp(oldconst->option2, "Custom", 6) && !_cups_strcasecmp(oldconst->choice2, "True")) { constptr[1].option = ppdFindOption(ppd, oldconst->option2 + 6); constptr[1].choice = ppdFindChoice(constptr[1].option, "Custom"); constptr[1].installable = 0; } else { constptr[1].option = ppdFindOption(ppd, oldconst->option2); constptr[1].choice = ppdFindChoice(constptr[1].option, oldconst->choice2); constptr[1].installable = ppd_is_installable(installable, oldconst->option2); } if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0])) { DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", oldconst->option2, oldconst->choice2)); free(consts->constraints); free(consts); continue; } consts->installable = constptr[0].installable || constptr[1].installable; /* * Add it to the constraints array... */ cupsArrayAdd(ppd->cups_uiconstraints, consts); } /* * Then load new-style constraints... */ for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL); constattr; constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL)) { if (!constattr->value) { DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); continue; } for (i = 0, vptr = strchr(constattr->value, '*'); vptr; i ++, vptr = strchr(vptr + 1, '*')); if (i == 0) { DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); continue; } if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) { DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "cupsUIConstraints!"); return; } if ((constptr = calloc((size_t)i, sizeof(_ppd_cups_uiconst_t))) == NULL) { free(consts); DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "cupsUIConstraints!"); return; } consts->num_constraints = i; consts->constraints = constptr; strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver)); for (i = 0, vptr = strchr(constattr->value, '*'); vptr; i ++, vptr = strchr(vptr, '*'), constptr ++) { /* * Extract "*Option Choice" or just "*Option"... */ for (vptr ++, ptr = option; *vptr && !_cups_isspace(*vptr); vptr ++) if (ptr < (option + sizeof(option) - 1)) *ptr++ = *vptr; *ptr = '\0'; while (_cups_isspace(*vptr)) vptr ++; if (*vptr == '*') choice[0] = '\0'; else { for (ptr = choice; *vptr && !_cups_isspace(*vptr); vptr ++) if (ptr < (choice + sizeof(choice) - 1)) *ptr++ = *vptr; *ptr = '\0'; } if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True")) { _cups_strcpy(option, option + 6); strlcpy(choice, "Custom", sizeof(choice)); } constptr->option = ppdFindOption(ppd, option); constptr->choice = ppdFindChoice(constptr->option, choice); constptr->installable = ppd_is_installable(installable, option); consts->installable |= constptr->installable; if (!constptr->option || (!constptr->choice && choice[0])) { DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", option, choice)); break; } } if (!vptr) cupsArrayAdd(ppd->cups_uiconstraints, consts); else { free(consts->constraints); free(consts); } } }
static int /* O - Exit status */ auto_configure(ppd_file_t *ppd, /* I - PPD file */ const char *user) /* I - Printing user */ { int status = 0; /* Exit status */ ppd_option_t *option; /* Current option in PPD */ ppd_attr_t *attr; /* Query command attribute */ const char *valptr; /* Pointer into attribute value */ char buffer[1024], /* String buffer */ *bufptr; /* Pointer into buffer */ ssize_t bytes; /* Number of bytes read */ int datalen; /* Side-channel data length */ /* * See if the backend supports bidirectional I/O... */ datalen = 1; if (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer, &datalen, 30.0) != CUPS_SC_STATUS_OK || buffer[0] != CUPS_SC_BIDI_SUPPORTED) { fputs("DEBUG: Unable to auto-configure PostScript Printer - no " "bidirectional I/O available!\n", stderr); return (1); } /* * Put the printer in PostScript mode... */ begin_ps(ppd, user); /* * (STR #4028) * * As a lot of PPDs contain bad PostScript query code, we need to prevent one * bad query sequence from affecting all auto-configuration. The following * error handler allows us to log PostScript errors to cupsd. */ puts("/cups_handleerror {\n" " $error /newerror false put\n" " (:PostScript error in \") print cups_query_keyword print (\": ) " "print\n" " $error /errorname get 128 string cvs print\n" " (; offending command:) print $error /command get 128 string cvs " "print (\n) print flush\n" "} bind def\n" "errordict /timeout {} put\n" "/cups_query_keyword (?Unknown) def\n"); fflush(stdout); /* * Wait for the printer to become connected... */ do { sleep(1); datalen = 1; } while (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_CONNECTED, buffer, &datalen, 5.0) == CUPS_SC_STATUS_OK && !buffer[0]); /* * Then loop through every option in the PPD file and ask for the current * value... */ fputs("DEBUG: Auto-configuring PostScript printer...\n", stderr); for (option = ppdFirstOption(ppd); option; option = ppdNextOption(ppd)) { /* * See if we have a query command for this option... */ snprintf(buffer, sizeof(buffer), "?%s", option->keyword); if ((attr = ppdFindAttr(ppd, buffer, NULL)) == NULL || !attr->value) { fprintf(stderr, "DEBUG: Skipping %s option...\n", option->keyword); continue; } /* * Send the query code to the printer... */ fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword); for (bufptr = buffer, valptr = attr->value; *valptr; valptr ++) { /* * Log the query code, breaking at newlines... */ if (*valptr == '\n') { *bufptr = '\0'; fprintf(stderr, "DEBUG: %s\\n\n", buffer); bufptr = buffer; } else if (*valptr < ' ') { if (bufptr >= (buffer + sizeof(buffer) - 4)) { *bufptr = '\0'; fprintf(stderr, "DEBUG: %s\n", buffer); bufptr = buffer; } if (*valptr == '\r') { *bufptr++ = '\\'; *bufptr++ = 'r'; } else if (*valptr == '\t') { *bufptr++ = '\\'; *bufptr++ = 't'; } else { *bufptr++ = '\\'; *bufptr++ = '0' + ((*valptr / 64) & 7); *bufptr++ = '0' + ((*valptr / 8) & 7); *bufptr++ = '0' + (*valptr & 7); } } else { if (bufptr >= (buffer + sizeof(buffer) - 1)) { *bufptr = '\0'; fprintf(stderr, "DEBUG: %s\n", buffer); bufptr = buffer; } *bufptr++ = *valptr; } } if (bufptr > buffer) { *bufptr = '\0'; fprintf(stderr, "DEBUG: %s\n", buffer); } printf("/cups_query_keyword (?%s) def\n", option->keyword); /* Set keyword for error reporting */ fputs("{ (", stdout); for (valptr = attr->value; *valptr; valptr ++) { if (*valptr == '(' || *valptr == ')' || *valptr == '\\') putchar('\\'); putchar(*valptr); } fputs(") cvx exec } stopped { cups_handleerror } if clear\n", stdout); /* Send query code */ fflush(stdout); datalen = 0; cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer, &datalen, 5.0); /* * Read the response data... */ bufptr = buffer; buffer[0] = '\0'; while ((bytes = cupsBackChannelRead(bufptr, sizeof(buffer) - (size_t)(bufptr - buffer) - 1, 10.0)) > 0) { /* * No newline at the end? Go on reading ... */ bufptr += bytes; *bufptr = '\0'; if (bytes == 0 || (bufptr > buffer && bufptr[-1] != '\r' && bufptr[-1] != '\n')) continue; /* * Trim whitespace and control characters from both ends... */ bytes = bufptr - buffer; for (bufptr --; bufptr >= buffer; bufptr --) if (isspace(*bufptr & 255) || iscntrl(*bufptr & 255)) *bufptr = '\0'; else break; for (bufptr = buffer; isspace(*bufptr & 255) || iscntrl(*bufptr & 255); bufptr ++); if (bufptr > buffer) { _cups_strcpy(buffer, bufptr); bufptr = buffer; } fprintf(stderr, "DEBUG: Got %d bytes.\n", (int)bytes); /* * Skip blank lines... */ if (!buffer[0]) continue; /* * Check the response... */ if ((bufptr = strchr(buffer, ':')) != NULL) { /* * PostScript code for this option in the PPD is broken; show the * interpreter's error message that came back... */ fprintf(stderr, "DEBUG%s\n", bufptr); break; } /* * Verify the result is a valid option choice... */ if (!ppdFindChoice(option, buffer)) { if (!strcasecmp(buffer, "Unknown")) break; bufptr = buffer; buffer[0] = '\0'; continue; } /* * Write out the result and move on to the next option... */ fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, buffer); break; } /* * Printer did not answer this option's query */ if (bytes <= 0) { fprintf(stderr, "DEBUG: No answer to query for option %s within 10 seconds.\n", option->keyword); status = 1; } } /* * Finish the job... */ fflush(stdout); end_ps(ppd); /* * Return... */ if (status) _cupsLangPrintFilter(stderr, "WARNING", _("Unable to configure printer options.")); 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 */ int errors = 0; /* Number of errors */ cups_lang_t *language; /* Message catalog */ cups_lang_t *language2; /* Message catalog */ struct lconv *loc; /* Locale data */ char buffer[1024]; /* String buffer */ double number; /* Number */ static const char * const tests[] = /* Test strings */ { "1", "-1", "3", "5.125" }; if (argc == 1) { language = cupsLangDefault(); language2 = cupsLangDefault(); } else { language = cupsLangGet(argv[1]); language2 = cupsLangGet(argv[1]); setenv("LANG", argv[1], 1); setenv("SOFTWARE", "CUPS/" CUPS_SVERSION, 1); } _cupsSetLocale(argv); if (language != language2) { errors ++; puts("**** ERROR: Language cache did not work! ****"); puts("First result from cupsLangGet:"); } printf("Language = \"%s\"\n", language->language); printf("Encoding = \"%s\"\n", _cupsEncodingName(language->encoding)); printf("No = \"%s\"\n", _cupsLangString(language, "No")); printf("Yes = \"%s\"\n", _cupsLangString(language, "Yes")); if (language != language2) { puts("Second result from cupsLangGet:"); printf("Language = \"%s\"\n", language2->language); printf("Encoding = \"%s\"\n", _cupsEncodingName(language2->encoding)); printf("No = \"%s\"\n", _cupsLangString(language2, "No")); printf("Yes = \"%s\"\n", _cupsLangString(language2, "Yes")); } loc = localeconv(); for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i ++) { number = _cupsStrScand(tests[i], NULL, loc); printf("_cupsStrScand(\"%s\") number=%f\n", tests[i], number); _cupsStrFormatd(buffer, buffer + sizeof(buffer), number, loc); printf("_cupsStrFormatd(%f) buffer=\"%s\"\n", number, buffer); if (strcmp(buffer, tests[i])) { errors ++; puts("**** ERROR: Bad formatted number! ****"); } } if (argc == 3) { ppd_file_t *ppd; /* PPD file */ ppd_option_t *option; /* PageSize option */ ppd_choice_t *choice; /* PageSize/Letter choice */ if ((ppd = ppdOpenFile(argv[2])) == NULL) { printf("Unable to open PPD file \"%s\".\n", argv[2]); errors ++; } else { ppdLocalize(ppd); if ((option = ppdFindOption(ppd, "PageSize")) == NULL) { puts("No PageSize option."); errors ++; } else { printf("PageSize: %s\n", option->text); if ((choice = ppdFindChoice(option, "Letter")) == NULL) { puts("No Letter PageSize choice."); errors ++; } else { printf("Letter: %s\n", choice->text); } } ppdClose(ppd); } } return (errors > 0); }