summaryrefslogtreecommitdiff
path: root/src/cups/genppd.c
diff options
context:
space:
mode:
authorDidier Raboud <odyx@debian.org>2018-09-28 10:34:15 +0200
committerDidier Raboud <odyx@debian.org>2018-09-28 10:34:15 +0200
commit477a402e36e91cb68b09f70ddf32a8ea1e47c22f (patch)
tree655c3f6331a6e8fd8b09ceb4da8f5896484ae16a /src/cups/genppd.c
Import gutenprint_5.3.1.orig.tar.xz
[dgit import orig gutenprint_5.3.1.orig.tar.xz]
Diffstat (limited to 'src/cups/genppd.c')
-rw-r--r--src/cups/genppd.c1984
1 files changed, 1984 insertions, 0 deletions
diff --git a/src/cups/genppd.c b/src/cups/genppd.c
new file mode 100644
index 0000000..aa47aad
--- /dev/null
+++ b/src/cups/genppd.c
@@ -0,0 +1,1984 @@
+/*
+ * PPD file generation program for the CUPS drivers.
+ *
+ * Copyright 1993-2008 by Mike Sweet and Robert Krawitz.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Contents:
+ *
+ * main() - Process files on the command-line...
+ * cat_ppd() - Copy the named PPD to stdout.
+ * generate_ppd() - Generate a PPD file.
+ * getlangs() - Get a list of available translations.
+ * help() - Show detailed help.
+ * is_special_option() - Determine if an option should be grouped.
+ * list_ppds() - List the available drivers.
+ * print_group_close() - Close a UI group.
+ * print_group_open() - Open a new UI group.
+ * printlangs() - Print list of available translations.
+ * printmodels() - Print a list of available models.
+ * usage() - Show program usage.
+ * write_ppd() - Write a PPD file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "genppd.h"
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+#if defined(HAVE_VARARGS_H) && !defined(HAVE_STDARG_H)
+#include <varargs.h>
+#else
+#include <stdarg.h>
+#endif
+
+const char *ppdext = ".ppd";
+const char *cups_modeldir = CUPS_MODELDIR;
+const char *gpext = "";
+
+static int use_compression;
+
+int use_base_version = 0;
+
+/*
+ * Some applications use the XxYdpi tags rather than the actual
+ * hardware resolutions to decide what resolution to print at. Some
+ * applications get very unhappy if the vertical resolution exceeds
+ * a certain amount. Some of those applications even get very unhappy if
+ * the PPD file even contains a resolution that exceeds that limit.
+ * And they're not even free source applications.
+ * Feh.
+ */
+#define MAXIMUM_SAFE_PPD_Y_RESOLUTION (720)
+#define MAXIMUM_SAFE_PPD_X_RESOLUTION (1500)
+
+/*
+ * Note:
+ *
+ * The current release of ESP Ghostscript is fully Level 3 compliant,
+ * so we can report Level 3 support by default...
+ */
+
+int cups_ppd_ps_level = CUPS_PPD_PS_LEVEL;
+int localize_numbers = 0;
+
+/*
+ * File handling stuff...
+ */
+
+typedef struct /**** Media size values ****/
+{
+ const char *name, /* Media size name */
+ *text; /* Media size text */
+ stp_dimension_t width, /* Media width */
+ height, /* Media height */
+ left, /* Media left margin */
+ right, /* Media right margin */
+ bottom, /* Media bottom margin */
+ top; /* Media top margin */
+} paper_t;
+
+const char *special_options[] =
+{
+ "PageSize",
+ "MediaType",
+ "InputSlot",
+ "Resolution",
+ "OutputOrder",
+ "Quality",
+ "Duplex",
+ NULL
+};
+
+/*
+ * TRANSLATORS:
+ * Please keep these translated names SHORT. The number of bytes in
+ * the parameter class name plus the number of bytes in the parameter
+ * name must not exceed 38 BYTES (not characters!)
+ */
+
+const char *parameter_class_names[] =
+{
+ _("Printer Features"),
+ _("Output Control")
+};
+
+const char *parameter_level_names[] =
+{
+ _("Common"),
+ _("Extra 1"),
+ _("Extra 2"),
+ _("Extra 3"),
+ _("Extra 4"),
+ _("Extra 5")
+};
+
+/*
+ * Local functions...
+ */
+
+static int gpputs(gpFile f, const char *s);
+static int gpprintf(gpFile f, const char *format, ...)
+ __attribute__((format(__printf__, 2, 3)));
+static int is_special_option(const char *name);
+static void print_group_close(gpFile fp, stp_parameter_class_t p_class,
+ stp_parameter_level_t p_level,
+ const char *language,
+ const stp_string_list_t *po);
+static void print_group_open(gpFile fp, stp_parameter_class_t p_class,
+ stp_parameter_level_t p_level,
+ const char *language,
+ const stp_string_list_t *po);
+
+
+/*
+ * Global variables...
+ */
+
+
+static int
+gpputs(gpFile f, const char *s)
+{
+#ifdef HAVE_LIBZ
+ if (use_compression)
+ return gzputs(f->gzf, s);
+ else
+ return fputs(s, f->f);
+#else
+ return fputs(s, f);
+#endif
+}
+
+static int
+gpprintf(gpFile f, const char *format, ...)
+{
+ int status;
+ int current_allocation = 64;
+ char *result = stp_malloc(current_allocation);
+ while (1)
+ {
+ int bytes;
+ va_list args;
+ va_start(args, format);
+ bytes = vsnprintf(result, current_allocation, format, args);
+ va_end(args);
+ if (bytes >= 0 && bytes < current_allocation)
+ break;
+ else
+ {
+ stp_free(result);
+ if (bytes < 0)
+ current_allocation *= 2;
+ else
+ current_allocation = bytes + 1;
+ result = stp_malloc(current_allocation);
+ }
+ }
+ status = gpputs(f, result);
+ stp_free(result);
+ return status;
+}
+
+/*
+ * 'getlangs()' - Get a list of available translations.
+ */
+
+char ** /* O - Array of languages */
+getlangs(void)
+{
+ int i; /* Looping var */
+ char *ptr; /* Pointer into string */
+ static char all_linguas[] = ALL_LINGUAS;
+ /* List of languages from configure.ac */
+ static char **langs = NULL; /* Array of languages */
+
+
+ if (!langs)
+ {
+ /*
+ * Create the langs array...
+ */
+
+ for (i = 1, ptr = strchr(all_linguas, ' '); ptr; ptr = strchr(ptr + 1, ' '))
+ i ++;
+
+ langs = calloc(i + 1, sizeof(char *));
+
+ langs[0] = all_linguas;
+ for (i = 1, ptr = strchr(all_linguas, ' '); ptr; ptr = strchr(ptr + 1, ' '))
+ {
+ *ptr = '\0';
+ langs[i] = ptr + 1;
+ i ++;
+ }
+ }
+
+ return (langs);
+}
+
+
+/*
+ * 'is_special_option()' - Determine if an option should be grouped.
+ */
+
+static int /* O - 1 if non-grouped, 0 otherwise */
+is_special_option(const char *name) /* I - Option name */
+{
+ int i = 0;
+ while (special_options[i])
+ {
+ if (strcmp(name, special_options[i]) == 0)
+ return 1;
+ i++;
+ }
+ return 0;
+}
+
+/*
+ * strlen returns the number of characters. PPD file limitations are
+ * defined in bytes. So we need something to count bytes, not merely
+ * characters.
+ */
+
+static size_t
+bytelen(const char *buffer)
+{
+ size_t answer = 0;
+ while (*buffer++ != '\0')
+ answer++;
+ return answer;
+}
+
+/*
+ * Use our localization routine to correctly do localization on all
+ * systems. The standard lookup routine has trouble creating multi-locale
+ * files on many systems, and on some systems there's not even a reliable
+ * way to use something other than the system locale.
+ */
+#ifdef _
+#undef _
+#endif
+#define _(x) stp_i18n_lookup(po, x)
+
+#define PPD_MAX_SHORT_NICKNAME (31)
+
+static void
+print_ppd_header(gpFile fp, ppd_type_t ppd_type, int model, const char *driver,
+ const char *family, const char *long_name,
+ const char *manufacturer, const char *device_id,
+ const char *ppd_location,
+ const char *language, const stp_string_list_t *po,
+ char **all_langs)
+{
+ char short_long_name[(PPD_MAX_SHORT_NICKNAME) + 1];
+ /*
+ * Write a standard header...
+ */
+ gpputs(fp, "*PPD-Adobe: \"4.3\"\n");
+ gpputs(fp, "*% PPD file for CUPS/Gutenprint.\n");
+ gpputs(fp, "*% Copyright 1993-2008 by Mike Sweet and Robert Krawitz.\n");
+ gpputs(fp, "*% This program is free software; you can redistribute it and/or\n");
+ gpputs(fp, "*% modify it under the terms of the GNU General Public License,\n");
+ gpputs(fp, "*% either version 2, or (at your option) any later version,\n");
+ gpputs(fp, "*% as published by the Free Software Foundation.\n");
+ gpputs(fp, "*%\n");
+ gpputs(fp, "*% This program is distributed in the hope that it will be useful, but\n");
+ gpputs(fp, "*% WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n");
+ gpputs(fp, "*% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n");
+ gpputs(fp, "*% for more details.\n");
+ gpputs(fp, "*%\n");
+ gpputs(fp, "*% You should have received a copy of the GNU General Public License\n");
+ gpputs(fp, "*% along with this program. If not, see <https://www.gnu.org/licenses/>.\n");
+ gpputs(fp, "*%\n");
+ gpputs(fp, "*FormatVersion: \"4.3\"\n");
+ if (use_base_version)
+ gpputs(fp, "*FileVersion: \"" BASE_VERSION "\"\n");
+ else
+ gpputs(fp, "*FileVersion: \"" VERSION "\"\n");
+ /* Specify language of PPD translation */
+ /* TRANSLATORS: Specify the language of the PPD translation.
+ * Use the English name of your language here, e.g. "Swedish" instead of
+ * "Svenska". */
+ gpprintf(fp, "*LanguageVersion: %s\n", _("English"));
+ if (language)
+ gpputs(fp, "*LanguageEncoding: UTF-8\n");
+ else
+ gpputs(fp, "*LanguageEncoding: ISOLatin1\n");
+ /*
+ * Strictly speaking, the PCFileName attribute should be a 12 character
+ * max (12345678.ppd) filename, as a requirement of the old PPD spec.
+ * The following code generates a (hopefully unique) 8.3 filename from
+ * the driver name, and makes the filename all UPPERCASE as well...
+ */
+
+ gpprintf(fp, "*PCFileName: \"STP%05d.PPD\"\n",
+ stp_get_printer_index_by_driver(driver) +
+ ((int) ppd_type * stp_printer_model_count()));
+ gpprintf(fp, "*Manufacturer: \"%s\"\n", manufacturer);
+
+ /*
+ * The Product attribute specifies the string returned by the PostScript
+ * interpreter. The last one will appear in the CUPS "product" field,
+ * while all instances are available as attributes. Rather than listing
+ * the PostScript interpreters we might encounter, we instead just list
+ * a single product line with the "long name" to be compatible with other
+ * CUPS-based drivers. (This is a change from Gutenprint 5.0 and earlier)
+ */
+
+ gpprintf(fp, "*Product: \"(%s)\"\n", long_name);
+
+ /*
+ * The ModelName attribute now provides the long name rather than the
+ * short driver name... The rastertoprinter driver looks up both...
+ */
+
+ gpprintf(fp, "*ModelName: \"%s\"\n", long_name);
+ strncpy(short_long_name, long_name, PPD_MAX_SHORT_NICKNAME);
+ short_long_name[PPD_MAX_SHORT_NICKNAME] = '\0';
+ gpprintf(fp, "*ShortNickName: \"%s\"\n", short_long_name);
+
+ /*
+ * NOTE - code in rastertoprinter looks for this version string.
+ * If this is changed, the corresponding change must be made in
+ * rastertoprinter.c. Look for "ppd->nickname"
+ */
+ gpprintf(fp, "*NickName: \"%s%s%s%s\"\n",
+ long_name, CUPS_PPD_NICKNAME_STRING, VERSION,
+ (ppd_type == PPD_SIMPLIFIED ? " Simplified" :
+ ppd_type == PPD_NO_COLOR_OPTS ? " No Color Options" : ""));
+ if (cups_ppd_ps_level == 2)
+ gpputs(fp, "*PSVersion: \"(2017.000) 550\"\n");
+ else
+ gpputs(fp, "*PSVersion: \"(3010.000) 0\"\n");
+ gpprintf(fp, "*LanguageLevel: \"%d\"\n", cups_ppd_ps_level);
+}
+
+static void
+print_ppd_header_3(gpFile fp, ppd_type_t ppd_type, int model,
+ const char *driver,
+ const char *family, const char *long_name,
+ const char *manufacturer, const char *device_id,
+ const char *ppd_location,
+ const char *language, const stp_string_list_t *po,
+ char **all_langs)
+{
+ int i;
+ gpputs(fp, "*FileSystem: False\n");
+ gpputs(fp, "*LandscapeOrientation: Plus90\n");
+ gpputs(fp, "*TTRasterizer: Type42\n");
+
+ gpputs(fp, "*cupsVersion: 1.2\n");
+
+ gpprintf(fp, "*cupsFilter: \"application/vnd.cups-raster 100 rastertogutenprint.%s\"\n", GUTENPRINT_RELEASE_VERSION);
+ if (strcasecmp(manufacturer, "EPSON") == 0)
+ gpputs(fp, "*cupsFilter: \"application/vnd.cups-command 33 commandtoepson\"\n");
+ if (device_id)
+ {
+ if (strlen(device_id) > 200)
+ {
+ char buf[129];
+ int bytes_left = strlen(device_id);
+ int offset = 0;
+ gpputs(fp, "*1284DeviceID: \"");
+ while (bytes_left > 0)
+ {
+ memset(buf, 0, 129);
+ strncpy(buf, device_id + offset, 128);
+ gpputs(fp, buf);
+ if (bytes_left <= 128)
+ gpputs(fp, "\"");
+ gpputs(fp, "\n");
+ offset += 128;
+ bytes_left -= 128;
+ }
+ gpputs(fp, "*End\n");
+ }
+ else
+ gpprintf(fp, "*1284DeviceID: \"%s\"\n", device_id);
+ }
+ if (!language)
+ {
+ /*
+ * Generate globalized PPDs when POSIX language is requested...
+ */
+
+ const char *prefix = "*cupsLanguages: \"";
+
+ for (i = 0; all_langs[i]; i ++)
+ {
+ if (!strcmp(all_langs[i], "C") || !strcmp(all_langs[i], "en"))
+ continue;
+
+ gpprintf(fp, "%s%s", prefix, all_langs[i]);
+ prefix = " ";
+ }
+
+ if (!strcmp(prefix, " "))
+ gpputs(fp, "\"\n");
+ }
+}
+
+static void
+print_ppd_header_2(gpFile fp, ppd_type_t ppd_type, int model, const char *driver,
+ const char *family, const char *long_name,
+ const char *manufacturer, const char *device_id,
+ const char *ppd_location,
+ const char *language, const stp_string_list_t *po,
+ char **all_langs)
+{
+ gpprintf(fp, "*StpDriverName: \"%s\"\n", driver);
+ gpprintf(fp, "*StpDriverModelFamily: \"%d_%s\"\n", model, family);
+ gpprintf(fp, "*StpPPDLocation: \"%s\"\n", ppd_location);
+ gpprintf(fp, "*StpLocale: \"%s\"\n", language ? language : "C");
+}
+
+static void
+print_page_sizes(gpFile fp, stp_vars_t *v, int simplified,
+ const stp_string_list_t *po)
+{
+ int variable_sizes = 0;
+ stp_parameter_t desc;
+ int num_opts;
+ paper_t *the_papers;
+ int i;
+ stp_dimension_t width, height, /* Page information */
+ bottom, left,
+ top, right;
+ stp_dimension_t min_width, /* Min/max custom size */
+ min_height,
+ max_width,
+ max_height;
+ const stp_param_string_t *opt;
+ int cur_opt = 0;
+
+ stp_describe_parameter(v, "PageSize", &desc);
+ num_opts = stp_string_list_count(desc.bounds.str);
+ the_papers = stp_malloc(sizeof(paper_t) * num_opts);
+ for (i = 0; i < num_opts; i++)
+ {
+ const stp_papersize_t *papersize;
+ opt = stp_string_list_param(desc.bounds.str, i);
+ if (strcmp(opt->name, "Custom") == 0)
+ {
+ variable_sizes = 1;
+ continue;
+ }
+
+ papersize = stp_describe_papersize(v, opt->name);
+
+ if (!papersize)
+ {
+ printf("Unable to lookup size %s!\n", opt->name);
+ continue;
+ }
+
+ if (simplified && num_opts >= 10 &&
+ (!desc.deflt.str || strcmp(opt->name, desc.deflt.str) != 0) &&
+ (papersize->paper_unit == PAPERSIZE_ENGLISH_EXTENDED ||
+ papersize->paper_unit == PAPERSIZE_METRIC_EXTENDED))
+ continue;
+
+ if (papersize->width <= 0 || papersize->height <= 0)
+ continue;
+
+ width = papersize->width;
+ height = papersize->height;
+
+ stp_set_string_parameter(v, "PageSize", opt->name);
+
+ stp_get_media_size(v, &width, &height);
+ stp_get_maximum_imageable_area(v, &left, &right, &bottom, &top);
+
+ if (left < 0)
+ left = 0;
+ if (right > width)
+ right = width;
+ if (bottom > height)
+ bottom = height;
+ if (top < 0)
+ top = 0;
+
+ the_papers[cur_opt].name = opt->name;
+ the_papers[cur_opt].text = stp_i18n_lookup(po, opt->text);
+ the_papers[cur_opt].width = width;
+ the_papers[cur_opt].height = height;
+ the_papers[cur_opt].left = left;
+ the_papers[cur_opt].right = right;
+ the_papers[cur_opt].bottom = height - bottom;
+ the_papers[cur_opt].top = height - top;
+
+ cur_opt++;
+ stp_clear_string_parameter(v, "PageSize");
+ }
+
+ /*
+ * The VariablePaperSize attribute is obsolete, however some popular
+ * applications still look for it to provide custom page size support.
+ */
+
+ gpprintf(fp, "*VariablePaperSize: %s\n\n", variable_sizes ? "true" : "false");
+
+ if (stp_parameter_has_category_value(v, &desc, "Color", "Yes"))
+ gpputs(fp, "*ColorKeyWords: \"PageSize\"\n");
+ gpprintf(fp, "*OpenUI *PageSize/%s: PickOne\n", _("Media Size"));
+ gpputs(fp, "*OPOptionHints PageSize: \"dropdown\"\n");
+ gpputs(fp, "*OrderDependency: 10 AnySetup *PageSize\n");
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc.name, desc.p_type, desc.is_mandatory,
+ desc.p_class, desc.p_level, desc.channel, 0.0, 0.0, 0.0);
+ gpprintf(fp, "*DefaultPageSize: %s\n", desc.deflt.str);
+ gpprintf(fp, "*StpDefaultPageSize: %s\n", desc.deflt.str);
+ for (i = 0; i < cur_opt; i ++)
+ {
+ gpprintf(fp, "*PageSize %s", the_papers[i].name);
+ gpprintf(fp, "/%s:\t\"<</PageSize[%.3f %.3f]/ImagingBBox null>>setpagedevice\"\n",
+ the_papers[i].text, the_papers[i].width, the_papers[i].height);
+ }
+ gpputs(fp, "*CloseUI: *PageSize\n\n");
+
+ if (stp_parameter_has_category_value(v, &desc, "Color", "Yes"))
+ gpputs(fp, "*ColorKeyWords: \"PageRegion\"\n");
+ gpprintf(fp, "*OpenUI *PageRegion/%s: PickOne\n", _("Media Size"));
+ gpputs(fp, "*OPOptionHints PageRegion: \"dropdown\"\n");
+ gpputs(fp, "*OrderDependency: 10 AnySetup *PageRegion\n");
+ gpprintf(fp, "*DefaultPageRegion: %s\n", desc.deflt.str);
+ gpprintf(fp, "*StpDefaultPageRegion: %s\n", desc.deflt.str);
+ for (i = 0; i < cur_opt; i ++)
+ {
+ gpprintf(fp, "*PageRegion %s", the_papers[i].name);
+ gpprintf(fp, "/%s:\t\"<</PageSize[%.3f %.3f]/ImagingBBox null>>setpagedevice\"\n",
+ the_papers[i].text, the_papers[i].width, the_papers[i].height);
+ }
+ gpputs(fp, "*CloseUI: *PageRegion\n\n");
+
+ gpprintf(fp, "*DefaultImageableArea: %s\n", desc.deflt.str);
+ gpprintf(fp, "*StpDefaultImageableArea: %s\n", desc.deflt.str);
+ for (i = 0; i < cur_opt; i ++)
+ {
+ gpprintf(fp, "*ImageableArea %s", the_papers[i].name);
+ gpprintf(fp, "/%s:\t\"%.3f %.3f %.3f %.3f\"\n", the_papers[i].text,
+ the_papers[i].left, the_papers[i].bottom,
+ the_papers[i].right, the_papers[i].top);
+ }
+ gpputs(fp, "\n");
+
+ gpprintf(fp, "*DefaultPaperDimension: %s\n", desc.deflt.str);
+ gpprintf(fp, "*StpDefaultPaperDimension: %s\n", desc.deflt.str);
+
+ for (i = 0; i < cur_opt; i ++)
+ {
+ gpprintf(fp, "*PaperDimension %s", the_papers[i].name);
+ gpprintf(fp, "/%s:\t\"%.3f %.3f\"\n",
+ the_papers[i].text, the_papers[i].width, the_papers[i].height);
+ }
+ gpputs(fp, "\n");
+
+ if (variable_sizes)
+ {
+ stp_get_size_limit(v, &max_width, &max_height, &min_width, &min_height);
+ stp_set_string_parameter(v, "PageSize", "Custom");
+ stp_get_media_size(v, &width, &height);
+ stp_get_maximum_imageable_area(v, &left, &right, &bottom, &top);
+ if (left < 0)
+ left = 0;
+ if (top < 0)
+ top = 0;
+ if (bottom > height)
+ bottom = height;
+ if (right > width)
+ width = right;
+
+ gpprintf(fp, "*MaxMediaWidth: \"%.3f\"\n", max_width);
+ gpprintf(fp, "*MaxMediaHeight: \"%.3f\"\n", max_height);
+ gpprintf(fp, "*HWMargins: %.3f %.3f %.3f %.3f\n",
+ left, height - bottom, width - right, top);
+ gpputs(fp, "*CustomPageSize True: \"pop pop pop <</PageSize[5 -2 roll]/ImagingBBox null>>setpagedevice\"\n");
+ gpprintf(fp, "*ParamCustomPageSize Width: 1 points %.3f %.3f\n",
+ min_width, max_width);
+ gpprintf(fp, "*ParamCustomPageSize Height: 2 points %.3f %.3f\n",
+ min_height, max_height);
+ gpputs(fp, "*ParamCustomPageSize WidthOffset: 3 points 0 0\n");
+ gpputs(fp, "*ParamCustomPageSize HeightOffset: 4 points 0 0\n");
+ gpputs(fp, "*ParamCustomPageSize Orientation: 5 int 0 0\n\n");
+ stp_clear_string_parameter(v, "PageSize");
+ }
+
+ stp_parameter_description_destroy(&desc);
+ if (the_papers)
+ stp_free(the_papers);
+}
+
+static void
+print_color_setup(gpFile fp, int simplified, int printer_is_color,
+ const stp_string_list_t *po)
+{
+ gpputs(fp, "*ColorKeyWords: \"ColorModel\"\n");
+ gpprintf(fp, "*OpenUI *ColorModel/%s: PickOne\n", _("Color Model"));
+ gpputs(fp, "*OPOptionHints ColorModel: \"radiobuttons\"\n");
+ gpputs(fp, "*OrderDependency: 2 AnySetup *ColorModel\n");
+
+ if (printer_is_color)
+ {
+ gpputs(fp, "*DefaultColorModel: RGB\n");
+ gpputs(fp, "*StpDefaultColorModel: RGB\n");
+ }
+ else
+ {
+ gpputs(fp, "*DefaultColorModel: Gray\n");
+ gpputs(fp, "*StpDefaultColorModel: Gray\n");
+ }
+
+ gpprintf(fp, "*ColorModel Gray/%s:\t\"<<"
+ "/cupsColorSpace %d"
+ "/cupsColorOrder %d"
+ "%s"
+ ">>setpagedevice\"\n",
+ _("Grayscale"), CUPS_CSPACE_W, CUPS_ORDER_CHUNKED,
+ simplified ? "/cupsBitsPerColor 8/cupsPreferredBitsPerColor 16" : "");
+ gpprintf(fp, "*ColorModel Black/%s:\t\"<<"
+ "/cupsColorSpace %d"
+ "/cupsColorOrder %d"
+ "%s"
+ ">>setpagedevice\"\n",
+ _("Inverted Grayscale"), CUPS_CSPACE_K, CUPS_ORDER_CHUNKED,
+ simplified ? "/cupsBitsPerColor 8/cupsPreferredBitsPerColor 16" : "");
+
+ if (printer_is_color)
+ {
+ gpprintf(fp, "*ColorModel RGB/%s:\t\"<<"
+ "/cupsColorSpace %d"
+ "/cupsColorOrder %d"
+ "%s"
+ ">>setpagedevice\"\n",
+ _("RGB Color"), CUPS_CSPACE_RGB, CUPS_ORDER_CHUNKED,
+ simplified ? "/cupsBitsPerColor 8/cupsPreferredBitsPerColor 16" : "");
+ gpprintf(fp, "*ColorModel CMY/%s:\t\"<<"
+ "/cupsColorSpace %d"
+ "/cupsColorOrder %d"
+ "%s"
+ ">>setpagedevice\"\n",
+ _("CMY Color"), CUPS_CSPACE_CMY, CUPS_ORDER_CHUNKED,
+ simplified ? "/cupsBitsPerColor 8/cupsPreferredBitsPerColor 16" : "");
+ gpprintf(fp, "*ColorModel CMYK/%s:\t\"<<"
+ "/cupsColorSpace %d"
+ "/cupsColorOrder %d"
+ "%s"
+ ">>setpagedevice\"\n",
+ _("CMYK"), CUPS_CSPACE_CMYK, CUPS_ORDER_CHUNKED,
+ simplified ? "/cupsBitsPerColor 8/cupsPreferredBitsPerColor 16" : "");
+ gpprintf(fp, "*ColorModel KCMY/%s:\t\"<<"
+ "/cupsColorSpace %d"
+ "/cupsColorOrder %d"
+ "%s"
+ ">>setpagedevice\"\n",
+ _("KCMY"), CUPS_CSPACE_KCMY, CUPS_ORDER_CHUNKED,
+ simplified ? "/cupsBitsPerColor 8/cupsPreferredBitsPerColor 16" : "");
+ }
+
+ gpputs(fp, "*CloseUI: *ColorModel\n\n");
+ if (!simplified)
+ {
+ /*
+ * 8 or 16 bit color (16 bit is slower)
+ */
+ gpputs(fp, "*ColorKeyWords: \"StpColorPrecision\"\n");
+ gpprintf(fp, "*OpenUI *StpColorPrecision/%s: PickOne\n", _("Color Precision"));
+ gpputs(fp, "*OPOptionHints StpColorPrecision: \"radiobuttons\"\n");
+ gpputs(fp, "*OrderDependency: 1 AnySetup *StpColorPrecision\n");
+ gpputs(fp, "*DefaultStpColorPrecision: Normal\n");
+ gpputs(fp, "*StpDefaultStpColorPrecision: Normal\n");
+ gpprintf(fp, "*StpColorPrecision Normal/%s:\t\"<<"
+ "/cupsBitsPerColor 8>>setpagedevice\"\n", _("Normal"));
+ gpprintf(fp, "*StpColorPrecision Best/%s:\t\"<<"
+ "/cupsBitsPerColor 8"
+ "/cupsPreferredBitsPerColor 16>>setpagedevice\"\n", _("Best"));
+ gpputs(fp, "*CloseUI: *StpColorPrecision\n\n");
+ }
+}
+
+static void
+print_group(
+ gpFile fp, /* I - File to write to */
+ const char *what,
+ stp_parameter_class_t p_class, /* I - Option class */
+ stp_parameter_level_t p_level, /* I - Option level */
+ const char *language, /* I - Language */
+ const stp_string_list_t *po) /* I - Message catalog */
+{
+ char buf[64];
+ const char *class = stp_i18n_lookup(po, parameter_class_names[p_class]);
+ const char *level = stp_i18n_lookup(po, parameter_level_names[p_level]);
+ size_t bytes = bytelen(class) + bytelen(level);
+ snprintf(buf, 40, "%s%s%s", class, bytes < 39 ? " " : "", level);
+ gpprintf(fp, "*%sGroup: C%dL%d/%s\n", what, p_class, p_level, buf);
+ if (language && !strcmp(language, "C") && !strcmp(what, "Open"))
+ {
+ char **all_langs = getlangs();/* All languages */
+ const char *lang;
+ int langnum;
+
+ for (langnum = 0; all_langs[langnum]; langnum ++)
+ {
+ const stp_string_list_t *altpo;
+
+ lang = all_langs[langnum];
+
+ if (!strcmp(lang, "C") || !strcmp(lang, "en"))
+ continue;
+ if ((altpo = stp_i18n_load(lang)) != NULL)
+ {
+ class = stp_i18n_lookup(altpo, parameter_class_names[p_class]);
+ level = stp_i18n_lookup(altpo, parameter_level_names[p_level]);
+ bytes = bytelen(class) + bytelen(level);
+ snprintf(buf, 40, "%s%s%s", class, bytes < 39 ? " " : "", level);
+ gpprintf(fp, "*%s.Translation C%dL%d/%s: \"\"\n",
+ lang, p_class, p_level, buf);
+ }
+ }
+ }
+ gpputs(fp, "\n");
+}
+
+/*
+ * 'print_group_close()' - Close a UI group.
+ */
+
+static void
+print_group_close(
+ gpFile fp, /* I - File to write to */
+ stp_parameter_class_t p_class, /* I - Option class */
+ stp_parameter_level_t p_level, /* I - Option level */
+ const char *language, /* I - language */
+ const stp_string_list_t *po) /* I - Message catalog */
+{
+ print_group(fp, "Close", p_class, p_level, NULL, NULL);
+}
+
+
+/*
+ * 'print_group_open()' - Open a new UI group.
+ */
+
+static void
+print_group_open(
+ gpFile fp, /* I - File to write to */
+ stp_parameter_class_t p_class, /* I - Option class */
+ stp_parameter_level_t p_level, /* I - Option level */
+ const char *language, /* I - language */
+ const stp_string_list_t *po) /* I - Message catalog */
+{
+ print_group(fp, "Open", p_class, p_level, language ? language : "C", po);
+}
+
+static void
+print_one_option(gpFile fp, stp_vars_t *v, const stp_string_list_t *po,
+ ppd_type_t ppd_type, const stp_parameter_t *lparam,
+ const stp_parameter_t *desc)
+{
+ int num_opts;
+ int i;
+ const stp_param_string_t *opt;
+ int printed_default_value = 0;
+ int simplified = ppd_type == PPD_SIMPLIFIED;
+ char dimstr[255]; /* Dimension string */
+ int print_close_ui = 1;
+ int is_color_opt = stp_parameter_has_category_value(v, desc, "Color", "Yes");
+ int skip_color = (ppd_type == PPD_NO_COLOR_OPTS && is_color_opt);
+ if (is_color_opt)
+ gpprintf(fp, "*ColorKeyWords: \"Stp%s\"\n", desc->name);
+
+#ifndef FULL_RAW
+ if (desc->p_type != STP_PARAMETER_TYPE_RAW)
+ {
+#endif
+ gpprintf(fp, "*OpenUI *Stp%s/%s: PickOne\n",
+ desc->name, stp_i18n_lookup(po, desc->text));
+ gpprintf(fp, "*OrderDependency: 10 AnySetup *Stp%s\n", desc->name);
+#ifndef FULL_RAW
+ }
+#endif
+ switch (desc->p_type)
+ {
+ case STP_PARAMETER_TYPE_STRING_LIST:
+ num_opts = stp_string_list_count(desc->bounds.str);
+ if (! skip_color)
+ {
+ if (num_opts > 3)
+ gpprintf(fp, "*OPOptionHints Stp%s: \"dropdown\"\n", lparam->name);
+ else
+ gpprintf(fp, "*OPOptionHints Stp%s: \"radiobuttons\"\n", lparam->name);
+ }
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc->name, desc->p_type, desc->is_mandatory, desc->p_class,
+ desc->p_level, desc->channel, 0.0, 0.0, 0.0);
+ if (desc->is_mandatory)
+ {
+ gpprintf(fp, "*DefaultStp%s: %s\n", desc->name, desc->deflt.str);
+ gpprintf(fp, "*StpDefaultStp%s: %s\n", desc->name, desc->deflt.str);
+ }
+ else
+ {
+ gpprintf(fp, "*DefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*StpDefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*Stp%s %s/%s: \"\"\n", desc->name, "None", _("None"));
+ }
+ for (i = 0; i < num_opts; i++)
+ {
+ opt = stp_string_list_param(desc->bounds.str, i);
+ if (skip_color && strcmp(opt->name, desc->deflt.str) != 0)
+ gpprintf(fp, "*?Stp%s %s/%s: \"\"\n",
+ desc->name, opt->name, stp_i18n_lookup(po, opt->text));
+ else
+ gpprintf(fp, "*Stp%s %s/%s: \"\"\n",
+ desc->name, opt->name, stp_i18n_lookup(po, opt->text));
+ }
+ break;
+ case STP_PARAMETER_TYPE_RAW:
+ print_close_ui = 0;
+#ifdef FULL_RAW /* XXX not sure if the standalone Custom... bit is sufficient */
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc->name, desc->p_type, desc->is_mandatory, desc->p_class,
+ desc->p_level, desc->channel, 0.0, 0.0, 0.0);
+ gpprintf(fp, "*DefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*StpDefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*Stp%s %s/%s: \"\"\n", desc->name, "None", _("None"));
+ gpprintf(fp, "*CloseUI: *Stp%s\n", desc->name);
+#endif
+ gpprintf(fp, "*CustomStp%s True: \"pop\"\n", desc->name);
+ gpprintf(fp, "*ParamCustomStp%s Text/%s: 1 string %d %d\n\n",
+ desc->name, _("Text"), 0, 0);
+
+ break;
+ case STP_PARAMETER_TYPE_BOOLEAN:
+ gpprintf(fp, "*OPOptionHints Stp%s: \"checkbox\"\n", lparam->name);
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc->name, desc->p_type, desc->is_mandatory, desc->p_class,
+ desc->p_level, desc->channel, 0.0, 0.0,
+ desc->deflt.boolean ? 1.0 : 0.0);
+ if (desc->is_mandatory)
+ {
+ gpprintf(fp, "*DefaultStp%s: %s\n", desc->name,
+ desc->deflt.boolean ? "True" : "False");
+ gpprintf(fp, "*StpDefaultStp%s: %s\n", desc->name,
+ desc->deflt.boolean ? "True" : "False");
+ if (skip_color)
+ gpprintf(fp, "*Stp%s %s/%s: \"\"\n",
+ desc->name, desc->deflt.boolean ? "True" : "False",
+ desc->deflt.boolean ? _("Yes") : _("No"));
+ }
+ else
+ {
+ gpprintf(fp, "*DefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*StpDefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*Stp%s %s/%s: \"\"\n", desc->name, "None", _("None"));
+ }
+ gpprintf(fp, "*%sStp%s %s/%s: \"\"\n",
+ (skip_color ? "?" : ""), desc->name, "False", _("No"));
+ gpprintf(fp, "*%sStp%s %s/%s: \"\"\n",
+ (skip_color ? "?" : ""), desc->name, "True", _("Yes"));
+ break;
+ case STP_PARAMETER_TYPE_DOUBLE:
+ gpprintf(fp, "*OPOptionHints Stp%s: \"slider input spinbox\"\n",
+ lparam->name);
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc->name, desc->p_type, desc->is_mandatory, desc->p_class,
+ desc->p_level, desc->channel, desc->bounds.dbl.lower,
+ desc->bounds.dbl.upper, desc->deflt.dbl);
+ gpprintf(fp, "*DefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*StpDefaultStp%s: None\n", desc->name);
+ if (!skip_color)
+ {
+ for (i = desc->bounds.dbl.lower * 1000;
+ i <= desc->bounds.dbl.upper * 1000 ; i += 100)
+ {
+ if (desc->deflt.dbl * 1000 == i && desc->is_mandatory)
+ {
+ gpprintf(fp, "*Stp%s None/%.3f: \"\"\n",
+ desc->name, ((double) i) * .001);
+ printed_default_value = 1;
+ }
+ else
+ gpprintf(fp, "*Stp%s %d/%.3f: \"\"\n",
+ desc->name, i, ((double) i) * .001);
+ }
+ }
+ if (!desc->is_mandatory)
+ gpprintf(fp, "*Stp%s None/%s: \"\"\n", desc->name, _("None"));
+ else if (! printed_default_value)
+ gpprintf(fp, "*Stp%s None/%.3f: \"\"\n", desc->name, desc->deflt.dbl);
+ gpprintf(fp, "*CloseUI: *Stp%s\n\n", desc->name);
+
+ /*
+ * Add custom option code and value parameter...
+ */
+
+ gpprintf(fp, "*CustomStp%s True: \"pop\"\n", desc->name);
+ gpprintf(fp, "*ParamCustomStp%s Value/%s: 1 real %.3f %.3f\n\n",
+ desc->name, _("Value"), desc->bounds.dbl.lower,
+ desc->bounds.dbl.upper);
+ if (!simplified && !skip_color)
+ {
+ if (is_color_opt)
+ gpprintf(fp, "*ColorKeyWords: \"StpFine%s\"\n", desc->name);
+ gpprintf(fp, "*OpenUI *StpFine%s/%s %s: PickOne\n",
+ desc->name, stp_i18n_lookup(po, desc->text),
+ _("Fine Adjustment"));
+ gpprintf(fp, "*OPOptionHints StpFine%s: \"hide\"\n", lparam->name);
+ gpprintf(fp, "*StpStpFine%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc->name, STP_PARAMETER_TYPE_INVALID, 0,
+ 0, 0, -1, 0.0, 0.0, 0.0);
+ gpprintf(fp, "*DefaultStpFine%s: None\n", desc->name);
+ gpprintf(fp, "*StpDefaultStpFine%s: None\n", desc->name);
+ gpprintf(fp, "*StpFine%s None/0.000: \"\"\n", desc->name);
+ for (i = 0; i < 100; i += 5)
+ gpprintf(fp, "*StpFine%s %d/%.3f: \"\"\n",
+ desc->name, i, ((double) i) * .001);
+ gpprintf(fp, "*CloseUI: *StpFine%s\n\n", desc->name);
+ }
+ print_close_ui = 0;
+
+ break;
+ case STP_PARAMETER_TYPE_DIMENSION:
+ gpprintf(fp, "*OPOptionHints Stp%s: \"length slider input spinbox\"\n",
+ lparam->name);
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc->name, desc->p_type, desc->is_mandatory,
+ desc->p_class, desc->p_level, desc->channel,
+ desc->bounds.dimension.lower,
+ desc->bounds.dimension.upper,
+ desc->deflt.dimension);
+ if (desc->is_mandatory)
+ {
+ gpprintf(fp, "*DefaultStp%s: %d\n",
+ desc->name, (int) desc->deflt.dimension);
+ gpprintf(fp, "*StpDefaultStp%s: %d\n",
+ desc->name, (int) desc->deflt.dimension);
+ }
+ else
+ {
+ gpprintf(fp, "*DefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*StpDefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*Stp%s %s/%s: \"\"\n", desc->name, "None", _("None"));
+ }
+ if (!skip_color)
+ {
+ for (i = (int) desc->bounds.dimension.lower;
+ i <= (int) desc->bounds.dimension.upper; i++)
+ {
+ snprintf(dimstr, sizeof(dimstr), _("%.1f mm"),
+ (double)i * 25.4 / 72.0);
+ gpprintf(fp, "*Stp%s %d/%s: \"\"\n", desc->name, i, dimstr);
+ }
+ }
+
+ print_close_ui = 0;
+ gpprintf(fp, "*CloseUI: *Stp%s\n\n", desc->name);
+
+ /*
+ * Add custom option code and value parameter...
+ */
+
+ gpprintf(fp, "*CustomStp%s True: \"pop\"\n", desc->name);
+ gpprintf(fp, "*ParamCustomStp%s Value/%s: 1 points %d %d\n\n",
+ desc->name, _("Value"), (int) desc->bounds.dimension.lower,
+ (int) desc->bounds.dimension.upper);
+
+ break;
+ case STP_PARAMETER_TYPE_INT:
+ gpprintf(fp, "*OPOptionHints Stp%s: \"input spinbox\"\n", lparam->name);
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc->name, desc->p_type, desc->is_mandatory, desc->p_class,
+ desc->p_level, desc->channel,
+ (double) desc->bounds.integer.lower,
+ (double) desc->bounds.integer.upper,
+ (double) desc->deflt.integer);
+ if (desc->is_mandatory)
+ {
+ gpprintf(fp, "*DefaultStp%s: %d\n", desc->name, desc->deflt.integer);
+ gpprintf(fp, "*StpDefaultStp%s: %d\n", desc->name, desc->deflt.integer);
+ if (skip_color)
+ gpprintf(fp, "*Stp%s %d/%d: \"\"\n", desc->name,
+ desc->deflt.integer, desc->deflt.integer);
+ }
+ else
+ {
+ gpprintf(fp, "*DefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*StpDefaultStp%s: None\n", desc->name);
+ gpprintf(fp, "*Stp%s %s/%s: \"\"\n", desc->name, "None", _("None"));
+ }
+ for (i = desc->bounds.integer.lower; i <= desc->bounds.integer.upper; i++)
+ {
+ gpprintf(fp, "*%sStp%s %d/%d: \"\"\n",
+ (skip_color ? "?" : ""), desc->name, i, i);
+ }
+
+ print_close_ui = 0;
+ gpprintf(fp, "*CloseUI: *Stp%s\n\n", desc->name);
+
+ break;
+ default:
+ break;
+ }
+ if (print_close_ui)
+ gpprintf(fp, "*CloseUI: *Stp%s\n\n", desc->name);
+}
+
+static void
+print_one_localization(gpFile fp, const stp_string_list_t *po,
+ int simplified, const char *lang,
+ const stp_parameter_t *lparam,
+ const stp_parameter_t *desc)
+{
+ int num_opts;
+ int i;
+ const stp_param_string_t *opt;
+ char dimstr[255]; /* Dimension string */
+
+ gpprintf(fp, "*%s.Translation Stp%s/%s: \"\"\n", lang,
+ desc->name, stp_i18n_lookup(po, desc->text));
+ switch (desc->p_type)
+ {
+ case STP_PARAMETER_TYPE_STRING_LIST:
+ if (!desc->is_mandatory)
+ gpprintf(fp, "*%s.Stp%s %s/%s: \"\"\n", lang, desc->name,
+ "None", _("None"));
+ num_opts = stp_string_list_count(desc->bounds.str);
+ for (i = 0; i < num_opts; i++)
+ {
+ opt = stp_string_list_param(desc->bounds.str, i);
+ gpprintf(fp, "*%s.Stp%s %s/%s: \"\"\n", lang,
+ desc->name, opt->name, stp_i18n_lookup(po, opt->text));
+ }
+ break;
+
+ case STP_PARAMETER_TYPE_BOOLEAN:
+ if (!desc->is_mandatory)
+ gpprintf(fp, "*%s.Stp%s %s/%s: \"\"\n", lang, desc->name,
+ "None", _("None"));
+ gpprintf(fp, "*%s.Stp%s %s/%s: \"\"\n", lang, desc->name, "False", _("No"));
+ gpprintf(fp, "*%s.Stp%s %s/%s: \"\"\n", lang, desc->name, "True", _("Yes"));
+ break;
+
+ case STP_PARAMETER_TYPE_DOUBLE:
+ if (localize_numbers)
+ {
+ for (i = desc->bounds.dbl.lower * 1000;
+ i <= desc->bounds.dbl.upper * 1000; i += 100)
+ {
+ if (desc->deflt.dbl * 1000 == i && desc->is_mandatory)
+ gpprintf(fp, "*%s.Stp%s None/%.3f: \"\"\n", lang,
+ desc->name, ((double) i) * .001);
+ else
+ gpprintf(fp, "*%s.Stp%s %d/%.3f: \"\"\n", lang,
+ desc->name, i, ((double) i) * .001);
+ }
+ }
+ if (!desc->is_mandatory)
+ gpprintf(fp, "*%s.Stp%s None/%s: \"\"\n", lang, desc->name, _("None"));
+ gpprintf(fp, "*%s.ParamCustomStp%s Value/%s: \"\"\n", lang,
+ desc->name, _("Value"));
+ if (!simplified)
+ {
+ gpprintf(fp, "*%s.Translation StpFine%s/%s %s: \"\"\n", lang,
+ desc->name, stp_i18n_lookup(po, desc->text),
+ _("Fine Adjustment"));
+ gpprintf(fp, "*%s.StpFine%s None/%.3f: \"\"\n", lang,
+ desc->name, 0.0);
+ if (localize_numbers)
+ {
+ for (i = 0; i < 100; i += 5)
+ gpprintf(fp, "*%s.StpFine%s %d/%.3f: \"\"\n", lang,
+ desc->name, i, ((double) i) * .001);
+ }
+ }
+ break;
+
+ case STP_PARAMETER_TYPE_DIMENSION:
+ if (!desc->is_mandatory)
+ gpprintf(fp, "*%s.Stp%s %s/%s: \"\"\n", lang, desc->name,
+ "None", _("None"));
+ /* Unlike the other fields, dimensions are not strictly numbers */
+ for (i = (int) desc->bounds.dimension.lower;
+ i <= (int) desc->bounds.dimension.upper; i++)
+ {
+ snprintf(dimstr, sizeof(dimstr), _("%.1f mm"),
+ (double)i * 25.4 / 72.0);
+ gpprintf(fp, "*%s.Stp%s %d/%s: \"\"\n", lang,
+ desc->name, i, dimstr);
+ }
+ gpprintf(fp, "*%s.ParamCustomStp%s Value/%s: \"\"\n", lang,
+ desc->name, _("Value"));
+ break;
+
+ case STP_PARAMETER_TYPE_INT:
+ if (!desc->is_mandatory)
+ gpprintf(fp, "*%s.Stp%s %s/%s: \"\"\n", lang, desc->name,
+ "None", _("None"));
+ if (localize_numbers)
+ {
+ for (i = desc->bounds.integer.lower;
+ i <= desc->bounds.integer.upper; i++)
+ {
+ gpprintf(fp, "*%s.Stp%s %d/%d: \"\"\n", lang, desc->name, i, i);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+print_standard_fonts(gpFile fp)
+{
+ gpputs(fp, "\n*DefaultFont: Courier\n");
+ gpputs(fp, "*Font AvantGarde-Book: Standard \"(001.006S)\" Standard ROM\n");
+ gpputs(fp, "*Font AvantGarde-BookOblique: Standard \"(001.006S)\" Standard ROM\n");
+ gpputs(fp, "*Font AvantGarde-Demi: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font AvantGarde-DemiOblique: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font Bookman-Demi: Standard \"(001.004S)\" Standard ROM\n");
+ gpputs(fp, "*Font Bookman-DemiItalic: Standard \"(001.004S)\" Standard ROM\n");
+ gpputs(fp, "*Font Bookman-Light: Standard \"(001.004S)\" Standard ROM\n");
+ gpputs(fp, "*Font Bookman-LightItalic: Standard \"(001.004S)\" Standard ROM\n");
+ gpputs(fp, "*Font Courier: Standard \"(002.004S)\" Standard ROM\n");
+ gpputs(fp, "*Font Courier-Bold: Standard \"(002.004S)\" Standard ROM\n");
+ gpputs(fp, "*Font Courier-BoldOblique: Standard \"(002.004S)\" Standard ROM\n");
+ gpputs(fp, "*Font Courier-Oblique: Standard \"(002.004S)\" Standard ROM\n");
+ gpputs(fp, "*Font Helvetica: Standard \"(001.006S)\" Standard ROM\n");
+ gpputs(fp, "*Font Helvetica-Bold: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font Helvetica-BoldOblique: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font Helvetica-Narrow: Standard \"(001.006S)\" Standard ROM\n");
+ gpputs(fp, "*Font Helvetica-Narrow-Bold: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font Helvetica-Narrow-BoldOblique: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font Helvetica-Narrow-Oblique: Standard \"(001.006S)\" Standard ROM\n");
+ gpputs(fp, "*Font Helvetica-Oblique: Standard \"(001.006S)\" Standard ROM\n");
+ gpputs(fp, "*Font NewCenturySchlbk-Bold: Standard \"(001.009S)\" Standard ROM\n");
+ gpputs(fp, "*Font NewCenturySchlbk-BoldItalic: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font NewCenturySchlbk-Italic: Standard \"(001.006S)\" Standard ROM\n");
+ gpputs(fp, "*Font NewCenturySchlbk-Roman: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font Palatino-Bold: Standard \"(001.005S)\" Standard ROM\n");
+ gpputs(fp, "*Font Palatino-BoldItalic: Standard \"(001.005S)\" Standard ROM\n");
+ gpputs(fp, "*Font Palatino-Italic: Standard \"(001.005S)\" Standard ROM\n");
+ gpputs(fp, "*Font Palatino-Roman: Standard \"(001.005S)\" Standard ROM\n");
+ gpputs(fp, "*Font Symbol: Special \"(001.007S)\" Special ROM\n");
+ gpputs(fp, "*Font Times-Bold: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font Times-BoldItalic: Standard \"(001.009S)\" Standard ROM\n");
+ gpputs(fp, "*Font Times-Italic: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font Times-Roman: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font ZapfChancery-MediumItalic: Standard \"(001.007S)\" Standard ROM\n");
+ gpputs(fp, "*Font ZapfDingbats: Special \"(001.004S)\" Standard ROM\n");
+}
+
+/*
+ * 'write_ppd()' - Write a PPD file.
+ */
+
+int /* O - Exit status */
+write_ppd(
+ gpFile fp, /* I - File to write to */
+ const stp_printer_t *p, /* I - Printer driver */
+ const char *language, /* I - Primary language */
+ const char *ppd_location, /* I - Location of PPD file */
+ ppd_type_t ppd_type, /* I - 1 = simplified options */
+ const char *filename, /* I - input filename */
+ int compress) /* I - compress output */
+{
+ int i, j, k, l; /* Looping vars */
+ int num_opts; /* Number of printer options */
+ stp_resolution_t xdpi, ydpi; /* Resolution info */
+ stp_vars_t *v; /* Variable info */
+ const char *driver; /* Driver name */
+ const char *family; /* Printer family */
+ int model; /* Internal model ID */
+ const char *long_name; /* Driver long name */
+ const char *manufacturer; /* Manufacturer of printer */
+ const char *device_id; /* IEEE1284 device ID */
+ const stp_vars_t *printvars; /* Printer option names */
+ int nativecopies = 0; /* Printer natively generates copies */
+ stp_parameter_t desc;
+ stp_parameter_list_t param_list;
+ const stp_param_string_t *opt;
+ int has_quality_parameter = 0;
+ int printer_is_color = 0;
+ int simplified = ppd_type == PPD_SIMPLIFIED;
+ int skip_color = ppd_type == PPD_NO_COLOR_OPTS;
+ int maximum_level = simplified ?
+ STP_PARAMETER_LEVEL_BASIC : STP_PARAMETER_LEVEL_ADVANCED4;
+ char *default_resolution = NULL; /* Default resolution mapped name */
+ stp_string_list_t *resolutions = stp_string_list_create();
+ char **all_langs = getlangs();/* All languages */
+ const stp_string_list_t *po = stp_i18n_load(language);
+ /* Message catalog */
+
+ /*
+ * This is ugly. The right thing would be to pass this through, but
+ * then all calls to gpputs, gpprintf, etc. and callers would need to
+ * have this arg.
+ */
+ use_compression = compress;
+ /*
+ * Initialize driver-specific variables...
+ */
+
+ driver = stp_printer_get_driver(p);
+ family = stp_printer_get_family(p);
+ model = stp_printer_get_model(p);
+ long_name = stp_printer_get_long_name(p);
+ manufacturer = stp_printer_get_manufacturer(p);
+ device_id = stp_printer_get_device_id(p);
+ printvars = stp_printer_get_defaults(p);
+
+ print_ppd_header(fp, ppd_type, model, driver, family, long_name,
+ manufacturer, device_id, ppd_location, language, po,
+ all_langs);
+
+
+ /* Set Job Mode to "Job" as this enables the Duplex option */
+ v = stp_vars_create_copy(printvars);
+ stp_set_string_parameter(v, "JobMode", "Job");
+
+ /* Assume that color printers are inkjets and should have pages reversed */
+ stp_describe_parameter(v, "PrintingMode", &desc);
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
+ {
+ if (stp_string_list_is_present(desc.bounds.str, "Color"))
+ {
+ printer_is_color = 1;
+ gpputs(fp, "*ColorDevice: True\n");
+ }
+ else
+ {
+ printer_is_color = 0;
+ gpputs(fp, "*ColorDevice: False\n");
+ }
+ if (strcmp(desc.deflt.str, "Color") == 0)
+ gpputs(fp, "*DefaultColorSpace: RGB\n");
+ else
+ gpputs(fp, "*DefaultColorSpace: Gray\n");
+ }
+ stp_parameter_description_destroy(&desc);
+
+ stp_describe_parameter(v, "NativeCopies", &desc);
+ if (desc.p_type == STP_PARAMETER_TYPE_BOOLEAN)
+ nativecopies = desc.deflt.boolean;
+ stp_parameter_description_destroy(&desc);
+
+ if (nativecopies)
+ gpputs(fp, "*cupsManualCopies: False\n");
+ else
+ gpputs(fp, "*cupsManualCopies: True\n");
+
+ print_ppd_header_3(fp, ppd_type, model,
+ driver, family, long_name,
+ manufacturer, device_id, ppd_location, language, po,
+ all_langs);
+
+ /* Macintosh color management */
+
+#ifdef __APPLE__
+ gpputs(fp, "*cupsICCProfile Gray../Grayscale: \"/System/Library/ColorSync/Profiles/sRGB Profile.icc\"\n");
+ gpputs(fp, "*cupsICCProfile RGB../Color: \"/System/Library/ColorSync/Profiles/sRGB Profile.icc\"\n");
+ gpputs(fp, "*cupsICCProfile CMYK../Color: \"/System/Library/ColorSync/Profiles/Generic CMYK Profile.icc\"\n");
+ gpputs(fp, "*APSupportsCustomColorMatching: true\n");
+ gpputs(fp, "*APDefaultCustomColorMatchingProfile: sRGB\n");
+ gpputs(fp, "*APCustomColorMatchingProfile: sRGB\n");
+#endif
+
+ gpputs(fp, "\n");
+
+ print_ppd_header_2(fp, ppd_type, model, driver, family, long_name,
+ manufacturer, device_id, ppd_location, language, po,
+ all_langs);
+
+ /*
+ * Get the page sizes from the driver...
+ */
+
+ if (printer_is_color)
+ stp_set_string_parameter(v, "PrintingMode", "Color");
+ else
+ stp_set_string_parameter(v, "PrintingMode", "BW");
+ stp_set_string_parameter(v, "ChannelBitDepth", "8");
+ print_page_sizes(fp, v, simplified, po);
+
+ /*
+ * Do we support color?
+ */
+
+ print_color_setup(fp, simplified, printer_is_color, po);
+
+ /*
+ * Media types...
+ */
+
+ stp_describe_parameter(v, "MediaType", &desc);
+
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && desc.is_active &&
+ stp_string_list_count(desc.bounds.str) > 0)
+ {
+ int is_color_opt =
+ stp_parameter_has_category_value(v, &desc, "Color", "Yes");
+ int nocolor = skip_color && is_color_opt;
+ num_opts = stp_string_list_count(desc.bounds.str);
+ if (is_color_opt)
+ gpprintf(fp, "*ColorKeyWords: \"MediaType\"\n");
+ gpprintf(fp, "*OpenUI *MediaType/%s: PickOne\n", _("Media Type"));
+ gpputs(fp, "*OPOptionHints MediaType: \"dropdown\"\n");
+ gpputs(fp, "*OrderDependency: 10 AnySetup *MediaType\n");
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc.name, desc.p_type, desc.is_mandatory,
+ desc.p_class, desc.p_level, desc.channel, 0.0, 0.0, 0.0);
+ gpprintf(fp, "*DefaultMediaType: %s\n", desc.deflt.str);
+ gpprintf(fp, "*StpDefaultMediaType: %s\n", desc.deflt.str);
+
+ for (i = 0; i < num_opts; i ++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ gpprintf(fp, "*%sMediaType %s/%s:\t\"<</MediaType(%s)>>setpagedevice\"\n",
+ nocolor && strcmp(opt->name, desc.deflt.str) != 0 ? "?" : "",
+ opt->name, stp_i18n_lookup(po, opt->text), opt->name);
+ }
+
+ gpputs(fp, "*CloseUI: *MediaType\n\n");
+ }
+ stp_parameter_description_destroy(&desc);
+
+ /*
+ * Input slots...
+ */
+
+ stp_describe_parameter(v, "InputSlot", &desc);
+
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && desc.is_active &&
+ stp_string_list_count(desc.bounds.str) > 0)
+ {
+ int is_color_opt =
+ stp_parameter_has_category_value(v, &desc, "Color", "Yes");
+ int nocolor = skip_color && is_color_opt;
+ num_opts = stp_string_list_count(desc.bounds.str);
+ if (is_color_opt)
+ gpprintf(fp, "*ColorKeyWords: \"InputSlot\"\n");
+ gpprintf(fp, "*OpenUI *InputSlot/%s: PickOne\n", _("Media Source"));
+ gpputs(fp, "*OPOptionHints InputSlot: \"dropdown\"\n");
+ gpputs(fp, "*OrderDependency: 10 AnySetup *InputSlot\n");
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc.name, desc.p_type, desc.is_mandatory,
+ desc.p_class, desc.p_level, desc.channel, 0.0, 0.0, 0.0);
+ gpprintf(fp, "*DefaultInputSlot: %s\n", desc.deflt.str);
+ gpprintf(fp, "*StpDefaultInputSlot: %s\n", desc.deflt.str);
+
+ for (i = 0; i < num_opts; i ++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ gpprintf(fp, "*%sInputSlot %s/%s:\t\"<</MediaClass(%s)>>setpagedevice\"\n",
+ nocolor && strcmp(opt->name, desc.deflt.str) != 0 ? "?" : "",
+ opt->name, stp_i18n_lookup(po, opt->text), opt->name);
+ }
+
+ gpputs(fp, "*CloseUI: *InputSlot\n\n");
+ }
+ stp_parameter_description_destroy(&desc);
+
+ /*
+ * Quality settings
+ */
+
+ stp_describe_parameter(v, "Quality", &desc);
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && desc.is_active)
+ {
+ int is_color_opt =
+ stp_parameter_has_category_value(v, &desc, "Color", "Yes");
+ int nocolor = skip_color && is_color_opt;
+ if (is_color_opt)
+ gpprintf(fp, "*ColorKeyWords: \"Quality\"\n");
+ stp_clear_string_parameter(v, "Resolution");
+ has_quality_parameter = 1;
+ num_opts = stp_string_list_count(desc.bounds.str);
+ gpprintf(fp, "*OpenUI *StpQuality/%s: PickOne\n", stp_i18n_lookup(po, desc.text));
+ if (num_opts > 3)
+ gpputs(fp, "*OPOptionHints Quality: \"radiobuttons\"\n");
+ else
+ gpputs(fp, "*OPOptionHints Quality: \"dropdown\"\n");
+ gpputs(fp, "*OrderDependency: 10 AnySetup *StpQuality\n");
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc.name, desc.p_type, desc.is_mandatory,
+ desc.p_type, desc.p_level, desc.channel, 0.0, 0.0, 0.0);
+ gpprintf(fp, "*DefaultStpQuality: %s\n", desc.deflt.str);
+ gpprintf(fp, "*StpDefaultStpQuality: %s\n", desc.deflt.str);
+ for (i = 0; i < num_opts; i++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ stp_set_string_parameter(v, "Quality", opt->name);
+ stp_describe_resolution(v, &xdpi, &ydpi);
+ if (xdpi == -1 || ydpi == -1)
+ {
+ stp_parameter_t res_desc;
+ stp_clear_string_parameter(v, "Quality");
+ stp_describe_parameter(v, "Resolution", &res_desc);
+ stp_set_string_parameter(v, "Resolution", res_desc.deflt.str);
+ stp_describe_resolution(v, &xdpi, &ydpi);
+ stp_clear_string_parameter(v, "Resolution");
+ stp_parameter_description_destroy(&res_desc);
+ }
+ gpprintf(fp, "*%sStpQuality %s/%s:\t\"<</HWResolution[%d %d]/cupsRowFeed %d>>setpagedevice\"\n",
+ nocolor && strcmp(opt->name, desc.deflt.str) != 0 ? "?" : "",
+ opt->name, stp_i18n_lookup(po, opt->text), (int) xdpi, (int) ydpi, i + 1);
+ }
+ gpputs(fp, "*CloseUI: *StpQuality\n\n");
+ }
+ stp_parameter_description_destroy(&desc);
+ stp_clear_string_parameter(v, "Quality");
+
+ /*
+ * Resolutions...
+ */
+
+ stp_describe_parameter(v, "Resolution", &desc);
+
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && desc.is_active)
+ {
+ num_opts = stp_string_list_count(desc.bounds.str);
+ if (!simplified || desc.p_level == STP_PARAMETER_LEVEL_BASIC)
+ {
+ int is_color_opt =
+ stp_parameter_has_category_value(v, &desc, "Color", "Yes");
+ int nocolor = skip_color && is_color_opt;
+ stp_string_list_t *res_list = stp_string_list_create();
+ char res_name[64]; /* Plenty long enough for XXXxYYYdpi */
+ int resolution_ok;
+ stp_resolution_t tmp_xdpi, tmp_ydpi;
+
+ if (is_color_opt)
+ gpprintf(fp, "*ColorKeyWords: \"Resolution\"\n");
+ gpprintf(fp, "*OpenUI *Resolution/%s: PickOne\n", _("Resolution"));
+ if (num_opts > 3)
+ gpputs(fp, "*OPOptionHints Resolution: \"resolution radiobuttons\"\n");
+ else
+ gpputs(fp, "*OPOptionHints Resolution: \"resolution dropdown\"\n");
+ gpputs(fp, "*OrderDependency: 10 AnySetup *Resolution\n");
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc.name, desc.p_type, desc.is_mandatory,
+ desc.p_class, desc.p_level, desc.channel, 0.0, 0.0, 0.0);
+ if (has_quality_parameter)
+ {
+ stp_parameter_t desc1;
+ stp_clear_string_parameter(v, "Resolution");
+ stp_describe_parameter(v, "Quality", &desc1);
+ stp_set_string_parameter(v, "Quality", desc1.deflt.str);
+ stp_parameter_description_destroy(&desc1);
+ stp_describe_resolution(v, &xdpi, &ydpi);
+ stp_clear_string_parameter(v, "Quality");
+ tmp_xdpi = xdpi;
+ while (tmp_xdpi > MAXIMUM_SAFE_PPD_X_RESOLUTION)
+ tmp_xdpi /= 2;
+ tmp_ydpi = ydpi;
+ while (tmp_ydpi > MAXIMUM_SAFE_PPD_Y_RESOLUTION)
+ tmp_ydpi /= 2;
+ if (tmp_ydpi < tmp_xdpi)
+ tmp_xdpi = tmp_ydpi;
+ /*
+ Make the default resolution look like an almost square resolution
+ so that applications using it will be less likely to generate
+ excess resolution. However, make the hardware resolution
+ match the printer default.
+ */
+ (void) snprintf(res_name, 63, "%dx%ddpi", (int) tmp_xdpi + 1, (int) tmp_xdpi);
+ default_resolution = stp_strdup(res_name);
+ stp_string_list_add_string(res_list, res_name, res_name);
+ gpprintf(fp, "*DefaultResolution: %s\n", res_name);
+ gpprintf(fp, "*StpDefaultResolution: %s\n", res_name);
+ gpprintf(fp, "*Resolution %s/%s:\t\"<</HWResolution[%d %d]>>setpagedevice\"\n",
+ res_name, _("Automatic"), (int) xdpi, (int) ydpi);
+ gpprintf(fp, "*StpResolutionMap: %s %s\n", res_name, "None");
+ }
+ else
+ {
+ stp_set_string_parameter(v, "Resolution", desc.deflt.str);
+ stp_describe_resolution(v, &xdpi, &ydpi);
+
+ if (xdpi == ydpi)
+ (void) snprintf(res_name, 63, "%ddpi", (int) xdpi);
+ else
+ (void) snprintf(res_name, 63, "%dx%ddpi", (int) xdpi, (int) ydpi);
+ gpprintf(fp, "*DefaultResolution: %s\n", res_name);
+ gpprintf(fp, "*StpDefaultResolution: %s\n", res_name);
+ /*
+ * We need to add this to the resolution list here so that
+ * some non-default resolution won't wind up with the
+ * default resolution name
+ */
+ stp_string_list_add_string(res_list, res_name, res_name);
+ }
+
+ stp_clear_string_parameter(v, "Quality");
+ for (i = 0; i < num_opts; i ++)
+ {
+ /*
+ * Strip resolution name to its essentials...
+ */
+ opt = stp_string_list_param(desc.bounds.str, i);
+ stp_set_string_parameter(v, "Resolution", opt->name);
+ stp_describe_resolution(v, &xdpi, &ydpi);
+
+ /* This should only happen with a "None" resolution */
+ if (xdpi == -1 || ydpi == -1)
+ continue;
+
+ resolution_ok = 0;
+ tmp_xdpi = xdpi;
+ while (tmp_xdpi > MAXIMUM_SAFE_PPD_X_RESOLUTION)
+ tmp_xdpi /= 2;
+ tmp_ydpi = ydpi;
+ while (tmp_ydpi > MAXIMUM_SAFE_PPD_Y_RESOLUTION)
+ tmp_ydpi /= 2;
+ do
+ {
+ if (tmp_xdpi == tmp_ydpi)
+ (void) snprintf(res_name, 63, "%ddpi", (int) tmp_xdpi);
+ else
+ (void) snprintf(res_name, 63, "%dx%ddpi", (int) tmp_xdpi, (int) tmp_ydpi);
+ if ((!has_quality_parameter &&
+ strcmp(opt->name, desc.deflt.str) == 0) ||
+ !stp_string_list_is_present(res_list, res_name))
+ {
+ resolution_ok = 1;
+ stp_string_list_add_string(res_list, res_name, opt->text);
+ }
+ else if (tmp_ydpi > tmp_xdpi &&
+ tmp_ydpi < MAXIMUM_SAFE_PPD_Y_RESOLUTION)
+ /* Note that we're incrementing the *higher* resolution.
+ This will generate less aliasing, and apps that convert
+ down to a square resolution will do the right thing. */
+ tmp_ydpi++;
+ else if (tmp_xdpi < MAXIMUM_SAFE_PPD_X_RESOLUTION)
+ tmp_xdpi++;
+ else
+ tmp_xdpi /= 2;
+ } while (!resolution_ok);
+ stp_string_list_add_string(resolutions, res_name, opt->text);
+ gpprintf(fp, "*%sResolution %s/%s:\t\"<</HWResolution[%d %d]/cupsCompression %d>>setpagedevice\"\n",
+ nocolor && strcmp(opt->name, desc.deflt.str) != 0 ? "?" : "",
+ res_name, stp_i18n_lookup(po, opt->text), (int) xdpi, (int) ydpi, i + 1);
+ if (strcmp(res_name, opt->name) != 0)
+ gpprintf(fp, "*StpResolutionMap: %s %s\n", res_name, opt->name);
+ }
+
+ stp_string_list_destroy(res_list);
+ stp_clear_string_parameter(v, "Resolution");
+ gpputs(fp, "*CloseUI: *Resolution\n\n");
+ }
+ }
+
+ stp_parameter_description_destroy(&desc);
+
+ stp_describe_parameter(v, "OutputOrder", &desc);
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
+ {
+ gpprintf(fp, "*OpenUI *OutputOrder/%s: PickOne\n", _("Output Order"));
+ gpputs(fp, "*OPOptionHints OutputOrder: \"radiobuttons\"\n");
+ gpputs(fp, "*OrderDependency: 10 AnySetup *OutputOrder\n");
+ gpprintf(fp, "*DefaultOutputOrder: %s\n", desc.deflt.str);
+ gpprintf(fp, "*StpDefaultOutputOrder: %s\n", desc.deflt.str);
+ gpprintf(fp, "*OutputOrder Normal/%s: \"\"\n", _("Normal"));
+ gpprintf(fp, "*OutputOrder Reverse/%s: \"\"\n", _("Reverse"));
+ gpputs(fp, "*CloseUI: *OutputOrder\n\n");
+ }
+ stp_parameter_description_destroy(&desc);
+
+ /*
+ * Duplex
+ * Note that the opt->name strings MUST match those in the printer driver(s)
+ * else the PPD files will not be generated correctly
+ */
+
+ stp_describe_parameter(v, "Duplex", &desc);
+ if (desc.is_active && desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
+ {
+ num_opts = stp_string_list_count(desc.bounds.str);
+ if (num_opts > 0)
+ {
+ int is_color_opt =
+ stp_parameter_has_category_value(v, &desc, "Color", "Yes");
+ if (is_color_opt)
+ gpprintf(fp, "*ColorKeyWords: \"InputSlot\"\n");
+ gpprintf(fp, "*OpenUI *Duplex/%s: PickOne\n", _("2-Sided Printing"));
+ gpputs(fp, "*OPOptionHints Duplex: \"radiobuttons\"\n");
+ gpputs(fp, "*OrderDependency: 10 AnySetup *Duplex\n");
+ gpprintf(fp, "*StpStp%s: %d %d %d %d %d %.3f %.3f %.3f\n",
+ desc.name, desc.p_type, desc.is_mandatory,
+ desc.p_class, desc.p_level, desc.channel, 0.0, 0.0, 0.0);
+ gpprintf(fp, "*DefaultDuplex: %s\n", desc.deflt.str);
+ gpprintf(fp, "*StpDefaultDuplex: %s\n", desc.deflt.str);
+
+ for (i = 0; i < num_opts; i++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ if (strcmp(opt->name, "None") == 0)
+ gpprintf(fp, "*Duplex %s/%s: \"<</Duplex false>>setpagedevice\"\n", opt->name, stp_i18n_lookup(po, opt->text));
+ else if (strcmp(opt->name, "DuplexNoTumble") == 0)
+ gpprintf(fp, "*Duplex %s/%s: \"<</Duplex true/Tumble false>>setpagedevice\"\n", opt->name, stp_i18n_lookup(po, opt->text));
+ else if (strcmp(opt->name, "DuplexTumble") == 0)
+ gpprintf(fp, "*Duplex %s/%s: \"<</Duplex true/Tumble true>>setpagedevice\"\n", opt->name, stp_i18n_lookup(po, opt->text));
+ }
+ gpputs(fp, "*CloseUI: *Duplex\n\n");
+ }
+ }
+ stp_parameter_description_destroy(&desc);
+
+ gpprintf(fp, "*OpenUI *StpiShrinkOutput/%s: PickOne\n",
+ _("Shrink Page If Necessary to Fit Borders"));
+ gpputs(fp, "*OPOptionHints StpiShrinkOutput: \"radiobuttons\"\n");
+ gpputs(fp, "*OrderDependency: 10 AnySetup *StpiShrinkOutput\n");
+ gpputs(fp, "*DefaultStpiShrinkOutput: Shrink\n");
+ gpputs(fp, "*StpDefaultStpiShrinkOutput: Shrink\n");
+ gpprintf(fp, "*StpiShrinkOutput %s/%s: \"\"\n", "Shrink", _("Shrink (print the whole page)"));
+ gpprintf(fp, "*StpiShrinkOutput %s/%s: \"\"\n", "Crop", _("Crop (preserve dimensions)"));
+ gpprintf(fp, "*StpiShrinkOutput %s/%s: \"\"\n", "Expand", _("Expand (use maximum page area)"));
+ gpputs(fp, "*CloseUI: *StpiShrinkOutput\n\n");
+
+ param_list = stp_get_parameter_list(v);
+
+ for (j = 0; j <= STP_PARAMETER_CLASS_OUTPUT; j++)
+ {
+ for (k = 0; k <= maximum_level; k++)
+ {
+ int printed_open_group = 0;
+ size_t param_count = stp_parameter_list_count(param_list);
+ for (l = 0; l < param_count; l++)
+ {
+ const stp_parameter_t *lparam =
+ stp_parameter_list_param(param_list, l);
+ if (lparam->p_class != j || lparam->p_level != k ||
+ is_special_option(lparam->name) || lparam->read_only ||
+ (lparam->p_type != STP_PARAMETER_TYPE_STRING_LIST &&
+ lparam->p_type != STP_PARAMETER_TYPE_RAW &&
+ lparam->p_type != STP_PARAMETER_TYPE_BOOLEAN &&
+ lparam->p_type != STP_PARAMETER_TYPE_DIMENSION &&
+ lparam->p_type != STP_PARAMETER_TYPE_INT &&
+ lparam->p_type != STP_PARAMETER_TYPE_DOUBLE))
+ continue;
+ stp_describe_parameter(v, lparam->name, &desc);
+ if (desc.is_active)
+ {
+ if (!printed_open_group)
+ {
+ print_group_open(fp, j, k, language, po);
+ printed_open_group = 1;
+ }
+ print_one_option(fp, v, po, ppd_type, lparam, &desc);
+ }
+ stp_parameter_description_destroy(&desc);
+ }
+ if (printed_open_group)
+ print_group_close(fp, j, k, language, po);
+ }
+ }
+ stp_describe_parameter(v, "ImageType", &desc);
+ if (desc.is_active && desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
+ {
+ num_opts = stp_string_list_count(desc.bounds.str);
+ if (num_opts > 0)
+ {
+ for (i = 0; i < num_opts; i++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ if (strcmp(opt->name, "None") != 0)
+ gpprintf(fp, "*APPrinterPreset %s/%s: \"*StpImageType %s\"\n",
+ opt->name, stp_i18n_lookup(po, opt->text), opt->name);
+ }
+ gpputs(fp, "\n");
+ }
+ }
+ stp_parameter_description_destroy(&desc);
+
+ if (!language)
+ {
+ /*
+ * Generate globalized PPDs when POSIX language is requested...
+ */
+
+ const char *lang;
+ const stp_string_list_t *savepo = po;
+ int langnum;
+
+ for (langnum = 0; all_langs[langnum]; langnum ++)
+ {
+ lang = all_langs[langnum];
+
+ if (!strcmp(lang, "C") || !strcmp(lang, "en"))
+ continue;
+
+ if ((po = stp_i18n_load(lang)) == NULL)
+ continue;
+
+ /*
+ * Get the page sizes from the driver...
+ */
+
+ if (printer_is_color)
+ stp_set_string_parameter(v, "PrintingMode", "Color");
+ else
+ stp_set_string_parameter(v, "PrintingMode", "BW");
+ stp_set_string_parameter(v, "ChannelBitDepth", "8");
+ stp_describe_parameter(v, "PageSize", &desc);
+ num_opts = stp_string_list_count(desc.bounds.str);
+
+ gpprintf(fp, "*%s.Translation PageSize/%s: \"\"\n", lang, _("Media Size"));
+ gpprintf(fp, "*%s.Translation PageRegion/%s: \"\"\n", lang, _("Media Size"));
+
+ for (i = 0; i < num_opts; i++)
+ {
+ const stp_papersize_t *papersize;
+ opt = stp_string_list_param(desc.bounds.str, i);
+ papersize = stp_describe_papersize(v, opt->name);
+
+ if (!papersize)
+ continue;
+
+ /*
+ if (strcmp(opt->name, "Custom") == 0)
+ continue;
+ */
+
+ if (simplified && num_opts >= 10 &&
+ (!desc.deflt.str || strcmp(opt->name, desc.deflt.str) != 0) &&
+ (papersize->paper_unit == PAPERSIZE_ENGLISH_EXTENDED ||
+ papersize->paper_unit == PAPERSIZE_METRIC_EXTENDED ||
+ ((papersize->width <= 0 || papersize->height <= 0) &&
+ strcmp(opt->name, "Custom") != 0)))
+ continue;
+
+ gpprintf(fp, "*%s.PageSize %s/%s: \"\"\n", lang, opt->name, stp_i18n_lookup(po, opt->text));
+ gpprintf(fp, "*%s.PageRegion %s/%s: \"\"\n", lang, opt->name, stp_i18n_lookup(po, opt->text));
+ }
+
+ stp_parameter_description_destroy(&desc);
+
+ /*
+ * Do we support color?
+ */
+
+ gpprintf(fp, "*%s.Translation ColorModel/%s: \"\"\n", lang, _("Color Model"));
+ gpprintf(fp, "*%s.ColorModel Gray/%s: \"\"\n", lang, _("Grayscale"));
+ gpprintf(fp, "*%s.ColorModel Black/%s: \"\"\n", lang, _("Inverted Grayscale"));
+
+ if (printer_is_color)
+ {
+ gpprintf(fp, "*%s.ColorModel RGB/%s: \"\"\n", lang, _("RGB Color"));
+ gpprintf(fp, "*%s.ColorModel CMY/%s: \"\"\n", lang, _("CMY Color"));
+ gpprintf(fp, "*%s.ColorModel CMYK/%s: \"\"\n", lang, _("CMYK"));
+ gpprintf(fp, "*%s.ColorModel KCMY/%s: \"\"\n", lang, _("KCMY"));
+ }
+
+ if (!simplified)
+ {
+ /*
+ * 8 or 16 bit color (16 bit is slower)
+ */
+ gpprintf(fp, "*%s.Translation StpColorPrecision/%s: \"\"\n", lang, _("Color Precision"));
+ gpprintf(fp, "*%s.StpColorPrecision Normal/%s: \"\"\n", lang, _("Normal"));
+ gpprintf(fp, "*%s.StpColorPrecision Best/%s: \"\"\n", lang, _("Best"));
+ }
+
+ /*
+ * Media types...
+ */
+
+ stp_describe_parameter(v, "MediaType", &desc);
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && desc.is_active &&
+ stp_string_list_count(desc.bounds.str) > 0)
+ {
+ num_opts = stp_string_list_count(desc.bounds.str);
+ gpprintf(fp, "*%s.Translation MediaType/%s: \"\"\n", lang, _("Media Type"));
+
+ for (i = 0; i < num_opts; i ++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ gpprintf(fp, "*%s.MediaType %s/%s: \"\"\n", lang, opt->name, stp_i18n_lookup(po, opt->text));
+ }
+ }
+ stp_parameter_description_destroy(&desc);
+
+ /*
+ * Input slots...
+ */
+
+ stp_describe_parameter(v, "InputSlot", &desc);
+
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && desc.is_active &&
+ stp_string_list_count(desc.bounds.str) > 0)
+ {
+ num_opts = stp_string_list_count(desc.bounds.str);
+ gpprintf(fp, "*%s.Translation InputSlot/%s: \"\"\n", lang, _("Media Source"));
+
+ for (i = 0; i < num_opts; i ++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ gpprintf(fp, "*%s.InputSlot %s/%s: \"\"\n", lang, opt->name, stp_i18n_lookup(po, opt->text));
+ }
+ }
+ stp_parameter_description_destroy(&desc);
+
+ /*
+ * Quality settings
+ */
+
+ stp_describe_parameter(v, "Quality", &desc);
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && desc.is_active)
+ {
+ gpprintf(fp, "*%s.Translation StpQuality/%s: \"\"\n", lang, stp_i18n_lookup(po, desc.text));
+ num_opts = stp_string_list_count(desc.bounds.str);
+ for (i = 0; i < num_opts; i++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ gpprintf(fp, "*%s.StpQuality %s/%s: \"\"\n", lang, opt->name, stp_i18n_lookup(po, opt->text));
+ }
+ }
+ stp_parameter_description_destroy(&desc);
+
+ /*
+ * Resolution
+ */
+
+ stp_describe_parameter(v, "Resolution", &desc);
+
+ if (!simplified || desc.p_level == STP_PARAMETER_LEVEL_BASIC)
+ {
+ gpprintf(fp, "*%s.Translation Resolution/%s: \"\"\n", lang, _("Resolution"));
+ if (has_quality_parameter)
+ gpprintf(fp, "*%s.Resolution %s/%s: \"\"\n", lang,
+ default_resolution, _("Automatic"));
+
+ num_opts = stp_string_list_count(resolutions);
+ for (i = 0; i < num_opts; i ++)
+ {
+ opt = stp_string_list_param(resolutions, i);
+ gpprintf(fp, "*%s.Resolution %s/%s: \"\"\n", lang,
+ opt->name, stp_i18n_lookup(po, opt->text));
+ }
+ }
+
+ stp_parameter_description_destroy(&desc);
+
+ /*
+ * OutputOrder
+ */
+
+ stp_describe_parameter(v, "OutputOrder", &desc);
+ if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
+ {
+ gpprintf(fp, "*%s.Translation OutputOrder/%s: \"\"\n", lang, _("Output Order"));
+ gpprintf(fp, "*%s.OutputOrder Normal/%s: \"\"\n", lang, _("Normal"));
+ gpprintf(fp, "*%s.OutputOrder Reverse/%s: \"\"\n", lang, _("Reverse"));
+ }
+ stp_parameter_description_destroy(&desc);
+
+ /*
+ * Duplex
+ * Note that the opt->name strings MUST match those in the printer driver(s)
+ * else the PPD files will not be generated correctly
+ */
+
+ stp_describe_parameter(v, "Duplex", &desc);
+ if (desc.is_active && desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
+ {
+ num_opts = stp_string_list_count(desc.bounds.str);
+ if (num_opts > 0)
+ {
+ gpprintf(fp, "*%s.Translation Duplex/%s: \"\"\n", lang, _("2-Sided Printing"));
+
+ for (i = 0; i < num_opts; i++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ if (strcmp(opt->name, "None") == 0)
+ gpprintf(fp, "*%s.Duplex %s/%s: \"\"\n", lang, opt->name, stp_i18n_lookup(po, opt->text));
+ else if (strcmp(opt->name, "DuplexNoTumble") == 0)
+ gpprintf(fp, "*%s.Duplex %s/%s: \"\"\n", lang, opt->name, stp_i18n_lookup(po, opt->text));
+ else if (strcmp(opt->name, "DuplexTumble") == 0)
+ gpprintf(fp, "*%s.Duplex %s/%s: \"\"\n", lang, opt->name, stp_i18n_lookup(po, opt->text));
+ }
+ }
+ }
+ stp_parameter_description_destroy(&desc);
+
+ gpprintf(fp, "*%s.Translation StpiShrinkOutput/%s: \"\"\n", lang,
+ _("Shrink Page If Necessary to Fit Borders"));
+ gpprintf(fp, "*%s.StpiShrinkOutput %s/%s: \"\"\n", lang, "Shrink", _("Shrink (print the whole page)"));
+ gpprintf(fp, "*%s.StpiShrinkOutput %s/%s: \"\"\n", lang, "Crop", _("Crop (preserve dimensions)"));
+ gpprintf(fp, "*%s.StpiShrinkOutput %s/%s: \"\"\n", lang, "Expand", _("Expand (use maximum page area)"));
+
+ for (j = 0; j <= STP_PARAMETER_CLASS_OUTPUT; j++)
+ {
+ for (k = 0; k <= maximum_level; k++)
+ {
+ size_t param_count = stp_parameter_list_count(param_list);
+ for (l = 0; l < param_count; l++)
+ {
+ const stp_parameter_t *lparam =
+ stp_parameter_list_param(param_list, l);
+ if (lparam->p_class != j || lparam->p_level != k ||
+ is_special_option(lparam->name) || lparam->read_only ||
+ (lparam->p_type != STP_PARAMETER_TYPE_STRING_LIST &&
+ lparam->p_type != STP_PARAMETER_TYPE_BOOLEAN &&
+ lparam->p_type != STP_PARAMETER_TYPE_DIMENSION &&
+ lparam->p_type != STP_PARAMETER_TYPE_INT &&
+ lparam->p_type != STP_PARAMETER_TYPE_DOUBLE))
+ continue;
+ stp_describe_parameter(v, lparam->name, &desc);
+ if (desc.is_active)
+ print_one_localization(fp, po, simplified, lang,
+ lparam, &desc);
+ stp_parameter_description_destroy(&desc);
+ }
+ }
+ }
+ stp_describe_parameter(v, "ImageType", &desc);
+ if (desc.is_active && desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
+ {
+ num_opts = stp_string_list_count(desc.bounds.str);
+ if (num_opts > 0)
+ {
+ for (i = 0; i < num_opts; i++)
+ {
+ opt = stp_string_list_param(desc.bounds.str, i);
+ if (strcmp(opt->name, "None") != 0)
+ gpprintf(fp, "*%s.APPrinterPreset %s/%s: \"*StpImageType %s\"\n",
+ lang, opt->name, opt->text, opt->name);
+ }
+ }
+ }
+ stp_parameter_description_destroy(&desc);
+ }
+ po = savepo;
+ }
+ stp_parameter_list_destroy(param_list);
+ if (has_quality_parameter)
+ stp_free(default_resolution);
+ stp_string_list_destroy(resolutions);
+
+ /*
+ * Fonts...
+ */
+
+ print_standard_fonts(fp);
+ gpprintf(fp, "\n*%% End of %s\n", filename);
+
+ stp_vars_destroy(v);
+
+ return (0);
+}