-/* foomaticrip.c
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// foomaticrip.c
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#include "foomaticrip.h"
#include "util.h"
#include <cupsfilters/colormanager.h>
#include <cupsfilters/filter.h>
-/* Logging */
+
+// Logging
FILE* logh = NULL;
-void _logv(const char *msg, va_list ap)
+
+void
+_logv(const char *msg,
+ va_list ap)
{
- if (!logh)
- return;
- vfprintf(logh, msg, ap);
- fflush(logh);
+ if (!logh)
+ return;
+ vfprintf(logh, msg, ap);
+ fflush(logh);
}
-void _log(const char* msg, ...)
+
+void
+_log(const char* msg,
+ ...)
{
- va_list ap;
- va_start(ap, msg);
- _logv(msg, ap);
- va_end(ap);
+ va_list ap;
+ va_start(ap, msg);
+ _logv(msg, ap);
+ va_end(ap);
}
-void close_log()
+
+void
+close_log()
{
- if (logh && logh != stderr)
- fclose(logh);
+ if (logh && logh != stderr)
+ fclose(logh);
}
-int redirect_log_to_stderr()
+
+int
+redirect_log_to_stderr()
{
- if (dup2(fileno(logh), fileno(stderr)) < 0) {
- _log("Could not dup logh to stderr\n");
- return 0;
- }
- return 1;
+ if (dup2(fileno(logh), fileno(stderr)) < 0)
+ {
+ _log("Could not dup logh to stderr\n");
+ return (0);
+ }
+ return (1);
}
-void rip_die(int status, const char *msg, ...)
+
+void
+rip_die(int status,
+ const char *msg,
+ ...)
{
- va_list ap;
+ va_list ap;
- _log("Process is dying with \"");
- va_start(ap, msg);
- _logv(msg, ap);
- va_end(ap);
- _log("\", exit stat %d\n", status);
+ _log("Process is dying with \"");
+ va_start(ap, msg);
+ _logv(msg, ap);
+ va_end(ap);
+ _log("\", exit stat %d\n", status);
- _log("Cleaning up...\n");
- kill_all_processes();
+ _log("Cleaning up...\n");
+ kill_all_processes();
- exit(status);
+ exit(status);
}
-jobparams_t *job = NULL;
+jobparams_t *job = NULL;
+
-jobparams_t * get_current_job()
+jobparams_t *
+get_current_job()
{
- return job;
+ return (job);
}
-dstr_t *postpipe = NULL; /* command into which the output of this filter should be piped */
+dstr_t *postpipe = NULL; // command into which the output of this filter
+ // should be piped
FILE *postpipe_fh = NULL;
-FILE * open_postpipe()
+
+FILE *
+open_postpipe()
{
- const char *p;
+ const char *p;
- if (postpipe_fh)
- return postpipe_fh;
+ if (postpipe_fh)
+ return (postpipe_fh);
- if (isempty(postpipe->data))
- return stdout;
+ if (isempty(postpipe->data))
+ return (stdout);
- /* Delete possible '|' symbol in the beginning */
- p = skip_whitespace(postpipe->data);
- if (*p && *p == '|')
- p += 1;
+ // Delete possible '|' symbol in the beginning
+ p = skip_whitespace(postpipe->data);
+ if (*p && *p == '|')
+ p += 1;
- if (start_system_process("postpipe", p, &postpipe_fh, NULL) < 0)
- rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
- "Cannot execute postpipe %s\n", postpipe->data);
+ if (start_system_process("postpipe", p, &postpipe_fh, NULL) < 0)
+ rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
+ "Cannot execute postpipe %s\n", postpipe->data);
- return postpipe_fh;
+ return (postpipe_fh);
}
int jobhasjcl;
int pdfconvertedtops;
-/* Streaming mode: Assume PostScript input, no zero-page job check */
+// Streaming mode: Assume PostScript input, no zero-page job check
int streaming = 0;
-/* cm-calibration flag */
+// cm-calibration flag
int cm_calibrate = 0;
int cm_disabled = 0;
-/* These variables were in 'dat' before */
+// These variables were in 'dat' before
char colorprofile [128];
char cupsfilter[256];
char **jclprepend = NULL;
dstr_t *jclappend;
-/* Set debug to 1 to enable the debug logfile for this filter; it will
- * appear as defined by LOG_FILE. It will contain status from this
- * filter, plus the renderer's stderr output. You can also add a line
- * "debug: 1" to your /etc/cups/foomatic-rip.conf or
- * /etc/foomatic/filter.conf to get all your Foomatic filters into
- * debug mode. WARNING: This logfile is a security hole; do not use
- * in production. */
+// Set debug to 1 to enable the debug logfile for this filter; it will
+// appear as defined by LOG_FILE. It will contain status from this
+// filter, plus the renderer's stderr output. You can also add a line
+// "debug: 1" to your /etc/cups/foomatic-rip.conf or
+// /etc/foomatic/filter.conf to get all your Foomatic filters into
+// debug mode. WARNING: This logfile is a security hole; do not use
+// in production.
int debug = 0;
-/* Path to the GhostScript which foomatic-rip shall use */
+// Path to the GhostScript which foomatic-rip shall use
char gspath[PATH_MAX] = "gs";
-/* What 'echo' program to use. It needs -e and -n. Linux's builtin
-and regular echo work fine; non-GNU platforms may need to install
-gnu echo and put gecho here or something. */
+// What 'echo' program to use. It needs -e and -n. Linux's builtin
+// and regular echo work fine; non-GNU platforms may need to install
+// gnu echo and put gecho here or something.
char echopath[PATH_MAX] = "echo";
-/* CUPS raster drivers are searched here */
+// CUPS raster drivers are searched here
char cupsfilterpath[PATH_MAX] = "/usr/local/lib/cups/filter:"
"/usr/local/libexec/cups/filter:"
"/opt/cups/filter:"
char modern_shell[] = SHELL;
-void config_set_option(const char *key, const char *value)
-{
- if (strcmp(key, "debug") == 0)
- debug = atoi(value);
-
- /* What path to use for filter programs and such
- *
- * Your printer driver must be in the path, as must be the renderer,
- * and possibly other stuff. The default path is often fine on Linux,
- * but may not be on other systems. */
- else if (strcmp(key, "execpath") == 0 && !isempty(value))
- setenv("PATH", value, 1);
-
- else if (strcmp(key, "cupsfilterpath") == 0)
- strlcpy(cupsfilterpath, value, PATH_MAX);
- else if (strcmp(key, "preferred_shell") == 0)
- strlcpy(modern_shell, value, 32);
- else if (strcmp(key, "gspath") == 0)
- strlcpy(gspath, value, PATH_MAX);
- else if (strcmp(key, "echo") == 0)
- strlcpy(echopath, value, PATH_MAX);
-}
-int config_from_file(const char *filename)
+void
+config_set_option(const char *key,
+ const char *value)
{
- FILE *fh;
- char line[256];
- char *key, *value;
+ if (strcmp(key, "debug") == 0)
+ debug = atoi(value);
+
+ // What path to use for filter programs and such
+ //
+ // Your printer driver must be in the path, as must be the renderer,
+ // and possibly other stuff. The default path is often fine on Linux,
+ // but may not be on other systems.
+ else if (strcmp(key, "execpath") == 0 && !isempty(value))
+ setenv("PATH", value, 1);
+ else if (strcmp(key, "cupsfilterpath") == 0)
+ strlcpy(cupsfilterpath, value, PATH_MAX);
+ else if (strcmp(key, "preferred_shell") == 0)
+ strlcpy(modern_shell, value, 32);
+ else if (strcmp(key, "gspath") == 0)
+ strlcpy(gspath, value, PATH_MAX);
+ else if (strcmp(key, "echo") == 0)
+ strlcpy(echopath, value, PATH_MAX);
+}
- fh = fopen(filename, "r");
- if (fh == NULL)
- return 0;
- while (fgets(line, 256, fh) != NULL)
- {
- key = strtok(line, " :\t\r\n");
- if (key == NULL || key[0] == '#')
- continue;
- value = strtok(NULL, " \t\r\n#");
- config_set_option(key, value);
- }
- fclose(fh);
-
- return 1;
+int
+config_from_file(const char *filename)
+{
+ FILE *fh;
+ char line[256];
+ char *key, *value;
+
+ fh = fopen(filename, "r");
+ if (fh == NULL)
+ return 0;
+
+ while (fgets(line, 256, fh) != NULL)
+ {
+ key = strtok(line, " :\t\r\n");
+ if (key == NULL || key[0] == '#')
+ continue;
+ value = strtok(NULL, " \t\r\n#");
+ config_set_option(key, value);
+ }
+ fclose(fh);
+
+ return (1);
}
-const char * get_modern_shell()
+
+const char *
+get_modern_shell()
{
- return modern_shell;
+ return (modern_shell);
}
-/* returns position in 'str' after the option */
-char * extract_next_option(char *str, char **pagerange, char **key, char **value)
-{
- char *p = str;
- char quotechar;
- *pagerange = NULL;
- *key = NULL;
- *value = NULL;
+// returns position in 'str' after the option
+char *
+extract_next_option(char *str,
+ char **pagerange,
+ char **key,
+ char **value)
+{
+ char *p = str;
+ char quotechar;
+
+ *pagerange = NULL;
+ *key = NULL;
+ *value = NULL;
+
+ if (!str)
+ return (NULL);
+
+ // skip whitespace
+ while (*p && isspace(*p))
+ p ++;
+
+ if (!*p)
+ return (NULL);
+
+ // read the pagerange if we have one
+ if (prefixcmp(p, "even:") == 0 || prefixcmp(p, "odd:") == 0 || isdigit(*p))
+ {
+ *pagerange = p;
+ p = strchr(p, ':');
+ if (!p)
+ return (NULL);
+ *p = '\0';
+ p++;
+ }
+
+ // read the key
+ if (*p == '\'' || *p == '\"')
+ {
+ quotechar = *p;
+ *key = p +1;
+ p = strchr(*key, quotechar);
+ if (!p)
+ return (NULL);
+ }
+ else
+ {
+ *key = p;
+ while (*p && *p != ':' && *p != '=' && !isspace(*p))
+ p ++;
+ }
+
+ if (*p != ':' && *p != '=')
+ { // no value for this option
+ if (!*p)
+ return NULL;
+ else if (isspace(*p)) {
+ *p = '\0';
+ return p +1;
+ }
+ return p;
+ }
+
+ *p++ = '\0'; // remove the separator char
+
+ if (*p == '\"' || *p == '\'')
+ {
+ quotechar = *p;
+ *value = p +1;
+ p = strchr(*value, quotechar);
+ if (!p)
+ return (NULL);
+ *p = '\0';
+ p++;
+ }
+ else
+ {
+ *value = p;
+ while (*p && !isspace(*p))
+ p ++;
+ if (*p == '\0')
+ return (NULL);
+ *p = '\0';
+ p++;
+ }
+
+ return *p ? p : NULL;
+}
- if (!str)
- return NULL;
- /* skip whitespace */
- while (*p && isspace(*p)) p++;
+// processes job->optstr
+void
+process_cmdline_options()
+{
+ char *p, *cmdlineopts, *nextopt, *pagerange, *key, *value;
+ option_t *opt, *opt2;
+ int optset;
+ char tmp [256];
+
+ _log("Printing system options:\n");
+ cmdlineopts = strdup(job->optstr->data);
+ for (nextopt = extract_next_option(cmdlineopts, &pagerange, &key, &value);
+ key;
+ nextopt = extract_next_option(nextopt, &pagerange, &key, &value))
+ {
+ // Consider only options which are not in the PPD file here
+ if ((opt = find_option(key)) != NULL)
+ continue;
+ if (value)
+ _log("Pondering option '%s=%s'\n", key, value);
+ else
+ _log("Pondering option '%s'\n", key);
- if (!*p)
- return NULL;
-
- /* read the pagerange if we have one */
- if (prefixcmp(p, "even:") == 0 || prefixcmp(p, "odd:") == 0 || isdigit(*p)) {
- *pagerange = p;
- p = strchr(p, ':');
- if (!p)
- return NULL;
- *p = '\0';
- p++;
+ // "profile" option to supply a color correction profile to a CUPS raster
+ // driver
+ if (!strcmp(key, "profile"))
+ {
+ strlcpy(colorprofile, value, 128);
+ continue;
}
-
- /* read the key */
- if (*p == '\'' || *p == '\"') {
- quotechar = *p;
- *key = p +1;
- p = strchr(*key, quotechar);
- if (!p)
- return NULL;
+ // option to set color calibration mode
+ if (!strcmp(key, "cm-calibration"))
+ {
+ cm_calibrate = 1;
+ continue;
}
- else {
- *key = p;
- while (*p && *p != ':' && *p != '=' && !isspace(*p)) p++;
+ // option to set color calibration mode
+ if (!strcmp(key, "filter-streaming-mode") &&
+ (!value ||
+ (strcasecmp(value, "false") && strcasecmp(value, "off") &&
+ strcasecmp(value, "no"))))
+ {
+ streaming = 1;
+ continue;
}
+ // Solaris options that have no reason to be
+ if (!strcmp(key, "nobanner") || !strcmp(key, "dest") ||
+ !strcmp(key, "protocol"))
+ continue;
- if (*p != ':' && *p != '=') { /* no value for this option */
- if (!*p)
- return NULL;
- else if (isspace(*p)) {
- *p = '\0';
- return p +1;
- }
- return p;
+ if (pagerange)
+ {
+ snprintf(tmp, 256, "pages:%s", pagerange);
+ optset = optionset(tmp);
}
+ else
+ optset = optionset("userval");
- *p++ = '\0'; /* remove the separator sign */
-
- if (*p == '\"' || *p == '\'') {
- quotechar = *p;
- *value = p +1;
- p = strchr(*value, quotechar);
- if (!p)
- return NULL;
- *p = '\0';
- p++;
- }
- else {
- *value = p;
- while (*p && !isspace(*p)) p++;
- if (*p == '\0')
- return NULL;
- *p = '\0';
- p++;
- }
+ if (value)
+ {
+ if (strcasecmp(key, "media") == 0)
+ {
+ // Standard arguments?
+ // media=x,y,z
+ // sides=one|two-sided-long|short-edge
+ //
+ // Rummage around in the media= option for known media, source,
+ // etc types.
+ // We ought to do something sensible to make the common manual
+ // boolean option work when specified as a media= tray thing.
+ //
+ // Note that this fails miserably when the option value is in
+ // fact a number; they all look alike. It's unclear how many
+ // drivers do that. We may have to standardize the verbose
+ // names to make them work as selections, too.
+
+ if (value[0] == '\0')
+ continue;
+ p = strtok(value, ",");
+ do
+ {
+ if ((opt = find_option("PageSize")) && option_accepts_value(opt, p))
+ option_set_value(opt, optset, p);
+ else if ((opt = find_option("MediaType")) &&
+ option_has_choice(opt, p))
+ option_set_value(opt, optset, p);
+ else if ((opt = find_option("InputSlot")) &&
+ option_has_choice(opt, p))
+ option_set_value(opt, optset, p);
+ else if (!strcasecmp(p, "manualfeed"))
+ {
+ // Special case for our typical boolean manual
+ // feeder option if we didn't match an InputSlot above
+ if ((opt = find_option("ManualFeed")))
+ option_set_value(opt, optset, "1");
+ }
+ else
+ _log("Unknown \"media\" component: \"%s\".\n", p);
- return *p ? p : NULL;
-}
+ }
+ while ((p = strtok(NULL, ",")));
+ }
+ else if (!strcasecmp(key, "sides"))
+ {
+ // Handle the standard duplex option, mostly
+ if (!prefixcasecmp(value, "two-sided"))
+ {
+ if ((opt = find_option("Duplex")))
+ {
+ // Default to long-edge binding here, for the case that
+ // there is no binding setting
+ option_set_value(opt, optset, "DuplexNoTumble");
+
+ // Check the binding: "long edge" or "short edge"
+ if (strcasestr(value, "long-edge"))
+ {
+ if ((opt2 = find_option("Binding")))
+ option_set_value(opt2, optset, "LongEdge");
+ else
+ option_set_value(opt, optset, "DuplexNoTumble");
+ }
+ else if (strcasestr(value, "short-edge"))
+ {
+ if ((opt2 = find_option("Binding")))
+ option_set_value(opt2, optset, "ShortEdge");
+ else
+ option_set_value(opt, optset, "DuplexTumble");
+ }
+ }
+ }
+ else if (!prefixcasecmp(value, "one-sided"))
+ {
+ if ((opt = find_option("Duplex")))
+ option_set_value(opt, optset, "0");
+ }
-/* processes job->optstr */
-void process_cmdline_options()
-{
- char *p, *cmdlineopts, *nextopt, *pagerange, *key, *value;
- option_t *opt, *opt2;
- int optset;
- char tmp [256];
-
- _log("Printing system options:\n");
- cmdlineopts = strdup(job->optstr->data);
- for (nextopt = extract_next_option(cmdlineopts, &pagerange, &key, &value);
- key;
- nextopt = extract_next_option(nextopt, &pagerange, &key, &value))
+ // TODO
+ // We should handle the other half of this option - the
+ // BindEdge bit. Also, are there well-known ipp/cups options
+ // for Collate and StapleLocation? These may be here...
+ }
+ else
+ _log("Unknown option %s=%s.\n", key, value);
+ }
+ // Custom paper size
+ else if ((opt = find_option("PageSize")) &&
+ option_set_value(opt, optset, key))
{
- /* Consider only options which are not in the PPD file here */
- if ((opt = find_option(key)) != NULL) continue;
- if (value)
- _log("Pondering option '%s=%s'\n", key, value);
- else
- _log("Pondering option '%s'\n", key);
-
- /* "profile" option to supply a color correction profile to a CUPS raster driver */
- if (!strcmp(key, "profile")) {
- strlcpy(colorprofile, value, 128);
- continue;
- }
- /* option to set color calibration mode */
- if (!strcmp(key, "cm-calibration")) {
- cm_calibrate = 1;
- continue;
- }
- /* option to set color calibration mode */
- if (!strcmp(key, "filter-streaming-mode") &&
- (!value ||
- (strcasecmp(value, "false") && strcasecmp(value, "off") &&
- strcasecmp(value, "no")))) {
- streaming = 1;
- continue;
- }
- /* Solaris options that have no reason to be */
- if (!strcmp(key, "nobanner") || !strcmp(key, "dest") || !strcmp(key, "protocol"))
- continue;
-
- if (pagerange) {
- snprintf(tmp, 256, "pages:%s", pagerange);
- optset = optionset(tmp);
- }
- else
- optset = optionset("userval");
-
- if (value) {
- if (strcasecmp(key, "media") == 0) {
- /* Standard arguments?
- media=x,y,z
- sides=one|two-sided-long|short-edge
-
- Rummage around in the media= option for known media, source,
- etc types.
- We ought to do something sensible to make the common manual
- boolean option work when specified as a media= tray thing.
-
- Note that this fails miserably when the option value is in
- fact a number; they all look alike. It's unclear how many
- drivers do that. We may have to standardize the verbose
- names to make them work as selections, too. */
-
- if (value[0] == '\0')
- continue;
- p = strtok(value, ",");
- do {
- if ((opt = find_option("PageSize")) && option_accepts_value(opt, p))
- option_set_value(opt, optset, p);
- else if ((opt = find_option("MediaType")) && option_has_choice(opt, p))
- option_set_value(opt, optset, p);
- else if ((opt = find_option("InputSlot")) && option_has_choice(opt, p))
- option_set_value(opt, optset, p);
- else if (!strcasecmp(p, "manualfeed")) {
- /* Special case for our typical boolean manual
- feeder option if we didn't match an InputSlot above */
- if ((opt = find_option("ManualFeed")))
- option_set_value(opt, optset, "1");
- }
- else
- _log("Unknown \"media\" component: \"%s\".\n", p);
-
- } while ((p = strtok(NULL, ",")));
- }
- else if (!strcasecmp(key, "sides")) {
- /* Handle the standard duplex option, mostly */
- if (!prefixcasecmp(value, "two-sided")) {
- if ((opt = find_option("Duplex"))) {
- /* Default to long-edge binding here, for the case that
- there is no binding setting */
- option_set_value(opt, optset, "DuplexNoTumble");
-
- /* Check the binding: "long edge" or "short edge" */
- if (strcasestr(value, "long-edge")) {
- if ((opt2 = find_option("Binding")))
- option_set_value(opt2, optset, "LongEdge");
- else
- option_set_value(opt, optset, "DuplexNoTumble");
- }
- else if (strcasestr(value, "short-edge")) {
- if ((opt2 = find_option("Binding")))
- option_set_value(opt2, optset, "ShortEdge");
- else
- option_set_value(opt, optset, "DuplexTumble");
- }
- }
- }
- else if (!prefixcasecmp(value, "one-sided")) {
- if ((opt = find_option("Duplex")))
- option_set_value(opt, optset, "0");
- }
-
- /* TODO
- We should handle the other half of this option - the
- BindEdge bit. Also, are there well-known ipp/cups options
- for Collate and StapleLocation? These may be here...
- */
- }
- else
- _log("Unknown option %s=%s.\n", key, value);
- }
- /* Custom paper size */
- else if ((opt = find_option("PageSize")) && option_set_value(opt, optset, key)) {
- /* do nothing, if the value could be set, it has been set */
- }
- else
- _log("Unknown boolean option \"%s\".\n", key);
+ // do nothing, if the value could be set, it has been set
}
- free(cmdlineopts);
+ else
+ _log("Unknown boolean option \"%s\".\n", key);
+ }
+ free(cmdlineopts);
+
+ // We 'clear' the profile if cm-calibration mode was specified
+ if (cm_calibrate)
+ {
+ colorprofile[0] = '\0';
+ cm_disabled = 1;
+ }
+
+ _log("Streaming Mode: %s\n", streaming ? "Activated" : "Off");
+ _log("CM Color Calibration Mode in CUPS: %s\n", cm_calibrate ?
+ "Activated" : "Off");
+
+ _log("Options from the PPD file:\n");
+ cmdlineopts = strdup(job->optstr->data);
+ for (nextopt = extract_next_option(cmdlineopts, &pagerange, &key, &value);
+ key;
+ nextopt = extract_next_option(nextopt, &pagerange, &key, &value))
+ {
+ // Consider only PPD file options here
+ if ((opt = find_option(key)) == NULL) continue;
+ if (value)
+ _log("Pondering option '%s=%s'\n", key, value);
+ else
+ _log("Pondering option '%s'\n", key);
- /* We 'clear' the profile if cm-calibration mode was specified */
- if (cm_calibrate) {
- colorprofile[0] = '\0';
- cm_disabled = 1;
+ if (pagerange)
+ {
+ snprintf(tmp, 256, "pages:%s", pagerange);
+ optset = optionset(tmp);
+
+ if (opt && (option_get_section(opt) != SECTION_ANYSETUP &&
+ option_get_section(opt) != SECTION_PAGESETUP))
+ {
+ _log("This option (%s) is not a \"PageSetup\" or \"AnySetup\" option, so it cannot be restricted to a page range.\n", key);
+ continue;
+ }
}
+ else
+ optset = optionset("userval");
- _log("Streaming Mode: %s\n", streaming ? "Activated" : "Off");
- _log("CM Color Calibration Mode in CUPS: %s\n", cm_calibrate ?
- "Activated" : "Off");
-
- _log("Options from the PPD file:\n");
- cmdlineopts = strdup(job->optstr->data);
- for (nextopt = extract_next_option(cmdlineopts, &pagerange, &key, &value);
- key;
- nextopt = extract_next_option(nextopt, &pagerange, &key, &value))
+ if (value)
{
- /* Consider only PPD file options here */
- if ((opt = find_option(key)) == NULL) continue;
- if (value)
- _log("Pondering option '%s=%s'\n", key, value);
- else
- _log("Pondering option '%s'\n", key);
-
- if (pagerange) {
- snprintf(tmp, 256, "pages:%s", pagerange);
- optset = optionset(tmp);
-
- if (opt && (option_get_section(opt) != SECTION_ANYSETUP &&
- option_get_section(opt) != SECTION_PAGESETUP)) {
- _log("This option (%s) is not a \"PageSetup\" or \"AnySetup\" option, so it cannot be restricted to a page range.\n", key);
- continue;
- }
- }
- else
- optset = optionset("userval");
-
- if (value) {
- /* Various non-standard printer-specific options */
- if (!option_set_value(opt, optset, value)) {
- _log(" invalid choice \"%s\", using \"%s\" instead\n",
- value, option_get_value(opt, optset));
- }
- }
- /* Standard bool args:
- landscape; what to do here?
- duplex; we should just handle this one OK now? */
- else if (!prefixcasecmp(key, "no"))
- option_set_value(opt, optset, "0");
- else
- option_set_value(opt, optset, "1");
+ // Various non-standard printer-specific options
+ if (!option_set_value(opt, optset, value)) {
+ _log(" invalid choice \"%s\", using \"%s\" instead\n",
+ value, option_get_value(opt, optset));
+ }
}
- free(cmdlineopts);
+ // Standard bool args:
+ // landscape; what to do here?
+ // duplex; we should just handle this one OK now?
+ else if (!prefixcasecmp(key, "no"))
+ option_set_value(opt, optset, "0");
+ else
+ option_set_value(opt, optset, "1");
+ }
+ free(cmdlineopts);
}
-/* Functions to let foomatic-rip fork to do several tasks in parallel.
-
-To do the filtering without loading the whole file into memory we work
-on a data stream, we read the data line by line analyse it to decide what
-filters to use and start the filters if we have found out which we need.
-We buffer the data only as long as we didn't determing which filters to
-use for this piece of data and with which options. There are no temporary
-files used.
-foomatic-rip splits into up to 3 parallel processes to do the whole
-filtering (listed in the order of the data flow):
+//
+// Functions to let foomatic-rip fork to do several tasks in parallel.
+//
+// To do the filtering without loading the whole file into memory we work
+// on a data stream, we read the data line by line analyse it to decide what
+// filters to use and start the filters if we have found out which we need.
+// We buffer the data only as long as we didn't determing which filters to
+// use for this piece of data and with which options. There are no temporary
+// files used.
+//
+// foomatic-rip splits into up to 3 parallel processes to do the whole
+// filtering (listed in the order of the data flow):
+//
+// MAIN: Prepare the job auto-detecting the spooler, reading the PPD,
+// extracting the options from the command line, and parsing
+// the job data itself. It analyses the job data to check
+// whether it is PostScript or PDF, it also stuffs PostScript
+// code from option settings into the PostScript data stream.
+// It starts the renderer (KID3/KID4) as soon as it knows its
+// command line and restarts it when page-specific option
+// settings need another command line or different JCL commands.
+// KID3: The rendering process. In most cases Ghostscript, "cat"
+// for native PostScript printers with their manufacturer's
+// PPD files.
+// KID4: Put together the JCL commands and the renderer's output
+// and send all that either to STDOUT or pipe it into the
+// command line defined with $postpipe.
+//
+
+
+void
+write_output(void *data,
+ size_t len)
+{
+ const char *p = (const char *)data;
+ size_t left = len;
+ FILE *postpipe = open_postpipe();
- MAIN: Prepare the job auto-detecting the spooler, reading the PPD,
- extracting the options from the command line, and parsing
- the job data itself. It analyses the job data to check
- whether it is PostScript or PDF, it also stuffs PostScript
- code from option settings into the PostScript data stream.
- It starts the renderer (KID3/KID4) as soon as it knows its
- command line and restarts it when page-specific option
- settings need another command line or different JCL commands.
- KID3: The rendering process. In most cases Ghostscript, "cat"
- for native PostScript printers with their manufacturer's
- PPD files.
- KID4: Put together the JCL commands and the renderer's output
- and send all that either to STDOUT or pipe it into the
- command line defined with $postpipe. */
+ // Remove leading whitespace
+ while (isspace(*p++) && left-- > 0);
+ fwrite_or_die((void *)p, left, 1, postpipe);
+ fflush(postpipe);
+}
-void write_output(void *data, size_t len)
+enum FileType
{
- const char *p = (const char *)data;
- size_t left = len;
- FILE *postpipe = open_postpipe();
+ UNKNOWN_FILE,
+ PDF_FILE,
+ PS_FILE
+};
- /* Remove leading whitespace */
- while (isspace(*p++) && left-- > 0)
- ;
- fwrite_or_die((void *)p, left, 1, postpipe);
- fflush(postpipe);
+int
+guess_file_type(const char *begin,
+ size_t len,
+ int *startpos)
+{
+ const char *p, *end;
+
+ p = begin;
+ end = begin + len;
+
+ while (p < end)
+ {
+ p = memchr(p, '%', end - p);
+ if (!p)
+ return UNKNOWN_FILE;
+ *startpos = p - begin;
+ if ((end - p) >= 2 && !memcmp(p, "%!", 2))
+ return PS_FILE;
+ else if ((end - p) > 7 && !memcmp(p, "%PDF-1.", 7))
+ return PDF_FILE;
+ ++ p;
+ }
+ *startpos = 0;
+ return UNKNOWN_FILE;
}
-enum FileType {
- UNKNOWN_FILE,
- PDF_FILE,
- PS_FILE
-};
-int guess_file_type(const char *begin, size_t len, int *startpos)
-{
- const char * p, * end;
- p = begin;
- end = begin + len;
+//
+// Prints 'filename'. If 'convert' is true, the file will be converted if it is
+// not Postscript or PDF
+//
- while (p < end)
+int
+print_file(const char *filename,
+ int convert)
+{
+ FILE *file;
+ char buf[8192];
+ char tmpfilename[PATH_MAX] = "";
+ int type;
+ int startpos;
+ size_t n;
+ int ret;
+
+ if (!strcasecmp(filename, "<STDIN>"))
+ file = stdin;
+ else
+ {
+ file = fopen(filename, "r");
+ if (!file)
{
- p = memchr(p, '%', end - p);
- if (!p)
- return UNKNOWN_FILE;
- *startpos = p - begin;
- if ((end - p) >= 2 && !memcmp(p, "%!", 2))
- return PS_FILE;
- else if ((end - p) > 7 && !memcmp(p, "%PDF-1.", 7))
- return PDF_FILE;
- ++ p;
+ _log("Could not open \"%s\" for reading\n", filename);
+ return (0);
}
- *startpos = 0;
- return UNKNOWN_FILE;
-}
-
-/*
- * Prints 'filename'. If 'convert' is true, the file will be converted if it is
- * not postscript or pdf
- */
-int print_file(const char *filename, int convert)
-{
- FILE *file;
- char buf[8192];
- char tmpfilename[PATH_MAX] = "";
- int type;
- int startpos;
- size_t n;
- int ret;
-
- if (!strcasecmp(filename, "<STDIN>"))
- file = stdin;
- else {
- file = fopen(filename, "r");
- if (!file) {
- _log("Could not open \"%s\" for reading\n", filename);
- return 0;
- }
+ }
+
+ if (streaming == 0 || file != stdin)
+ {
+ n = fread_or_die(buf, 1, sizeof(buf) - 1, file);
+ if (!n) {
+ _log("Input is empty, outputting empty file.\n");
+ return (1);
}
+ buf[n] = '\0';
+ type = guess_file_type(buf, n, &startpos);
+ // We do not use any JCL preceeded to the input data, as it is simply
+ // the PJL commands from the PPD file, and these commands we can also
+ // generate, end we even merge them with PJl from the driver
+ //if (startpos > 0)
+ //{
+ // jobhasjcl = 1;
+ // write_output(buf, startpos);
+ //}
+ if (file != stdin)
+ rewind(file);
+
+ if (convert) pdfconvertedtops = 0;
+ }
+ else
+ {
+ n = 0;
+ buf[0] = '\n';
+ type = PS_FILE;
+ }
+
+ switch (type)
+ {
+ case PDF_FILE:
+ _log("Filetype: PDF\n");
+
+ if (!ppd_supports_pdf())
+ {
+ char pdf2ps_cmd[CMDLINE_MAX];
+ FILE *out, *in;
+ int renderer_pid;
+
+ _log("Driver does not understand PDF input, "
+ "converting to PostScript\n");
+
+ pdfconvertedtops = 1;
+
+ // If reading from stdin, write everything into a temporary file
+ if (file == stdin)
+ {
+ int fd;
+ FILE *tmpfile;
+
+ snprintf(tmpfilename, PATH_MAX, "%s/foomatic-XXXXXX", temp_dir());
+ fd = mkstemp(tmpfilename);
+ if (fd < 0)
+ {
+ _log("Could not create temporary file: %s\n", strerror(errno));
+ return (EXIT_PRNERR_NORETRY_BAD_SETTINGS);
+ }
+ tmpfile = fdopen(fd, "r+");
+ copy_file(tmpfile, stdin, buf, n);
+ fclose(tmpfile);
+
+ filename = tmpfilename;
+ }
+
+ // If the spooler is CUPS we use the pdftops filter of CUPS,
+ // to have always the same PDF->PostScript conversion method
+ // in the whole printing environment, including incompatibility
+ // workarounds in the CUPS filter (so this way we also have to
+ // maintain all these quirks only once).
+ //
+ // The "-dNOINTERPOLATE" makes Ghostscript rendering
+ // significantly faster.
+ //
+ // The "-dNOMEDIAATTRS" makes Ghostscript not checking the
+ // page sizes against a list of known sizes and try to
+ // correct them.
+ //
+ // Note that Ghostscript's "pswrite" output device turns text
+ // into bitmaps and therefore produces huge PostScript files.
+ // In addition, this output device is deprecated. Therefore
+ // we use "ps2write".
+ //
+ // We give priority to Ghostscript here and use Poppler if
+ // Ghostscript is not available.
+ if (spooler == SPOOLER_CUPS)
+ snprintf(pdf2ps_cmd, CMDLINE_MAX,
+ "pdftops '%s' '%s' '%s' '%s' '%s' '%s'",
+ job->id, job->user, job->title, "1", job->optstr->data,
+ filename);
+ else
+ snprintf(pdf2ps_cmd, CMDLINE_MAX,
+ "gs -q -sstdout=%%stderr -sDEVICE=ps2write -sOutputFile=- "
+ "-dBATCH -dNOPAUSE -dSAFER -dNOINTERPOLATE -dNOMEDIAATTRS -dShowAcroForm %s 2>/dev/null || "
+ "pdftops -level2 -origpagesizes %s - 2>/dev/null",
+ filename, filename);
+
+ renderer_pid = start_system_process("pdf-to-ps", pdf2ps_cmd, &in, &out);
+
+ if (dup2(fileno(out), fileno(stdin)) < 0)
+ rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
+ "Couldn't dup stdout of pdf-to-ps\n");
+
+ clearerr(stdin);
+
+ ret = print_file("<STDIN>", 0);
+
+ wait_for_process(renderer_pid);
+ if (in != NULL)
+ fclose(in);
+ if (out != NULL)
+ fclose(out);
+
+ // Delete temp file if we created one
+ if ( *tmpfilename )
+ unlink(tmpfilename);
+
+ return ret;
+ }
- if (streaming == 0 || file != stdin) {
- n = fread_or_die(buf, 1, sizeof(buf) - 1, file);
- if (!n) {
- _log("Input is empty, outputting empty file.\n");
- return 1;
- }
- buf[n] = '\0';
- type = guess_file_type(buf, n, &startpos);
- /* We do not use any JCL preceeded to the input data, as it is simply
- the PJL commands from the PPD file, and these commands we can also
- generate, end we even merge them with PJl from the driver */
- /*if (startpos > 0) {
- jobhasjcl = 1;
- write_output(buf, startpos);
- }*/
- if (file != stdin)
- rewind(file);
-
- if (convert) pdfconvertedtops = 0;
- } else {
- n = 0;
- buf[0] = '\n';
- type = PS_FILE;
- }
+ if (file == stdin)
+ return (print_pdf(stdin, buf, n, filename, startpos));
+ else
+ return (print_pdf(file, NULL, 0, filename, startpos));
- switch (type) {
- case PDF_FILE:
- _log("Filetype: PDF\n");
-
- if (!ppd_supports_pdf())
- {
- char pdf2ps_cmd[CMDLINE_MAX];
- FILE *out, *in;
- int renderer_pid;
-
- _log("Driver does not understand PDF input, "
- "converting to PostScript\n");
-
- pdfconvertedtops = 1;
-
- /* If reading from stdin, write everything into a temporary file */
- if (file == stdin)
- {
- int fd;
- FILE *tmpfile;
-
- snprintf(tmpfilename, PATH_MAX, "%s/foomatic-XXXXXX", temp_dir());
- fd = mkstemp(tmpfilename);
- if (fd < 0) {
- _log("Could not create temporary file: %s\n", strerror(errno));
- return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
- }
- tmpfile = fdopen(fd, "r+");
- copy_file(tmpfile, stdin, buf, n);
- fclose(tmpfile);
-
- filename = tmpfilename;
- }
-
- /* If the spooler is CUPS we use the pdftops filter of CUPS,
- to have always the same PDF->PostScript conversion method
- in the whole printing environment, including incompatibility
- workarounds in the CUPS filter (so this way we also have to
- maintain all these quirks only once).
-
- The "-dNOINTERPOLATE" makes Ghostscript rendering
- significantly faster.
-
- The "-dNOMEDIAATTRS" makes Ghostscript not checking the
- page sizes against a list of known sizes and try to
- correct them.
-
- Note that Ghostscript's "pswrite" output device turns text
- into bitmaps and therefore produces huge PostScript files.
- In addition, this output device is deprecated. Therefore
- we use "ps2write".
-
- We give priority to Ghostscript here and use Poppler if
- Ghostscript is not available. */
- if (spooler == SPOOLER_CUPS)
- snprintf(pdf2ps_cmd, CMDLINE_MAX,
- "pdftops '%s' '%s' '%s' '%s' '%s' '%s'",
- job->id, job->user, job->title, "1", job->optstr->data,
- filename);
- else
- snprintf(pdf2ps_cmd, CMDLINE_MAX,
- "gs -q -sstdout=%%stderr -sDEVICE=ps2write -sOutputFile=- "
- "-dBATCH -dNOPAUSE -dSAFER -dNOINTERPOLATE -dNOMEDIAATTRS -dShowAcroForm %s 2>/dev/null || "
- "pdftops -level2 -origpagesizes %s - 2>/dev/null",
- filename, filename);
-
- renderer_pid = start_system_process("pdf-to-ps", pdf2ps_cmd, &in, &out);
-
- if (dup2(fileno(out), fileno(stdin)) < 0)
- rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
- "Couldn't dup stdout of pdf-to-ps\n");
-
- clearerr(stdin);
-
- ret = print_file("<STDIN>", 0);
-
- wait_for_process(renderer_pid);
- if (in != NULL)
- fclose(in);
- if (out != NULL)
- fclose(out);
-
- // Delete temp file if we created one
- if ( *tmpfilename )
- unlink(tmpfilename);
-
- return ret;
- }
-
- if (file == stdin)
- return print_pdf(stdin, buf, n, filename, startpos);
- else
- return print_pdf(file, NULL, 0, filename, startpos);
-
- case PS_FILE:
- _log("Filetype: PostScript\n");
- if (file == stdin)
- return print_ps(stdin, buf, n, filename);
- else
- return print_ps(file, NULL, 0, filename);
-
- case UNKNOWN_FILE:
- _log("Cannot process \"%s\": Unknown filetype.\n", filename);
- if (file != NULL)
- fclose(file);
- return 0;
- }
+ case PS_FILE:
+ _log("Filetype: PostScript\n");
+ if (file == stdin)
+ return (print_ps(stdin, buf, n, filename));
+ else
+ return (print_ps(file, NULL, 0, filename));
- fclose(file);
- return 1;
-}
+ case UNKNOWN_FILE:
+ _log("Cannot process \"%s\": Unknown filetype.\n", filename);
+ if (file != NULL)
+ fclose(file);
+ return (0);
+ }
-void signal_terminate(int signal)
-{
- rip_die(EXIT_PRINTED, "Caught termination signal: Job canceled\n");
+ fclose(file);
+ return (1);
}
-jobparams_t * create_job()
-{
- jobparams_t *job = calloc(1, sizeof(jobparams_t));
- struct passwd *passwd;
-
- job->optstr = create_dstr();
- job->time = time(NULL);
- strcpy(job->copies, "1");
- gethostname(job->host, 128);
- passwd = getpwuid(getuid());
- if (passwd)
- strlcpy(job->user, passwd->pw_name, 128);
- snprintf(job->title, 2048, "%s@%s", job->user, job->host);
-
- return job;
-}
-void free_job(jobparams_t *job)
+void
+signal_terminate(int signal)
{
- free_dstr(job->optstr);
- free(job);
+ rip_die(EXIT_PRINTED, "Caught termination signal: Job canceled\n");
}
-int main(int argc, char** argv)
-{
- int i;
- int verbose = 0, quiet = 0;
- const char* str;
- char *p, *filename;
- const char *path;
- char tmp[1024], profile_arg[256], gstoraster[512];
- int havefilter, havegstoraster;
- dstr_t *filelist;
- list_t * arglist;
- cf_filter_data_t temp;
- cf_filter_data_t *data = &temp;
- data->logdata = NULL;
- data->logfunc = cfCUPSLogFunc;
- arglist = list_create_from_array(argc -1, (void**)&argv[1]);
-
- if (argc == 2 && (arglist_find(arglist, "--version") || arglist_find(arglist, "--help") ||
- arglist_find(arglist, "-v") || arglist_find(arglist, "-h"))) {
- printf("foomatic-rip of cups-filters version "VERSION"\n");
- printf("\"man foomatic-rip\" for help.\n");
- list_free(arglist);
- return 0;
- }
- filelist = create_dstr();
- job = create_job();
+jobparams_t *
+create_job()
+{
+ jobparams_t *job = calloc(1, sizeof(jobparams_t));
+ struct passwd *passwd;
+
+ job->optstr = create_dstr();
+ job->time = time(NULL);
+ strcpy(job->copies, "1");
+ gethostname(job->host, 128);
+ passwd = getpwuid(getuid());
+ if (passwd)
+ strlcpy(job->user, passwd->pw_name, 128);
+ snprintf(job->title, 2048, "%s@%s", job->user, job->host);
+
+ return (job);
+}
- jclprepend = NULL;
- jclappend = create_dstr();
- postpipe = create_dstr();
- options_init();
+void
+free_job(jobparams_t *job)
+{
+ free_dstr(job->optstr);
+ free(job);
+}
- signal(SIGTERM, signal_terminate);
- signal(SIGINT, signal_terminate);
- signal(SIGPIPE, SIG_IGN);
- /* First try to find a config file in the CUS config directory, like
- /etc/cups/foomatic-rip.conf */
- i = 0;
- if ((str = getenv("CUPS_SERVERROOT")) != NULL) {
- snprintf(tmp, sizeof(tmp), "%s/foomatic-rip.conf", str);
- i = config_from_file(tmp);
- }
- /* If there is none, fall back to /etc/foomatic/filter.conf */
- if (i == 0)
- i = config_from_file(CONFIG_PATH "/filter.conf");
-
- /* Command line options for verbosity */
- if (arglist_remove_flag(arglist, "-v"))
- verbose = 1;
- if (arglist_remove_flag(arglist, "-q"))
- quiet = 1;
- if (arglist_remove_flag(arglist, "--debug"))
- debug = 1;
-
- if (debug) {
+int
+main(int argc,
+ char** argv)
+{
+ int i;
+ int verbose = 0, quiet = 0;
+ const char* str;
+ char *p, *filename;
+ const char *path;
+ char tmp[1024], profile_arg[256], gstoraster[512];
+ int havefilter, havegstoraster;
+ dstr_t *filelist;
+ list_t * arglist;
+ cf_filter_data_t temp;
+ cf_filter_data_t *data = &temp;
+ data->logdata = NULL;
+ data->logfunc = cfCUPSLogFunc;
+ arglist = list_create_from_array(argc -1, (void**)&argv[1]);
+
+ if (argc == 2 && (arglist_find(arglist, "--version") ||
+ arglist_find(arglist, "--help") ||
+ arglist_find(arglist, "-v") ||
+ arglist_find(arglist, "-h")))
+ {
+ printf("foomatic-rip of cups-filters version "VERSION"\n");
+ printf("\"man foomatic-rip\" for help.\n");
+ list_free(arglist);
+ return (0);
+ }
+
+ filelist = create_dstr();
+ job = create_job();
+
+ jclprepend = NULL;
+ jclappend = create_dstr();
+ postpipe = create_dstr();
+
+ options_init();
+
+ signal(SIGTERM, signal_terminate);
+ signal(SIGINT, signal_terminate);
+ signal(SIGPIPE, SIG_IGN);
+
+ // First try to find a config file in the CUPS config directory, like
+ // /etc/cups/foomatic-rip.conf
+ i = 0;
+ if ((str = getenv("CUPS_SERVERROOT")) != NULL)
+ {
+ snprintf(tmp, sizeof(tmp), "%s/foomatic-rip.conf", str);
+ i = config_from_file(tmp);
+ }
+ // If there is none, fall back to /etc/foomatic/filter.conf
+ if (i == 0)
+ i = config_from_file(CONFIG_PATH "/filter.conf");
+
+ // Command line options for verbosity
+ if (arglist_remove_flag(arglist, "-v"))
+ verbose = 1;
+ if (arglist_remove_flag(arglist, "-q"))
+ quiet = 1;
+ if (arglist_remove_flag(arglist, "--debug"))
+ debug = 1;
+
+ if (debug)
+ {
#if defined(__UCLIBC__) || defined(__NetBSD__)
- sprintf(tmp, "%s-log-XXXXXX", LOG_FILE);
- int fd = mkstemp (tmp);
+ sprintf(tmp, "%s-log-XXXXXX", LOG_FILE);
+ int fd = mkstemp (tmp);
#else
- sprintf(tmp, "%s-XXXXXX.log", LOG_FILE);
- int fd = mkstemps (tmp, 4);
+ sprintf(tmp, "%s-XXXXXX.log", LOG_FILE);
+ int fd = mkstemps (tmp, 4);
#endif
- if (fd != -1)
- logh = fdopen(fd, "w");
- else
- logh = stderr;
- } else if (quiet && !verbose)
- logh = NULL; /* Quiet mode, do not log */
+ if (fd != -1)
+ logh = fdopen(fd, "w");
else
- logh = stderr; /* Default: log to stderr */
-
- /* Start debug logging */
- if (debug) {
- /* If we are not in debug mode, we do this later, as we must find out at
- first which spooler is used. When printing without spooler we
- suppress logging because foomatic-rip is called directly on the
- command line and so we avoid logging onto the console. */
- _log("foomatic-rip version "VERSION" running...\n");
-
- /* Print the command line only in debug mode, Mac OS X adds very many
- options so that CUPS cannot handle the output of the command line
- in its log files. If CUPS encounters a line with more than 1024
- characters sent into its log files, it aborts the job with an error. */
- if (spooler != SPOOLER_CUPS) {
- _log("called with arguments: ");
- for (i = 1; i < argc -1; i++)
- _log("\'%s\', ", argv[i]);
- _log("\'%s\'\n", argv[i]);
- }
+ logh = stderr;
+ }
+ else if (quiet && !verbose)
+ logh = NULL; // Quiet mode, do not log
+ else
+ logh = stderr; // Default: log to stderr
+
+ // Start debug logging
+ if (debug)
+ {
+ // If we are not in debug mode, we do this later, as we must find out at
+ // first which spooler is used. When printing without spooler we
+ // suppress logging because foomatic-rip is called directly on the
+ // command line and so we avoid logging onto the console.
+ // _log("foomatic-rip version "VERSION" running...\n");
+
+ // Print the command line only in debug mode, Mac OS X adds very many
+ // options so that CUPS cannot handle the output of the command line
+ // in its log files. If CUPS encounters a line with more than 1024
+ // characters sent into its log files, it aborts the job with an error.
+ if (spooler != SPOOLER_CUPS)
+ {
+ _log("called with arguments: ");
+ for (i = 1; i < argc -1; i++)
+ _log("\'%s\', ", argv[i]);
+ _log("\'%s\'\n", argv[i]);
}
-
- if (getenv("PPD")) {
- strncpy(job->ppdfile, getenv("PPD"), sizeof(job->ppdfile) - 1);
- if (strlen(getenv("PPD")) > 2047)
- job->ppdfile[2047] = '\0';
- spooler = SPOOLER_CUPS;
- strncpy_omit(job->printer, getenv("PRINTER"), 256, omit_shellescapes);
- if (getenv("CUPS_SERVERBIN")) {
- strncpy(cupsfilterpath, getenv("CUPS_SERVERBIN"),
- sizeof(cupsfilterpath) - 1);
- if (strlen(getenv("CUPS_SERVERBIN")) > PATH_MAX-1)
- cupsfilterpath[PATH_MAX-1] = '\0';
- }
+ }
+
+ if (getenv("PPD"))
+ {
+ strncpy(job->ppdfile, getenv("PPD"), sizeof(job->ppdfile) - 1);
+ if (strlen(getenv("PPD")) > 2047)
+ job->ppdfile[2047] = '\0';
+ spooler = SPOOLER_CUPS;
+ strncpy_omit(job->printer, getenv("PRINTER"), 256, omit_shellescapes);
+ if (getenv("CUPS_SERVERBIN"))
+ {
+ strncpy(cupsfilterpath, getenv("CUPS_SERVERBIN"),
+ sizeof(cupsfilterpath) - 1);
+ if (strlen(getenv("CUPS_SERVERBIN")) > PATH_MAX-1)
+ cupsfilterpath[PATH_MAX-1] = '\0';
}
-
- /* CUPS calls foomatic-rip only with 5 or 6 positional parameters,
- not with named options, like for example "-p <string>". */
- if (spooler != SPOOLER_CUPS) {
-
- if ((str = arglist_get_value(arglist, "-j")) || (str = arglist_get_value(arglist, "-J"))) {
- strncpy_omit(job->title, str, 2048, omit_shellescapes);
- if (!arglist_remove(arglist, "-j"))
- arglist_remove(arglist, "-J");
- }
-
- /* PPD file name given via the command line
- allow duplicates, and use the last specified one */
- while ((str = arglist_get_value(arglist, "-p"))) {
- strncpy(job->ppdfile, str, sizeof(job->ppdfile) - 1);
- if (strlen(str) > 2047)
- job->ppdfile[2047] = '\0';
- arglist_remove(arglist, "-p");
- }
- while ((str = arglist_get_value(arglist, "--ppd"))) {
- strncpy(job->ppdfile, str, sizeof(job->ppdfile) - 1);
- if (strlen(str) > 2047)
- job->ppdfile[2047] = '\0';
- arglist_remove(arglist, "--ppd");
- }
-
- /* Options for spooler-less printing */
- while ((str = arglist_get_value(arglist, "-o"))) {
- strncpy_omit(tmp, str, 1024, omit_shellescapes);
- dstrcatf(job->optstr, "%s ", tmp);
- /* if "-o cm-calibration" was passed, we raise a flag */
- if (!strcmp(tmp, "cm-calibration")) {
- cm_calibrate = 1;
- cm_disabled = 1;
- }
- arglist_remove(arglist, "-o");
- /* We print without spooler */
- spooler = SPOOLER_DIRECT;
- }
-
- /* Printer for spooler-less printing */
- if ((str = arglist_get_value(arglist, "-d"))) {
- strncpy_omit(job->printer, str, 256, omit_shellescapes);
- arglist_remove(arglist, "-d");
- }
-
- /* Printer for spooler-less printing */
- if ((str = arglist_get_value(arglist, "-P"))) {
- strncpy_omit(job->printer, str, 256, omit_shellescapes);
- arglist_remove(arglist, "-P");
- }
-
+ }
+
+ // CUPS calls foomatic-rip only with 5 or 6 positional parameters,
+ // not with named options, like for example "-p <string>".
+ if (spooler != SPOOLER_CUPS)
+ {
+ if ((str = arglist_get_value(arglist, "-j")) ||
+ (str = arglist_get_value(arglist, "-J")))
+ {
+ strncpy_omit(job->title, str, 2048, omit_shellescapes);
+ if (!arglist_remove(arglist, "-j"))
+ arglist_remove(arglist, "-J");
}
- /* Check status of printer color management from the color manager */
- data->printer = job->printer;
- cm_disabled = cfCmIsPrinterCmDisabled(data);
-
- _log("'CM Color Calibration' Mode in SPOOLER-LESS: %s\n", cm_calibrate ?
- "Activated" : "Off");
-
- /* spooler specific initialization */
- switch (spooler) {
-
- case SPOOLER_CUPS:
- init_cups(arglist, filelist, job);
- break;
-
- case SPOOLER_DIRECT:
- init_direct(arglist, filelist, job);
- break;
+ // PPD file name given via the command line
+ // allow duplicates, and use the last specified one
+ while ((str = arglist_get_value(arglist, "-p")))
+ {
+ strncpy(job->ppdfile, str, sizeof(job->ppdfile) - 1);
+ if (strlen(str) > 2047)
+ job->ppdfile[2047] = '\0';
+ arglist_remove(arglist, "-p");
}
-
- /* Files to be printed (can be more than one for spooler-less printing) */
- /* Empty file list -> print STDIN */
- dstrtrim(filelist);
- if (filelist->len == 0)
- dstrcpyf(filelist, "<STDIN>");
-
- /* Check filelist */
- p = strtok(strdup(filelist->data), " ");
- while (p) {
- if (strcmp(p, "<STDIN>") != 0) {
- if (p[0] == '-')
- rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Invalid argument: %s", p);
- else if (access(p, R_OK) != 0) {
- _log("File %s does not exist/is not readable\n", p);
- strclr(p);
- }
- }
- p = strtok(NULL, " ");
+ while ((str = arglist_get_value(arglist, "--ppd")))
+ {
+ strncpy(job->ppdfile, str, sizeof(job->ppdfile) - 1);
+ if (strlen(str) > 2047)
+ job->ppdfile[2047] = '\0';
+ arglist_remove(arglist, "--ppd");
}
- /* When we print without spooler do not log onto STDERR unless
- the "-v" ('Verbose') is set or the debug mode is used */
- if (spooler == SPOOLER_DIRECT && !verbose && !debug) {
- if (logh && logh != stderr)
- fclose(logh);
- logh = NULL;
+ // Options for spooler-less printing
+ while ((str = arglist_get_value(arglist, "-o")))
+ {
+ strncpy_omit(tmp, str, 1024, omit_shellescapes);
+ dstrcatf(job->optstr, "%s ", tmp);
+ // if "-o cm-calibration" was passed, we raise a flag
+ if (!strcmp(tmp, "cm-calibration"))
+ {
+ cm_calibrate = 1;
+ cm_disabled = 1;
+ }
+ arglist_remove(arglist, "-o");
+ // We print without spooler
+ spooler = SPOOLER_DIRECT;
}
- /* If we are in debug mode, we do this earlier. */
- if (!debug) {
- _log("foomatic-rip version " VERSION " running...\n");
- /* Print the command line only in debug mode, Mac OS X adds very many
- options so that CUPS cannot handle the output of the command line
- in its log files. If CUPS encounters a line with more than 1024
- characters sent into its log files, it aborts the job with an error. */
- if (spooler != SPOOLER_CUPS) {
- _log("called with arguments: ");
- for (i = 1; i < argc -1; i++)
- _log("\'%s\', ", argv[i]);
- _log("\'%s\'\n", argv[i]);
- }
+ // Printer for spooler-less printing
+ if ((str = arglist_get_value(arglist, "-d")))
+ {
+ strncpy_omit(job->printer, str, 256, omit_shellescapes);
+ arglist_remove(arglist, "-d");
}
- /* PPD File */
- /* Load the PPD file and build a data structure for the renderer's
- command line and the options */
- read_ppd_file(job->ppdfile);
-
- /* We do not need to parse the PostScript job when we don't have
- any options. If we have options, we must check whether the
- default settings from the PPD file are valid and correct them
- if nexessary. */
- if (option_count() == 0) {
- /* We don't have any options, so we do not need to parse the
- PostScript data */
- dontparse = 1;
+ // Printer for spooler-less printing
+ if ((str = arglist_get_value(arglist, "-P")))
+ {
+ strncpy_omit(job->printer, str, 256, omit_shellescapes);
+ arglist_remove(arglist, "-P");
}
+ }
+
+ // Check status of printer color management from the color manager
+ data->printer = job->printer;
+ cm_disabled = cfCmIsPrinterCmDisabled(data);
+
+ _log("'CM Color Calibration' Mode in SPOOLER-LESS: %s\n", cm_calibrate ?
+ "Activated" : "Off");
+
+ // spooler specific initialization
+ switch (spooler)
+ {
+ case SPOOLER_CUPS:
+ init_cups(arglist, filelist, job);
+ break;
+
+ case SPOOLER_DIRECT:
+ init_direct(arglist, filelist, job);
+ break;
+ }
+
+ // Files to be printed (can be more than one for spooler-less printing)
+ // Empty file list -> print STDIN
+ dstrtrim(filelist);
+ if (filelist->len == 0)
+ dstrcpyf(filelist, "<STDIN>");
+
+ // Check filelist
+ p = strtok(strdup(filelist->data), " ");
+ while (p)
+ {
+ if (strcmp(p, "<STDIN>") != 0)
+ {
+ if (p[0] == '-')
+ rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Invalid argument: %s", p);
+ else if (access(p, R_OK) != 0)
+ {
+ _log("File %s does not exist/is not readable\n", p);
+ strclr(p);
+ }
+ }
+ p = strtok(NULL, " ");
+ }
- /* Is our PPD for a CUPS raster driver */
- if (!isempty(cupsfilter)) {
- /* Search the filter in cupsfilterpath
- The %Y is a placeholder for the option settings */
- havefilter = 0;
- path = cupsfilterpath;
- while ((path = strncpy_tochar(tmp, path, 1024, ":"))) {
- strlcat(tmp, "/", 1024);
- strlcat(tmp, cupsfilter, 1024);
- if (access(tmp, X_OK) == 0) {
- havefilter = 1;
- strlcpy(cupsfilter, tmp, 256);
- strlcat(cupsfilter, " 0 '' '' 0 '%Y%X'", 256);
- break;
- }
- }
-
- if (!havefilter) {
- /* We do not have the required filter, so we assume that
- rendering this job is supposed to be done on a remote
- server. So we do not define a renderer command line and
- embed only the option settings (as we had a PostScript
- printer). This way the settings are taken into account
- when the job is rendered on the server.*/
- _log("CUPS filter for this PPD file not found - assuming that job will "
- "be rendered on a remote server. Only the PostScript of the options"
- "will be inserted into the PostScript data stream.\n");
- }
- else {
- /* use gstoraster filter if available, otherwise run Ghostscript
- directly */
- havegstoraster = 0;
- path = cupsfilterpath;
- while ((path = strncpy_tochar(tmp, path, 1024, ":"))) {
- strlcat(tmp, "/gstoraster", 1024);
- if (access(tmp, X_OK) == 0) {
- havegstoraster = 1;
- strlcpy(gstoraster, tmp, 256);
- strlcat(gstoraster, " 0 '' '' 0 '%X'", 256);
- break;
- }
- }
- if (!havegstoraster) {
- const char **qualifier = NULL;
- char *icc_profile = NULL;
-
- if (!cm_disabled) {
- qualifier = get_ppd_qualifier();
- _log("INFO: Using qualifer: '%s.%s.%s'\n",
- qualifier[0], qualifier[1], qualifier[2]);
-
- /* fall back to PPD */
- if (icc_profile == NULL) {
- _log("INFO: need to look in PPD for matching qualifer\n");
- icc_profile = get_icc_profile_for_qualifier(qualifier);
- }
- }
-
- /* ICC profile is specified for Ghostscript unless
- "cm-calibration" option was passed in foomatic-rip */
- if (icc_profile != NULL)
- snprintf(profile_arg, sizeof(profile_arg),
- "-sOutputICCProfile='%s'", icc_profile);
- else
- profile_arg[0] = '\0';
-
- snprintf(gstoraster, sizeof(gstoraster), "gs -dQUIET -dDEBUG -dSAFER -dNOPAUSE -dBATCH -dNOINTERPOLATE -dNOMEDIAATTRS -sDEVICE=cups -dShowAcroForm %s -sOutputFile=- -", profile_arg);
- free(icc_profile);
- }
-
- /* build Ghostscript/CUPS driver command line */
- snprintf(cmd, 1024, "%s | %s", gstoraster, cupsfilter);
- _log("INFO: Using command line: %s\n", cmd);
-
- /* Set environment variables */
- setenv("PPD", job->ppdfile, 1);
- }
+ // When we print without spooler do not log onto STDERR unless
+ // the "-v" ('Verbose') is set or the debug mode is used
+ if (spooler == SPOOLER_DIRECT && !verbose && !debug)
+ {
+ if (logh && logh != stderr)
+ fclose(logh);
+ logh = NULL;
+ }
+
+ // If we are in debug mode, we do this earlier.
+ if (!debug)
+ {
+ _log("foomatic-rip version " VERSION " running...\n");
+ // Print the command line only in debug mode, Mac OS X adds very many
+ // options so that CUPS cannot handle the output of the command line
+ // in its log files. If CUPS encounters a line with more than 1024
+ // characters sent into its log files, it aborts the job with an error.
+ if (spooler != SPOOLER_CUPS)
+ {
+ _log("called with arguments: ");
+ for (i = 1; i < argc -1; i++)
+ _log("\'%s\', ", argv[i]);
+ _log("\'%s\'\n", argv[i]);
+ }
+ }
+
+ // PPD File
+ // Load the PPD file and build a data structure for the renderer's
+ // command line and the options
+ read_ppd_file(job->ppdfile);
+
+ // We do not need to parse the PostScript job when we don't have
+ // any options. If we have options, we must check whether the
+ // default settings from the PPD file are valid and correct them
+ // if nexessary.
+ if (option_count() == 0)
+ {
+ // We don't have any options, so we do not need to parse the
+ // PostScript data
+ dontparse = 1;
+ }
+
+ // Is our PPD for a CUPS raster driver
+ if (!isempty(cupsfilter))
+ {
+ // Search the filter in cupsfilterpath
+ // The %Y is a placeholder for the option settings
+ havefilter = 0;
+ path = cupsfilterpath;
+ while ((path = strncpy_tochar(tmp, path, 1024, ":")))
+ {
+ strlcat(tmp, "/", 1024);
+ strlcat(tmp, cupsfilter, 1024);
+ if (access(tmp, X_OK) == 0) {
+ havefilter = 1;
+ strlcpy(cupsfilter, tmp, 256);
+ strlcat(cupsfilter, " 0 '' '' 0 '%Y%X'", 256);
+ break;
+ }
}
- /* Was the RIP command line defined in the PPD file? If not, we assume a PostScript printer
- and do not render/translate the input data */
- if (isempty(cmd)) {
- strcpy(cmd, "cat%A%B%C%D%E%F%G%H%I%J%K%L%M%Z");
- if (dontparse) {
- /* No command line, no options, we have a raw queue, don't check
- whether the input is PostScript, simply pass the input data to
- the backend.*/
- dontparse = 2;
- strcpy(printer_model, "Raw queue");
- }
+ if (!havefilter)
+ {
+ // We do not have the required filter, so we assume that
+ // rendering this job is supposed to be done on a remote
+ // server. So we do not define a renderer command line and
+ // embed only the option settings (as we had a PostScript
+ // printer). This way the settings are taken into account
+ // when the job is rendered on the server.
+ _log("CUPS filter for this PPD file not found - assuming that job will "
+ "be rendered on a remote server. Only the PostScript of the options"
+ "will be inserted into the PostScript data stream.\n");
}
+ else
+ {
+ // use gstoraster filter if available, otherwise run Ghostscript
+ // directly
+ havegstoraster = 0;
+ path = cupsfilterpath;
+ while ((path = strncpy_tochar(tmp, path, 1024, ":")))
+ {
+ strlcat(tmp, "/gstoraster", 1024);
+ if (access(tmp, X_OK) == 0)
+ {
+ havegstoraster = 1;
+ strlcpy(gstoraster, tmp, 256);
+ strlcat(gstoraster, " 0 '' '' 0 '%X'", 256);
+ break;
+ }
+ }
+ if (!havegstoraster)
+ {
+ const char **qualifier = NULL;
+ char *icc_profile = NULL;
+
+ if (!cm_disabled)
+ {
+ qualifier = get_ppd_qualifier();
+ _log("INFO: Using qualifer: '%s.%s.%s'\n",
+ qualifier[0], qualifier[1], qualifier[2]);
+
+ // fall back to PPD
+ if (icc_profile == NULL)
+ {
+ _log("INFO: need to look in PPD for matching qualifer\n");
+ icc_profile = get_icc_profile_for_qualifier(qualifier);
+ }
+ }
+
+ // ICC profile is specified for Ghostscript unless
+ // "cm-calibration" option was passed in foomatic-rip
+ if (icc_profile != NULL)
+ snprintf(profile_arg, sizeof(profile_arg),
+ "-sOutputICCProfile='%s'", icc_profile);
+ else
+ profile_arg[0] = '\0';
+
+ snprintf(gstoraster, sizeof(gstoraster), "gs -dQUIET -dDEBUG -dSAFER -dNOPAUSE -dBATCH -dNOINTERPOLATE -dNOMEDIAATTRS -sDEVICE=cups -dShowAcroForm %s -sOutputFile=- -", profile_arg);
+ free(icc_profile);
+ }
- /* Summary for debugging */
- _log("\nParameter Summary\n"
- "-----------------\n\n"
- "Spooler: %s\n"
- "Printer: %s\n"
- "Shell: %s\n"
- "PPD file: %s\n"
- "ATTR file: %s\n"
- "Printer model: %s\n",
- spooler_name(spooler), job->printer, get_modern_shell(), job->ppdfile, attrpath, printer_model);
- /* Print the options string only in debug mode, Mac OS X adds very many
- options so that CUPS cannot handle the output of the option string
- in its log files. If CUPS encounters a line with more than 1024 characters
- sent into its log files, it aborts the job with an error.*/
- if (debug || spooler != SPOOLER_CUPS)
- _log("Options: %s\n", job->optstr->data);
- _log("Job title: %s\n", job->title);
- _log("File(s) to be printed:\n");
- _log("%s\n\n", filelist->data);
- if (getenv("GS_LIB"))
- _log("Ghostscript extra search path ('GS_LIB'): %s\n", getenv("GS_LIB"));
-
- /* Process options from command line */
- optionset_copy_values(optionset("default"), optionset("userval"));
- process_cmdline_options();
-
- /* no postpipe for CUPS , even if one is defined in the PPD file */
- if (spooler == SPOOLER_CUPS )
- dstrclear(postpipe);
-
- if (postpipe->len)
- _log("Output will be redirected to:\n%s\n", postpipe);
-
-
- filename = strtok_r(filelist->data, " ", &p);
- while (filename) {
- _log("\n================================================\n\n"
- "File: %s\n\n"
- "================================================\n\n", filename);
-
- /* Do we have a raw queue? */
- if (dontparse == 2) {
- /* Raw queue, simply pass the input into the postpipe (or to STDOUT
- when there is no postpipe) */
- _log("Raw printing, executing \"cat %%s\"\n\n");
- snprintf(tmp, 1024, "cat %s", postpipe->data);
- if (strcasecmp(filename, "<STDIN>")) {
- FILE *fh = fopen(filename, "r");
- if (!fh) {
- _log("Failed to open \"%s\".\n", filename);
- fclose(stdin);
- } else {
- dup2(fileno(fh), 0);
- fclose(fh);
- }
- }
- run_system_process("raw-printer", tmp);
- filename = strtok_r(NULL, " ", &p);
- continue;
- }
-
- /* First, for arguments with a default, stick the default in as
- the initial value for the "header" option set, this option set
- consists of the PPD defaults, the options specified on the
- command line, and the options set in the header part of the
- PostScript file (all before the first page begins). */
- optionset_copy_values(optionset("userval"), optionset("header"));
-
- if (!print_file(filename, 1))
- rip_die(EXIT_PRNERR_NORETRY, "Could not print file %s\n", filename);
- filename = strtok_r(NULL, " ", &p);
+ // build Ghostscript/CUPS driver command line
+ snprintf(cmd, 1024, "%s | %s", gstoraster, cupsfilter);
+ _log("INFO: Using command line: %s\n", cmd);
+
+ // Set environment variables
+ setenv("PPD", job->ppdfile, 1);
+ }
+ }
+
+ // Was the RIP command line defined in the PPD file? If not, we assume a
+ // PostScript printer and do not render/translate the input data
+ if (isempty(cmd))
+ {
+ strcpy(cmd, "cat%A%B%C%D%E%F%G%H%I%J%K%L%M%Z");
+ if (dontparse)
+ {
+ // No command line, no options, we have a raw queue, don't check
+ // whether the input is PostScript, simply pass the input data to
+ // the backend.
+ dontparse = 2;
+ strcpy(printer_model, "Raw queue");
+ }
+ }
+
+ // Summary for debugging
+ _log("\nParameter Summary\n"
+ "-----------------\n\n"
+ "Spooler: %s\n"
+ "Printer: %s\n"
+ "Shell: %s\n"
+ "PPD file: %s\n"
+ "ATTR file: %s\n"
+ "Printer model: %s\n",
+ spooler_name(spooler), job->printer, get_modern_shell(),
+ job->ppdfile, attrpath, printer_model);
+ // Print the options string only in debug mode, Mac OS X adds very many
+ // options so that CUPS cannot handle the output of the option string
+ // in its log files. If CUPS encounters a line with more than 1024 characters
+ // sent into its log files, it aborts the job with an error.
+ if (debug || spooler != SPOOLER_CUPS)
+ _log("Options: %s\n", job->optstr->data);
+ _log("Job title: %s\n", job->title);
+ _log("File(s) to be printed:\n");
+ _log("%s\n\n", filelist->data);
+ if (getenv("GS_LIB"))
+ _log("Ghostscript extra search path ('GS_LIB'): %s\n", getenv("GS_LIB"));
+
+ // Process options from command line
+ optionset_copy_values(optionset("default"), optionset("userval"));
+ process_cmdline_options();
+
+ // no postpipe for CUPS , even if one is defined in the PPD file
+ if (spooler == SPOOLER_CUPS )
+ dstrclear(postpipe);
+
+ if (postpipe->len)
+ _log("Output will be redirected to:\n%s\n", postpipe);
+
+ filename = strtok_r(filelist->data, " ", &p);
+ while (filename)
+ {
+ _log("\n================================================\n\n"
+ "File: %s\n\n"
+ "================================================\n\n", filename);
+
+ // Do we have a raw queue?
+ if (dontparse == 2)
+ {
+ // Raw queue, simply pass the input into the postpipe (or to STDOUT
+ // when there is no postpipe)
+ _log("Raw printing, executing \"cat %%s\"\n\n");
+ snprintf(tmp, 1024, "cat %s", postpipe->data);
+ if (strcasecmp(filename, "<STDIN>"))
+ {
+ FILE *fh = fopen(filename, "r");
+ if (!fh)
+ {
+ _log("Failed to open \"%s\".\n", filename);
+ fclose(stdin);
+ }
+ else
+ {
+ dup2(fileno(fh), 0);
+ fclose(fh);
+ }
+ }
+ run_system_process("raw-printer", tmp);
+ filename = strtok_r(NULL, " ", &p);
+ continue;
}
- /* Close the last input file */
- fclose(stdin);
+ // First, for arguments with a default, stick the default in as
+ // the initial value for the "header" option set, this option set
+ // consists of the PPD defaults, the options specified on the
+ // command line, and the options set in the header part of the
+ // PostScript file (all before the first page begins).
+ optionset_copy_values(optionset("userval"), optionset("header"));
- /* TODO dump everything in $dat when debug is turned on (necessary?) */
+ if (!print_file(filename, 1))
+ rip_die(EXIT_PRNERR_NORETRY, "Could not print file %s\n", filename);
+ filename = strtok_r(NULL, " ", &p);
+ }
- _log("\nClosing foomatic-rip.\n");
+ // Close the last input file
+ fclose(stdin);
+ // TODO dump everything in $dat when debug is turned on (necessary?)
- /* Cleanup */
- free_job(job);
- free_dstr(filelist);
- options_free();
- close_log();
+ _log("\nClosing foomatic-rip.\n");
- argv_free(jclprepend);
- free_dstr(jclappend);
+ // Cleanup
+ free_job(job);
+ free_dstr(filelist);
+ options_free();
+ close_log();
- list_free(arglist);
+ argv_free(jclprepend);
+ free_dstr(jclappend);
- return EXIT_PRINTED;
-}
+ list_free(arglist);
+ return (EXIT_PRINTED);
+}
-/* foomaticrip.h
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// foomaticrip.h
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#ifndef foomatic_h
#define foomatic_h
#include <time.h>
#include <limits.h>
-/* This is the location of the debug logfile (and also the copy of the
- * processed PostScript data) in case you have enabled debugging above.
- * The logfile will get the extension ".log", the PostScript data ".ps".
- */
+// This is the location of the debug logfile (and also the copy of the
+// processed PostScript data) in case you have enabled debugging above.
+// The logfile will get the extension ".log", the PostScript data ".ps".
+
#ifndef LOG_FILE
#define LOG_FILE "/tmp/foomatic-rip"
#endif
-/* Constants used by this filter
- *
- * Error codes, as some spoolers behave different depending on the reason why
- * the RIP failed, we return an error code.
- */
-#define EXIT_PRINTED 0 /* file was printed normally */
-#define EXIT_PRNERR 1 /* printer error occured */
-#define EXIT_PRNERR_NORETRY 2 /* printer error with no hope of retry */
-#define EXIT_JOBERR 3 /* job is defective */
-#define EXIT_SIGNAL 4 /* terminated after catching signal */
-#define EXIT_ENGAGED 5 /* printer is otherwise engaged (connection refused) */
-#define EXIT_STARVED 6 /* starved for system resources */
-#define EXIT_PRNERR_NORETRY_ACCESS_DENIED 7 /* bad password? bad port permissions? */
-#define EXIT_PRNERR_NOT_RESPONDING 8 /* just doesn't answer at all (turned off?) */
-#define EXIT_PRNERR_NORETRY_BAD_SETTINGS 9 /* interface settings are invalid */
-#define EXIT_PRNERR_NO_SUCH_ADDRESS 10 /* address lookup failed, may be transient */
-#define EXIT_PRNERR_NORETRY_NO_SUCH_ADDRESS 11 /* address lookup failed, not transient */
-#define EXIT_INCAPABLE 50 /* printer wants (lacks) features or resources */
-
-
-/* Supported spoolers are currently:
- *
- * cups - CUPS - Common Unix Printing System
- * direct - Direct, spooler-less printing
- */
+// Constants used by this filter
+//
+// Error codes, as some spoolers behave different depending on the reason why
+// the RIP failed, we return an error code.
+
+#define EXIT_PRINTED 0 // file was printed normally
+#define EXIT_PRNERR 1 // printer error occured
+#define EXIT_PRNERR_NORETRY 2 // printer error with no hope
+ // of retry
+#define EXIT_JOBERR 3 // job is defective
+#define EXIT_SIGNAL 4 // terminated after catching
+ // signal
+#define EXIT_ENGAGED 5 // printer is otherwise engaged
+ // (connection refused)
+#define EXIT_STARVED 6 // starved for system resources
+#define EXIT_PRNERR_NORETRY_ACCESS_DENIED 7 // bad password? bad port
+ // permissions?
+#define EXIT_PRNERR_NOT_RESPONDING 8 // just doesn't answer at all
+ // (turned off?)
+#define EXIT_PRNERR_NORETRY_BAD_SETTINGS 9 // interface settings are
+ // invalid
+#define EXIT_PRNERR_NO_SUCH_ADDRESS 10 // address lookup failed, may
+ // be transient
+#define EXIT_PRNERR_NORETRY_NO_SUCH_ADDRESS 11 // address lookup failed, not
+ // transient
+#define EXIT_INCAPABLE 50 // printer wants (lacks)
+ // features or resources
+
+
+// Supported spoolers are currently:
+//
+// cups - CUPS - Common Unix Printing System
+// direct - Direct, spooler-less printing
+
#define SPOOLER_CUPS 1
#define SPOOLER_DIRECT 2
-/* The spooler from which foomatic-rip was called. set in main() */
+// The spooler from which foomatic-rip was called. set in main()
extern int spooler;
#ifndef PATH_MAX
#endif
#define CMDLINE_MAX 65536
-typedef struct {
+typedef struct
+{
char printer[256];
char id[128];
char user[128];
} jobparams_t;
-jobparams_t * get_current_job();
+jobparams_t *get_current_job();
void _log(const char* msg, ...);
int redirect_log_to_stderr();
void rip_die(int status, const char *msg, ...);
-const char * get_modern_shell();
-FILE * open_postpipe();
+const char *get_modern_shell();
+FILE *open_postpipe();
extern struct dstr *currentcmd;
extern struct dstr *jclappend;
-/* options.c
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// options.c
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#include "foomaticrip.h"
#include "options.h"
#include <string.h>
#include <math.h>
-/* qualifier -> filename mapping entry */
-typedef struct icc_mapping_entry_s {
- char *qualifier;
- char *filename;
+// qualifier -> filename mapping entry
+typedef struct icc_mapping_entry_s
+{
+ char *qualifier;
+ char *filename;
} icc_mapping_entry_t;
-/* Values from foomatic keywords in the ppd file */
+// Values from foomatic keywords in the ppd file
extern char printer_model [256];
char printer_id [256];
char driver [128];
char cmd [4096];
char cmd_pdf [4096];
-extern dstr_t *postpipe; /* command into which the output of this
- filter should be piped */
+extern dstr_t *postpipe; // command into which the output of this
+ // filter should be piped
extern char cupsfilter [256];
int jobentitymaxlen = 0;
int userentitymaxlen = 0;
int titleentitymaxlen = 0;
int optionsentitymaxlen = 0;
-/* JCL prefix to put before the JCL options
- (Can be modified by a "*JCLBegin:" keyword in the ppd file): */
+// JCL prefix to put before the JCL options
+// (Can be modified by a "*JCLBegin:" keyword in the ppd file):
char jclbegin[256] = "\033%-12345X@PJL\n";
-/* JCL command to switch the printer to the PostScript interpreter
- (Can be modified by a "*JCLToPSInterpreter:" keyword in the PPD file): */
+// JCL command to switch the printer to the PostScript interpreter
+// (Can be modified by a "*JCLToPSInterpreter:" keyword in the PPD file):
char jcltointerpreter[256] = "";
-/* JCL command to close a print job
- (Can be modified by a "*JCLEnd:" keyword in the PPD file): */
+// JCL command to close a print job
+// (Can be modified by a "*JCLEnd:" keyword in the PPD file):
char jclend[256] = "\033%-12345X@PJL RESET\n";
-/* Prefix for starting every JCL command
- (Can be modified by "*FoomaticJCLPrefix:" keyword in the PPD file): */
+// Prefix for starting every JCL command
+// (Can be modified by "*FoomaticJCLPrefix:" keyword in the PPD file):
char jclprefix[256] = "@PJL ";
int jclprefixset = 0;
char **optionsets;
-char * get_icc_profile_for_qualifier(const char **qualifier)
+char *
+get_icc_profile_for_qualifier(const char **qualifier)
{
- char tmp[1024];
- char *profile = NULL;
- listitem_t *i;
- icc_mapping_entry_t *entry;
+ char tmp[1024];
+ char *profile = NULL;
+ listitem_t *i;
+ icc_mapping_entry_t *entry;
- /* no data */
- if (qualifier_data == NULL)
- goto out;
+ // no data
+ if (qualifier_data == NULL)
+ goto out;
- /* search list for qualifier */
- snprintf(tmp, sizeof(tmp), "%s.%s.%s",
- qualifier[0], qualifier[1], qualifier[2]);
- for (i = qualifier_data->first; i != NULL; i = i->next) {
- entry = (icc_mapping_entry_t *) i->data;
- if (strcmp(entry->qualifier, tmp) == 0) {
- profile = entry->filename;
- break;
- }
+ // search list for qualifier
+ snprintf(tmp, sizeof(tmp), "%s.%s.%s",
+ qualifier[0], qualifier[1], qualifier[2]);
+ for (i = qualifier_data->first; i != NULL; i = i->next)
+ {
+ entry = (icc_mapping_entry_t *)i->data;
+ if (strcmp(entry->qualifier, tmp) == 0)
+ {
+ profile = entry->filename;
+ break;
}
-out:
- return profile;
+ }
+ out:
+ return (profile);
}
-/* a selector is a general tri-dotted specification.
- * The 2nd and 3rd elements of the qualifier are optionally modified by
- * cupsICCQualifier2 and cupsICCQualifier3:
- *
- * [Colorspace].[{cupsICCQualifier2}].[{cupsICCQualifier3}]
- */
+
+// a selector is a general tri-dotted specification.
+// The 2nd and 3rd elements of the qualifier are optionally modified by
+// cupsICCQualifier2 and cupsICCQualifier3:
+//
+// [Colorspace].[{cupsICCQualifier2}].[{cupsICCQualifier3}]
+
const char **
get_ppd_qualifier ()
{
- return (const char**) qualifier;
-}
-
-const char * type_name(int type)
-{
- switch (type) {
- case TYPE_NONE:
- return "none";
- case TYPE_ENUM:
- return "enum";
- case TYPE_PICKMANY:
- return "pickmany";
- case TYPE_BOOL:
- return "bool";
- case TYPE_INT:
- return "int";
- case TYPE_FLOAT:
- return "float";
- case TYPE_STRING:
- return "string";
- };
- _log("type '%d' does not exist\n", type);
- return NULL;
+ return ((const char**)qualifier);
}
-int type_from_string(const char *typestr)
+
+const char *
+type_name(int type)
+{
+ switch (type)
+ {
+ case TYPE_NONE:
+ return ("none");
+ case TYPE_ENUM:
+ return ("enum");
+ case TYPE_PICKMANY:
+ return ("pickmany");
+ case TYPE_BOOL:
+ return ("bool");
+ case TYPE_INT:
+ return ("int");
+ case TYPE_FLOAT:
+ return ("float");
+ case TYPE_STRING:
+ return ("string");
+ }
+ _log("type '%d' does not exist\n", type);
+ return (NULL);
+}
+
+
+int
+type_from_string(const char *typestr)
{
- int type = TYPE_NONE;
+ int type = TYPE_NONE;
- /* Official PPD options */
- if (!strcmp(typestr, "PickOne"))
- type = TYPE_ENUM;
- else if (!strcmp(typestr, "PickMany"))
- type = TYPE_PICKMANY;
- else if (!strcmp(typestr, "Boolean"))
- type = TYPE_BOOL;
+ // Official PPD options
+ if (!strcmp(typestr, "PickOne"))
+ type = TYPE_ENUM;
+ else if (!strcmp(typestr, "PickMany"))
+ type = TYPE_PICKMANY;
+ else if (!strcmp(typestr, "Boolean"))
+ type = TYPE_BOOL;
- /* FoomaticRIPOption */
- else if (strcasecmp(typestr, "enum") == 0)
- type = TYPE_ENUM;
- else if (strcasecmp(typestr, "pickmany") == 0)
- type = TYPE_PICKMANY;
- else if (strcasecmp(typestr, "bool") == 0)
- type = TYPE_BOOL;
- else if (strcasecmp(typestr, "int") == 0)
- type = TYPE_INT;
- else if (strcasecmp(typestr, "float") == 0)
- type = TYPE_FLOAT;
- else if (strcasecmp(typestr, "string") == 0)
- type = TYPE_STRING;
- else if (strcasecmp(typestr, "password") == 0)
- type = TYPE_PASSWORD;
+ // FoomaticRIPOption
+ else if (strcasecmp(typestr, "enum") == 0)
+ type = TYPE_ENUM;
+ else if (strcasecmp(typestr, "pickmany") == 0)
+ type = TYPE_PICKMANY;
+ else if (strcasecmp(typestr, "bool") == 0)
+ type = TYPE_BOOL;
+ else if (strcasecmp(typestr, "int") == 0)
+ type = TYPE_INT;
+ else if (strcasecmp(typestr, "float") == 0)
+ type = TYPE_FLOAT;
+ else if (strcasecmp(typestr, "string") == 0)
+ type = TYPE_STRING;
+ else if (strcasecmp(typestr, "password") == 0)
+ type = TYPE_PASSWORD;
- return type;
+ return (type);
}
-char style_from_string(const char *style)
-{
- char r = '\0';
- if (strcmp(style, "PS") == 0)
- r = 'G';
- else if (strcmp(style, "CmdLine") == 0)
- r = 'C';
- else if (strcmp(style, "JCL") == 0)
- r = 'J';
- else if (strcmp(style, "Composite") == 0)
- r = 'X';
- return r;
-}
-int section_from_string(const char *value)
+char
+style_from_string(const char *style)
{
- if (!strcasecmp(value, "AnySetup"))
- return SECTION_ANYSETUP;
- else if (!strcasecmp(value, "PageSetup"))
- return SECTION_PAGESETUP;
- else if (!strcasecmp(value, "Prolog"))
- return SECTION_PROLOG;
- else if (!strcasecmp(value, "DocumentSetup"))
- return SECTION_DOCUMENTSETUP;
- else if (!strcasecmp(value, "JCLSetup"))
- return SECTION_JCLSETUP;
-
- _log("Unknown section: \"%s\"\n", value);
- return 0;
+ char r = '\0';
+ if (strcmp(style, "PS") == 0)
+ r = 'G';
+ else if (strcmp(style, "CmdLine") == 0)
+ r = 'C';
+ else if (strcmp(style, "JCL") == 0)
+ r = 'J';
+ else if (strcmp(style, "Composite") == 0)
+ r = 'X';
+ return (r);
}
-void options_init()
+
+int
+section_from_string(const char *value)
{
- optionset_alloc = 8;
- optionset_count = 0;
- optionsets = calloc(optionset_alloc, sizeof(char *));
+ if (!strcasecmp(value, "AnySetup"))
+ return (SECTION_ANYSETUP);
+ else if (!strcasecmp(value, "PageSetup"))
+ return (SECTION_PAGESETUP);
+ else if (!strcasecmp(value, "Prolog"))
+ return (SECTION_PROLOG);
+ else if (!strcasecmp(value, "DocumentSetup"))
+ return (SECTION_DOCUMENTSETUP);
+ else if (!strcasecmp(value, "JCLSetup"))
+ return (SECTION_JCLSETUP);
- prologprepend = create_dstr();
- setupprepend = create_dstr();
- pagesetupprepend = create_dstr();
+ _log("Unknown section: \"%s\"\n", value);
+ return (0);
}
-static void free_param(param_t *param)
+
+void
+options_init()
{
- if (param->allowedchars) {
- regfree(param->allowedchars);
- free(param->allowedchars);
- }
-
- if (param->allowedregexp) {
- regfree(param->allowedregexp);
- free(param->allowedregexp);
- }
+ optionset_alloc = 8;
+ optionset_count = 0;
+ optionsets = calloc(optionset_alloc, sizeof(char *));
- free(param);
+ prologprepend = create_dstr();
+ setupprepend = create_dstr();
+ pagesetupprepend = create_dstr();
}
-/*
- * Values
- */
-static void free_value(value_t *val)
+static void
+free_param(param_t *param)
{
- if (val->value)
- free(val->value);
- free(val);
-}
+ if (param->allowedchars)
+ {
+ regfree(param->allowedchars);
+ free(param->allowedchars);
+ }
+ if (param->allowedregexp)
+ {
+ regfree(param->allowedregexp);
+ free(param->allowedregexp);
+ }
-/*
- * Options
- */
-static void free_option(option_t *opt)
-{
- choice_t *choice;
- param_t *param;
- value_t *value;
+ free(param);
+}
- free(opt->custom_command);
- free(opt->proto);
- while (opt->valuelist) {
- value = opt->valuelist;
- opt->valuelist = opt->valuelist->next;
- free_value(value);
- }
- while (opt->choicelist) {
- choice = opt->choicelist;
- opt->choicelist = opt->choicelist->next;
- free(choice);
- }
- while (opt->paramlist) {
- param = opt->paramlist;
- opt->paramlist = opt->paramlist->next;
- free_param(param);
- }
- if (opt->foomatic_param)
- free_param(opt->foomatic_param);
+//
+// Values
+//
- free(opt);
+static void
+free_value(value_t *val)
+{
+ if (val->value)
+ free(val->value);
+ free(val);
}
-void options_free()
-{
- option_t *opt;
- int i;
- listitem_t *item;
- icc_mapping_entry_t *entry;
- for (i = 0; i < optionset_count; i++)
- free(optionsets[i]);
- free(optionsets);
- optionsets = NULL;
- optionset_alloc = 0;
- optionset_count = 0;
+//
+// Options
+//
- if (qualifier_data) {
- for (item = qualifier_data->first; item != NULL; item = item->next) {
- entry = (icc_mapping_entry_t *) item->data;
- free(entry->qualifier);
- free(entry->filename);
- free(entry);
- }
- list_free(qualifier_data);
+static void free_option(option_t *opt)
+{
+ choice_t *choice;
+ param_t *param;
+ value_t *value;
+
+ free(opt->custom_command);
+ free(opt->proto);
+
+ while (opt->valuelist)
+ {
+ value = opt->valuelist;
+ opt->valuelist = opt->valuelist->next;
+ free_value(value);
+ }
+ while (opt->choicelist)
+ {
+ choice = opt->choicelist;
+ opt->choicelist = opt->choicelist->next;
+ free(choice);
+ }
+ while (opt->paramlist)
+ {
+ param = opt->paramlist;
+ opt->paramlist = opt->paramlist->next;
+ free_param(param);
+ }
+ if (opt->foomatic_param)
+ free_param(opt->foomatic_param);
+
+ free(opt);
+}
+
+
+void
+options_free()
+{
+ option_t *opt;
+ int i;
+ listitem_t *item;
+ icc_mapping_entry_t *entry;
+
+ for (i = 0; i < optionset_count; i++)
+ free(optionsets[i]);
+ free(optionsets);
+ optionsets = NULL;
+ optionset_alloc = 0;
+ optionset_count = 0;
+
+ if (qualifier_data)
+ {
+ for (item = qualifier_data->first; item != NULL; item = item->next)
+ {
+ entry = (icc_mapping_entry_t *) item->data;
+ free(entry->qualifier);
+ free(entry->filename);
+ free(entry);
}
+ list_free(qualifier_data);
+ }
- for (i=0; i<3; i++)
- free(qualifier[i]);
- free(qualifier);
+ for (i = 0; i < 3; i ++)
+ free(qualifier[i]);
+ free(qualifier);
- while (optionlist) {
- opt = optionlist;
- optionlist = optionlist->next;
- free_option(opt);
- }
+ while (optionlist)
+ {
+ opt = optionlist;
+ optionlist = optionlist->next;
+ free_option(opt);
+ }
- if (postpipe)
- free_dstr(postpipe);
+ if (postpipe)
+ free_dstr(postpipe);
- free_dstr(prologprepend);
- free_dstr(setupprepend);
- free_dstr(pagesetupprepend);
+ free_dstr(prologprepend);
+ free_dstr(setupprepend);
+ free_dstr(pagesetupprepend);
}
-size_t option_count()
+
+size_t
+option_count()
{
- option_t *opt;
- size_t cnt = 0;
+ option_t *opt;
+ size_t cnt = 0;
- for (opt = optionlist; opt; opt = opt->next)
- cnt++;
- return cnt;
+ for (opt = optionlist; opt; opt = opt->next)
+ cnt++;
+ return (cnt);
}
-option_t * find_option(const char *name)
+
+option_t *
+find_option(const char *name)
{
- option_t *opt;
+ option_t *opt;
- /* PageRegion and PageSize are the same options, just store one of them */
- if (!strcasecmp(name, "PageRegion"))
- return find_option("PageSize");
+ // PageRegion and PageSize are the same options, just store one of them
+ if (!strcasecmp(name, "PageRegion"))
+ return (find_option("PageSize"));
- for (opt = optionlist; opt; opt = opt->next) {
- if ((!strcasecmp(opt->name, name)) ||
- ((!strcasecmp(opt->name, &name[2])) &&
- (!prefixcasecmp(name, "no"))))
- return opt;
- }
- return NULL;
+ for (opt = optionlist; opt; opt = opt->next)
+ {
+ if ((!strcasecmp(opt->name, name)) ||
+ ((!strcasecmp(opt->name, &name[2])) &&
+ (!prefixcasecmp(name, "no"))))
+ return (opt);
+ }
+ return (NULL);
}
-option_t * assure_option(const char *name)
+
+option_t *
+assure_option(const char *name)
{
- option_t *opt, *last;
+ option_t *opt, *last;
- if ((opt = find_option(name)))
- return opt;
+ if ((opt = find_option(name)))
+ return (opt);
- opt = calloc(1, sizeof(option_t));
+ opt = calloc(1, sizeof(option_t));
- /* PageRegion and PageSize are the same options, just store one of them */
- if (!strcmp(name, "PageRegion"))
- strlcpy(opt->name, "PageSize", 128);
- else
- strlcpy(opt->name, name, 128);
+ // PageRegion and PageSize are the same options, just store one of them
+ if (!strcmp(name, "PageRegion"))
+ strlcpy(opt->name, "PageSize", 128);
+ else
+ strlcpy(opt->name, name, 128);
- /* set varname */
- strcpy(opt->varname, opt->name);
- strrepl(opt->varname, "-/.", '_');
+ // set varname
+ strcpy(opt->varname, opt->name);
+ strrepl(opt->varname, "-/.", '_');
- /* Default execution style is 'G' (PostScript) since all arguments for
- which we don't find "*Foomatic..." keywords are usual PostScript options */
- opt->style = 'G';
+ // Default execution style is 'G' (PostScript) since all arguments for
+ // which we don't find "*Foomatic..." keywords are usual PostScript options
+ opt->style = 'G';
- opt->type = TYPE_NONE;
+ opt->type = TYPE_NONE;
- /* append opt to optionlist */
- if (optionlist) {
- for (last = optionlist; last->next; last = last->next);
- last->next = opt;
- }
- else
- optionlist = opt;
+ // append opt to optionlist
+ if (optionlist)
+ {
+ for (last = optionlist; last->next; last = last->next);
+ last->next = opt;
+ }
+ else
+ optionlist = opt;
- /* prepend opt to optionlist_sorted_by_order
- (0 is always at the beginning) */
- if (optionlist_sorted_by_order) {
- opt->next_by_order = optionlist_sorted_by_order;
- optionlist_sorted_by_order = opt;
- }
- else {
- optionlist_sorted_by_order = opt;
- }
+ // prepend opt to optionlist_sorted_by_order
+ // (0 is always at the beginning)
+ if (optionlist_sorted_by_order)
+ {
+ opt->next_by_order = optionlist_sorted_by_order;
+ optionlist_sorted_by_order = opt;
+ }
+ else
+ optionlist_sorted_by_order = opt;
- _log("Added option %s\n", opt->name);
- return opt;
+ _log("Added option %s\n", opt->name);
+ return (opt);
}
-/* This functions checks if "opt" is named "name", or if it has any
- alternative names "name" (e.g. PageSize / PageRegion) */
-int option_has_name(option_t *opt, const char *name)
+
+// This functions checks if "opt" is named "name", or if it has any
+// alternative names "name" (e.g. PageSize / PageRegion)
+int
+option_has_name(option_t *opt,
+ const char *name)
{
- if (!strcmp(opt->name, name))
- return 1;
+ if (!strcmp(opt->name, name))
+ return (1);
- if (!strcmp(opt->name, "PageSize") && !strcmp(name, "PageRegion"))
- return 1;
+ if (!strcmp(opt->name, "PageSize") && !strcmp(name, "PageRegion"))
+ return (1);
- return 0;
+ return (0);
}
-int option_is_composite(option_t *opt)
+
+int
+option_is_composite(option_t *opt)
{
- return opt ? (opt->style == 'X') : 0;
+ return (opt ? (opt->style == 'X') : 0);
}
-int option_is_ps_command(option_t *opt)
+
+int
+option_is_ps_command(option_t *opt)
{
- return opt->style == 'G';
+ return (opt->style == 'G');
}
-int option_is_jcl_arg(option_t *opt)
+
+int
+option_is_jcl_arg(option_t *opt)
{
- return opt->style == 'J';
+ return (opt->style == 'J');
}
-int option_is_commandline_arg(option_t *opt)
+
+int
+option_is_commandline_arg(option_t *opt)
{
- return opt->style == 'C';
+ return (opt->style == 'C');
}
-int option_get_section(option_t *opt)
+
+int
+option_get_section(option_t *opt)
{
- return opt->section;
+ return (opt->section);
}
-static value_t * option_find_value(option_t *opt, int optionset)
+
+static value_t *
+option_find_value(option_t *opt,
+ int optionset)
{
- value_t *val;
+ value_t *val;
- if (!opt)
- return NULL;
+ if (!opt)
+ return (NULL);
- for (val = opt->valuelist; val; val = val->next) {
- if (val->optionset == optionset)
- return val;
- }
- return NULL;
+ for (val = opt->valuelist; val; val = val->next)
+ {
+ if (val->optionset == optionset)
+ return (val);
+ }
+ return (NULL);
}
-static value_t * option_assure_value(option_t *opt, int optionset)
+
+static value_t *
+option_assure_value(option_t *opt,
+ int optionset)
{
- value_t *val, *last;
- val = option_find_value(opt, optionset);
- if (!val) {
- val = calloc(1, sizeof(value_t));
- val->optionset = optionset;
+ value_t *val, *last;
- /* append to opt->valuelist */
- if (opt->valuelist) {
- for (last = opt->valuelist; last->next; last = last->next);
- last->next = val;
- }
- else
- opt->valuelist = val;
+ val = option_find_value(opt, optionset);
+ if (!val)
+ {
+ val = calloc(1, sizeof(value_t));
+ val->optionset = optionset;
+
+ // append to opt->valuelist
+ if (opt->valuelist)
+ {
+ for (last = opt->valuelist; last->next; last = last->next);
+ last->next = val;
}
- return val;
+ else
+ opt->valuelist = val;
+ }
+ return (val);
}
-static param_t * option_find_param_index(option_t *opt, const char *name, int *idx)
+
+static param_t *
+option_find_param_index(option_t *opt,
+ const char *name,
+ int *idx)
{
- param_t *param;
- int i;
- for (param = opt->paramlist, i = 0; param; param = param->next, i += 1) {
- if (!strcasecmp(param->name, name)) {
- if (idx)
- *idx = i;
- return param;
- }
+ param_t *param;
+ int i;
+ for (param = opt->paramlist, i = 0; param; param = param->next, i += 1)
+ {
+ if (!strcasecmp(param->name, name))
+ {
+ if (idx)
+ *idx = i;
+ return (param);
+ }
+ }
+ if (idx)
+ *idx = -1;
+ return (0);
+}
+
+static choice_t *
+option_find_choice(option_t *opt,
+ const char *name)
+{
+ choice_t *choice;
+ if (!opt || !name)
+ return (NULL);
+ for (choice = opt->choicelist; choice; choice = choice->next)
+ {
+ if (!strcasecmp(choice->value, name))
+ return (choice);
+ }
+ return (NULL);
+}
+
+
+void
+free_paramvalues(option_t *opt,
+ char **paramvalues)
+{
+ int i;
+ if (!paramvalues)
+ return;
+ for (i = 0; i < opt->param_count; i++)
+ free(paramvalues[i]);
+ free(paramvalues);
+}
+
+
+char *
+get_valid_param_string(option_t *opt,
+ param_t *param,
+ const char *str)
+{
+ char *result;
+ int i, imin, imax;
+ float f, fmin, fmax;
+ size_t len;
+
+ switch (param->type)
+ {
+ case TYPE_INT:
+ i = atoi(str);
+ imin = !isempty(param->min) ? atoi(param->min) : -999999;
+ imax = !isempty(param->max) ? atoi(param->max) : 1000000;
+ if (i < imin)
+ {
+ _log("Value \"%s\" for option \"%s\", parameter \"%s\" is smaller than the minimum value \"%d\"\n",
+ str, opt->name, param->name, imin);
+ return (NULL);
+ }
+ else if (i > imax)
+ {
+ _log("Value \"%s\" for option \"%s\", parameter \"%s\" is larger than the maximum value \"%d\"\n",
+ str, opt->name, param->name, imax);
+ return (NULL);
+ }
+ result = malloc(32);
+ snprintf(result, 32, "%d", i);
+ return (result);
+
+ case TYPE_FLOAT:
+ case TYPE_CURVE:
+ case TYPE_INVCURVE:
+ case TYPE_POINTS:
+ f = atof(str);
+ fmin = !isempty(param->min) ? atof(param->min) : -999999.0;
+ fmax = !isempty(param->max) ? atof(param->max) : 1000000.0;
+ if (f < fmin)
+ {
+ _log("Value \"%s\" for option \"%s\", parameter \"%s\" is smaller than the minimum value \"%d\"\n",
+ str, opt->name, param->name, fmin);
+ return (NULL);
+ }
+ else if (f > fmax)
+ {
+ _log("Value \"%s\" for option \"%s\", parameter \"%s\" is larger than the maximum value \"%d\"\n",
+ str, opt->name, param->name, fmax);
+ return (NULL);
+ }
+ result = malloc(32);
+ snprintf(result, 32, "%f", f);
+ return (result);
+
+ case TYPE_STRING:
+ case TYPE_PASSWORD:
+ case TYPE_PASSCODE:
+ if (param->allowedchars &&
+ regexec(param->allowedchars, str, 0, NULL, 0) != 0)
+ {
+ _log("Custom string \"%s\" for \"%s\", parameter \"%s\" contains illegal characters.\n",
+ str, opt->name, param->name);
+ return (NULL);
+ }
+ if (param->allowedregexp &&
+ regexec(param->allowedregexp, str, 0, NULL, 0) != 0)
+ {
+ _log("Custom string \"%s\" for \"%s\", parameter \"%s\" does not match the allowed regexp.\n",
+ str, opt->name, param->name);
+ return (NULL);
+ }
+ len = strlen(str);
+ if (!isempty(param->min) && len < atoi(param->min))
+ {
+ _log("Custom value \"%s\" is too short for option \"%s\", parameter \"%s\".\n",
+ str, opt->name, param->name);
+ return (NULL);
+ }
+ if (!isempty(param->max) && len > atoi(param->max))
+ {
+ _log("Custom value \"%s\" is too long for option \"%s\", parameter \"%s\".\n",
+ str, opt->name, param->name);
+ return (NULL);
+ }
+ return (strdup(str));
+ }
+ return (NULL);
+}
+
+
+char *
+get_valid_param_string_int(option_t *opt,
+ param_t *param,
+ int value)
+{
+ char str[20];
+ snprintf(str, 20, "%d", value);
+ return (get_valid_param_string(opt, param, str));
+}
+
+
+char *
+get_valid_param_string_float(option_t *opt,
+ param_t *param,
+ float value)
+{
+ char str[20];
+ snprintf(str, 20, "%f", value);
+ return (get_valid_param_string(opt, param, str));
+}
+
+
+float
+convert_to_points(float f,
+ const char *unit)
+{
+ if (!strcasecmp(unit, "pt"))
+ return (roundf(f));
+ if (!strcasecmp(unit, "in"))
+ return (roundf(f * 72.0));
+ if (!strcasecmp(unit, "cm"))
+ return (roundf(f * 72.0 / 2.54));
+ if (!strcasecmp(unit, "mm"))
+ return (roundf(f * 72.0 / 25.4));
+
+ _log("Unknown unit: \"%s\"\n", unit);
+ return (roundf(f));
+}
+
+
+static char **
+paramvalues_from_string(option_t *opt,
+ const char *str)
+{
+ char **paramvalues;
+ int n, i;
+ param_t *param;
+ char *copy, *cur, *p;
+ float width, height;
+ char unit[3];
+
+ if (!strcmp(opt->name, "PageSize"))
+ {
+ if (startswith(str, "Custom."))
+ str = &str[7];
+ // 'unit' is optional, if it is not given, 'pt' is assumed
+ n = sscanf(str, "%fx%f%2s", &width, &height, unit);
+ if (n > 1)
+ {
+ if (n == 3)
+ {
+ width = convert_to_points(width, unit);
+ height = convert_to_points(height, unit);
+ }
+ paramvalues = calloc(opt->param_count, sizeof(char*));
+ for (param = opt->paramlist, i = 0; param; param = param->next, i++)
+ {
+ if (!strcasecmp(param->name, "width"))
+ paramvalues[i] = get_valid_param_string_int(opt, param, (int)width);
+ else if (!strcasecmp(param->name, "height"))
+ paramvalues[i] = get_valid_param_string_int(opt, param, (int)height);
+ else
+ paramvalues[i] = !isempty(param->min) ? param->min : "-999999";
+ if (!paramvalues[i])
+ {
+ free_paramvalues(opt, paramvalues);
+ return (NULL);
+ }
+ }
+ return (paramvalues);
+ }
+ }
+
+ if (opt->param_count == 1)
+ {
+ paramvalues = malloc(sizeof(char*));
+ paramvalues[0] =
+ get_valid_param_string(opt, opt->paramlist,
+ startswith(str, "Custom.") ? &str[7] : str);
+ if (!paramvalues[0])
+ {
+ free(paramvalues);
+ return (NULL);
+ }
+ }
+ else
+ {
+ if (!(p = strchr(str, '{')))
+ return (NULL);
+ paramvalues = calloc(opt->param_count, sizeof(char*));
+ copy = strdup(p +1);
+ for (cur = strtok(copy, " \t}"); cur; cur = strtok(NULL, " \t}"))
+ {
+ p = strchr(cur, '=');
+ if (!p)
+ continue;
+ *p++ = '\0';
+ if ((param = option_find_param_index(opt, cur, &i)))
+ paramvalues[i] = get_valid_param_string(opt, param, p);
+ else
+ _log("Could not find param \"%s\" for option \"%s\"\n",
+ cur, opt->name);
}
- if (idx)
- *idx = -1;
- return 0;
-}
+ free(copy);
-static choice_t * option_find_choice(option_t *opt, const char *name)
-{
- choice_t *choice;
- if (!opt || !name)
- return NULL;
- for (choice = opt->choicelist; choice; choice = choice->next) {
- if (!strcasecmp(choice->value, name))
- return choice;
+ // check if all params have been set
+ for (i = 0; i < opt->param_count; i++)
+ {
+ if (!paramvalues[i])
+ {
+ free_paramvalues(opt, paramvalues);
+ return (NULL);
+ }
+ }
+ }
+ return (paramvalues);
+}
+
+
+char *
+paramvalues_to_string(option_t *opt,
+ char **paramvalues)
+{
+ int i;
+ param_t *param;
+ dstr_t *res = create_dstr();
+ char *data;
+
+ if (opt->param_count < 1)
+ {
+ free (res);
+ return (NULL);
+ }
+
+ if (opt->param_count == 1)
+ {
+ param = opt->paramlist;
+ dstrcpyf(res, "Custom.%s", paramvalues[0]);
+ }
+ else
+ {
+ dstrcpyf(res, "{%s=%s", opt->paramlist->name, paramvalues[0]);
+ param = opt->paramlist->next;
+ i = 1;
+ while (param)
+ {
+ dstrcatf(res, " %s=%s", param->name, paramvalues[i]);
+ i++;
+ param = param->next;
}
- return NULL;
+ dstrcat(res, "}");
+ }
+ // only free dstr struct, NOT the string data
+ data = res->data;
+ free(res);
+ return (data);
}
-void free_paramvalues(option_t *opt, char **paramvalues)
+
+char *
+get_valid_value_string(option_t *opt,
+ const char *value)
{
- int i;
- if (!paramvalues)
- return;
- for (i = 0; i < opt->param_count; i++)
- free(paramvalues[i]);
- free(paramvalues);
-}
-
-char * get_valid_param_string(option_t *opt, param_t *param, const char *str)
-{
- char *result;
- int i, imin, imax;
- float f, fmin, fmax;
- size_t len;
-
- switch (param->type) {
- case TYPE_INT:
- i = atoi(str);
- imin = !isempty(param->min) ? atoi(param->min) : -999999;
- imax = !isempty(param->max) ? atoi(param->max) : 1000000;
- if (i < imin) {
- _log("Value \"%s\" for option \"%s\", parameter \"%s\" is smaller than the minimum value \"%d\"\n",
- str, opt->name, param->name, imin);
- return NULL;
- }
- else if (i > imax) {
- _log("Value \"%s\" for option \"%s\", parameter \"%s\" is larger than the maximum value \"%d\"\n",
- str, opt->name, param->name, imax);
- return NULL;
- }
- result = malloc(32);
- snprintf(result, 32, "%d", i);
- return result;
-
- case TYPE_FLOAT:
- case TYPE_CURVE:
- case TYPE_INVCURVE:
- case TYPE_POINTS:
- f = atof(str);
- fmin = !isempty(param->min) ? atof(param->min) : -999999.0;
- fmax = !isempty(param->max) ? atof(param->max) : 1000000.0;
- if (f < fmin) {
- _log("Value \"%s\" for option \"%s\", parameter \"%s\" is smaller than the minimum value \"%d\"\n",
- str, opt->name, param->name, fmin);
- return NULL;
- }
- else if (f > fmax) {
- _log("Value \"%s\" for option \"%s\", parameter \"%s\" is larger than the maximum value \"%d\"\n",
- str, opt->name, param->name, fmax);
- return NULL;
- }
- result = malloc(32);
- snprintf(result, 32, "%f", f);
- return result;
-
- case TYPE_STRING:
- case TYPE_PASSWORD:
- case TYPE_PASSCODE:
- if (param->allowedchars &&
- regexec(param->allowedchars, str, 0, NULL, 0) != 0) {
- _log("Custom string \"%s\" for \"%s\", parameter \"%s\" contains illegal characters.\n",
- str, opt->name, param->name);
- return NULL;
- }
- if (param->allowedregexp &&
- regexec(param->allowedregexp, str, 0, NULL, 0) != 0) {
- _log("Custom string \"%s\" for \"%s\", parameter \"%s\" does not match the allowed regexp.\n",
- str, opt->name, param->name);
- return NULL;
- }
- len = strlen(str);
- if (!isempty(param->min) && len < atoi(param->min)) {
- _log("Custom value \"%s\" is too short for option \"%s\", parameter \"%s\".\n",
- str, opt->name, param->name);
- return NULL;
- }
- if (!isempty(param->max) && len > atoi(param->max)) {
- _log("Custom value \"%s\" is too long for option \"%s\", parameter \"%s\".\n",
- str, opt->name, param->name);
- return NULL;
- }
- return strdup(str);
- }
- return NULL;
-}
-
-char * get_valid_param_string_int(option_t *opt, param_t *param, int value)
-{
- char str[20];
- snprintf(str, 20, "%d", value);
- return get_valid_param_string(opt, param, str);
-}
-
-char * get_valid_param_string_float(option_t *opt, param_t *param, float value)
-{
- char str[20];
- snprintf(str, 20, "%f", value);
- return get_valid_param_string(opt, param, str);
-}
-
-float convert_to_points(float f, const char *unit)
-{
- if (!strcasecmp(unit, "pt"))
- return roundf(f);
- if (!strcasecmp(unit, "in"))
- return roundf(f * 72.0);
- if (!strcasecmp(unit, "cm"))
- return roundf(f * 72.0 / 2.54);
- if (!strcasecmp(unit, "mm"))
- return roundf(f * 72.0 / 25.4);
-
- _log("Unknown unit: \"%s\"\n", unit);
- return roundf(f);
-}
-
-static char ** paramvalues_from_string(option_t *opt, const char *str)
-{
- char ** paramvalues;
- int n, i;
- param_t *param;
- char *copy, *cur, *p;
- float width, height;
- char unit[3];
-
- if (!strcmp(opt->name, "PageSize"))
- {
- if (startswith(str, "Custom."))
- str = &str[7];
- /* 'unit' is optional, if it is not given, 'pt' is assumed */
- n = sscanf(str, "%fx%f%2s", &width, &height, unit);
- if (n > 1) {
- if (n == 3) {
- width = convert_to_points(width, unit);
- height = convert_to_points(height, unit);
- }
- paramvalues = calloc(opt->param_count, sizeof(char*));
- for (param = opt->paramlist, i = 0; param; param = param->next, i++) {
- if (!strcasecmp(param->name, "width"))
- paramvalues[i] = get_valid_param_string_int(opt, param, (int)width);
- else if (!strcasecmp(param->name, "height"))
- paramvalues[i] = get_valid_param_string_int(opt, param, (int)height);
- else
- paramvalues[i] = !isempty(param->min) ? param->min : "-999999";
- if (!paramvalues[i]) {
- free_paramvalues(opt, paramvalues);
- return NULL;
- }
- }
- return paramvalues;
- }
- }
-
- if (opt->param_count == 1) {
- paramvalues = malloc(sizeof(char*));
- paramvalues[0] = get_valid_param_string(opt, opt->paramlist,
- startswith(str, "Custom.") ? &str[7] : str);
- if (!paramvalues[0]) {
- free(paramvalues);
- return NULL;
- }
- }
- else {
- if (!(p = strchr(str, '{')))
- return NULL;
- paramvalues = calloc(opt->param_count, sizeof(char*));
- copy = strdup(p +1);
- for (cur = strtok(copy, " \t}"); cur; cur = strtok(NULL, " \t}")) {
- p = strchr(cur, '=');
- if (!p)
- continue;
- *p++ = '\0';
- if ((param = option_find_param_index(opt, cur, &i)))
- paramvalues[i] = get_valid_param_string(opt, param, p);
- else
- _log("Could not find param \"%s\" for option \"%s\"\n",
- cur, opt->name);
- }
- free(copy);
-
- /* check if all params have been set */
- for (i = 0; i < opt->param_count; i++) {
- if (!paramvalues[i]) {
- free_paramvalues(opt, paramvalues);
- return NULL;
- }
- }
- }
- return paramvalues;
-}
-
-char * paramvalues_to_string(option_t *opt, char **paramvalues)
-{
- int i;
- param_t *param;
- dstr_t *res = create_dstr();
- char *data;
-
- if (opt->param_count < 1) {
- free (res);
- return NULL;
- }
-
- if (opt->param_count == 1) {
- param = opt->paramlist;
- dstrcpyf(res, "Custom.%s", paramvalues[0]);
- }
- else {
- dstrcpyf(res, "{%s=%s", opt->paramlist->name, paramvalues[0]);
- param = opt->paramlist->next;
- i = 1;
- while (param) {
- dstrcatf(res, " %s=%s", param->name, paramvalues[i]);
- i++;
- param = param->next;
- }
- dstrcat(res, "}");
- }
- /* only free dstr struct, NOT the string data */
- data = res->data;
- free(res);
- return data;
-}
-
-char * get_valid_value_string(option_t *opt, const char *value)
-{
- char *res;
- choice_t *choice;
- char **paramvalues;
-
- if (!value)
- return NULL;
-
- if (startswith(value, "From") && option_is_composite(find_option(&value[4])))
- return strdup(value);
-
- if (opt->type == TYPE_BOOL) {
- if (is_true_string(value))
- return strdup("1");
- else if (is_false_string(value))
- return strdup("0");
- else {
- _log("Could not interpret \"%s\" as boolean value for option \"%s\".\n", value, opt->name);
- return NULL;
- }
- }
+ char *res;
+ choice_t *choice;
+ char **paramvalues;
- /* Check if "value" is a predefined choice (except for "Custom", which is
- * not really a predefined choice, but an error if used without further
- * parameters) */
- if ((strcmp(value, "Custom") != 0 || strcmp(opt->name, "PageSize") == 0) &&
- (choice = option_find_choice(opt, value)))
- return strdup(choice->value);
+ if (!value)
+ return (NULL);
- if (opt->type == TYPE_ENUM) {
- if (!strcasecmp(value, "none"))
- return strdup("None");
+ if (startswith(value, "From") && option_is_composite(find_option(&value[4])))
+ return (strdup(value));
- /*
- * CUPS assumes that options with the choices "Yes", "No", "On", "Off",
- * "True", or "False" are boolean options and maps "-o Option=On" to
- * "-o Option" and "-o Option=Off" to "-o noOption", which foomatic-rip
- * maps to "0" and "1". So when "0" or "1" is unavailable in the
- * option, we try "Yes", "No", "On", "Off", "True", and "False".
- */
- if (is_true_string(value)) {
- for (choice = opt->choicelist; choice; choice = choice->next) {
- if (is_true_string(choice->value))
- return strdup(choice->value);
- }
- }
- else if (is_false_string(value)) {
- for (choice = opt->choicelist; choice; choice = choice->next) {
- if (is_false_string(choice->value))
- return strdup(choice->value);
- }
- }
+ if (opt->type == TYPE_BOOL)
+ {
+ if (is_true_string(value))
+ return (strdup("1"));
+ else if (is_false_string(value))
+ return (strdup("0"));
+ else
+ {
+ _log("Could not interpret \"%s\" as boolean value for option \"%s\".\n", value, opt->name);
+ return (NULL);
+ }
+ }
+
+ // Check if "value" is a predefined choice (except for "Custom", which is
+ // not really a predefined choice, but an error if used without further
+ // parameters)
+ if ((strcmp(value, "Custom") != 0 || strcmp(opt->name, "PageSize") == 0) &&
+ (choice = option_find_choice(opt, value)))
+ return (strdup(choice->value));
+
+ if (opt->type == TYPE_ENUM)
+ {
+ if (!strcasecmp(value, "none"))
+ return (strdup("None"));
+
+ //
+ // CUPS assumes that options with the choices "Yes", "No", "On", "Off",
+ // "True", or "False" are boolean options and maps "-o Option=On" to
+ // "-o Option" and "-o Option=Off" to "-o noOption", which foomatic-rip
+ // maps to "0" and "1". So when "0" or "1" is unavailable in the
+ // option, we try "Yes", "No", "On", "Off", "True", and "False".
+
+ if (is_true_string(value))
+ {
+ for (choice = opt->choicelist; choice; choice = choice->next)
+ {
+ if (is_true_string(choice->value))
+ return (strdup(choice->value));
+ }
}
-
- /* Custom value */
- if (opt->paramlist) {
- paramvalues = paramvalues_from_string(opt, value);
- if (paramvalues) {
- res = paramvalues_to_string(opt, paramvalues);
- free(paramvalues);
- return (startswith(res, "Custom.") ? strdup(&res[7]) : strdup(res));
- }
+ else if (is_false_string(value))
+ {
+ for (choice = opt->choicelist; choice; choice = choice->next)
+ {
+ if (is_false_string(choice->value))
+ return (strdup(choice->value));
+ }
+ }
+ }
+
+ // Custom value
+ if (opt->paramlist)
+ {
+ paramvalues = paramvalues_from_string(opt, value);
+ if (paramvalues)
+ {
+ res = paramvalues_to_string(opt, paramvalues);
+ free(paramvalues);
+ return (startswith(res, "Custom.") ? strdup(&res[7]) : strdup(res));
}
- else if (opt->foomatic_param)
- return get_valid_param_string(opt, opt->foomatic_param,
- startswith(value, "Custom.") ? &value[7] : value);
+ }
+ else if (opt->foomatic_param)
+ return (get_valid_param_string(opt, opt->foomatic_param,
+ startswith(value, "Custom.") ?
+ &value[7] : value));
- /* Return the default value */
- return NULL;
+ // Return the default value
+ return (NULL);
}
-/* Returns the current value for 'opt' in 'optionset'. */
-const char * option_get_value(option_t *opt, int optionset)
+
+// Returns the current value for 'opt' in 'optionset'.
+const char *
+option_get_value(option_t *opt, int optionset)
{
- value_t *val = option_find_value(opt, optionset);
- return val ? val->value : NULL;
+ value_t *val = option_find_value(opt, optionset);
+ return (val ? val->value : NULL);
}
-/* Returns non-zero if the foomatic prototype should be used for that
- * optionset, otherwise the custom_command will be used */
-int option_use_foomatic_prototype(option_t *opt)
+
+// Returns non-zero if the foomatic prototype should be used for that
+// optionset, otherwise the custom_command will be used
+int
+option_use_foomatic_prototype(option_t *opt)
{
- /* Only PostScript and JCL options can be CUPS custom options */
- if (!option_is_ps_command(opt) && !option_is_jcl_arg(opt))
- return 1;
+ // Only PostScript and JCL options can be CUPS custom options
+ if (!option_is_ps_command(opt) && !option_is_jcl_arg(opt))
+ return (1);
- /* if only one of them exists, take that one */
- if (opt->custom_command && !opt->proto)
- return 0;
- if (!opt->custom_command && opt->proto)
- return 1;
- return 0;
+ // if only one of them exists, take that one
+ if (opt->custom_command && !opt->proto)
+ return (0);
+ if (!opt->custom_command && opt->proto)
+ return (1);
+ return (0);
}
-void build_foomatic_custom_command(dstr_t *cmd, option_t *opt, const char *values)
+
+void
+build_foomatic_custom_command(dstr_t *cmd,
+ option_t *opt,
+ const char *values)
{
- if (!opt->proto && !strcmp(opt->name, "PageSize"))
- {
- choice_t *choice = option_find_choice(opt, "Custom");
- char **paramvalues = NULL;
- char width[30], height[30];
- int pos;
+ if (!opt->proto && !strcmp(opt->name, "PageSize"))
+ {
+ choice_t *choice = option_find_choice(opt, "Custom");
+ char **paramvalues = NULL;
+ char width[30], height[30];
+ int pos;
- if (!choice)
- return;
+ if (!choice)
+ return;
- paramvalues = paramvalues_from_string(opt, values);
+ paramvalues = paramvalues_from_string(opt, values);
- /* Get rid of the trailing ".00000", it confuses ghostscript */
- snprintf(width, 20, "%d", atoi(paramvalues[0]));
- snprintf(height, 20, "%d", atoi(paramvalues[1]));
+ // Get rid of the trailing ".00000", it confuses ghostscript
+ snprintf(width, 20, "%d", atoi(paramvalues[0]));
+ snprintf(height, 20, "%d", atoi(paramvalues[1]));
- dstrcpy(cmd, choice->command);
+ dstrcpy(cmd, choice->command);
- if ((pos = dstrreplace(cmd, "%0", width, 0)) < 0)
- pos = dstrreplace(cmd, "0", width, 0);
+ if ((pos = dstrreplace(cmd, "%0", width, 0)) < 0)
+ pos = dstrreplace(cmd, "0", width, 0);
- if (dstrreplace(cmd, "%1", height, pos) < 0)
- dstrreplace(cmd, "0", height, pos);
+ if (dstrreplace(cmd, "%1", height, pos) < 0)
+ dstrreplace(cmd, "0", height, pos);
- free_paramvalues(opt, paramvalues);
+ free_paramvalues(opt, paramvalues);
+ }
+ else
+ {
+ dstrcpy(cmd, opt->proto);
+ // use replace instead of printf-style because opt->proto could contain
+ // other format strings
+ dstrreplace(cmd, "%s", values, 0);
+ }
+}
+
+
+void
+build_cups_custom_ps_command(dstr_t *cmd, option_t *opt,
+ const char *values)
+{
+ param_t *param;
+ int i;
+ char **paramvalues = paramvalues_from_string(opt, values);
+
+ dstrclear(cmd);
+ for (param = opt->paramlist, i = 0; param; param = param->next, i++)
+ dstrcatf(cmd, "%s ", paramvalues[i]);
+ dstrcat(cmd, opt->custom_command);
+ free_paramvalues(opt, paramvalues);
+}
+
+
+void
+build_cups_custom_jcl_command(dstr_t *cmd,
+ option_t *opt,
+ const char *values)
+{
+ param_t *param;
+ int i;
+ char orderstr[8];
+ char **paramvalues = paramvalues_from_string(opt, values);
+
+ dstrcpy(cmd, opt->custom_command);
+ for (param = opt->paramlist, i = 0; param; param = param->next, i++)
+ {
+ snprintf(orderstr, 8, "\\%d", param->order);
+ dstrreplace(cmd, orderstr, paramvalues[i], 0);
+ }
+ free_paramvalues(opt, paramvalues);
+}
+
+
+int
+composite_get_command(dstr_t *cmd,
+ option_t *opt,
+ int optionset,
+ int section)
+{
+ char *copy, *cur, *p;
+ option_t *dep;
+ const char * valstr;
+ dstr_t *depcmd;
+
+ dstrclear(cmd);
+ if (!option_is_composite(opt))
+ return (0);
+
+ if (!(valstr = option_get_value(opt, optionset)))
+ return (0);
+
+ depcmd = create_dstr();
+ copy = strdup(valstr);
+ // Dependent options have been set to the right value in composite_set_values,
+ // so just find out which options depend on this composite and get their
+ // commands for "optionset" with option_get_command()
+ for (cur = strtok(copy, " \t"); cur; cur = strtok(NULL, " \t"))
+ {
+ dstrclear(depcmd);
+ if ((p = strchr(cur, '=')))
+ {
+ *p++ = '\0';
+ if ((dep = find_option(cur)))
+ option_get_command(depcmd, dep, optionset, section);
+ }
+ else if (startswith(cur, "no") || startswith(cur, "No"))
+ {
+ if ((dep = find_option(&cur[2])))
+ option_get_command(depcmd, dep, optionset, section);
}
else
{
- dstrcpy(cmd, opt->proto);
- /* use replace instead of printf-style because opt->proto could contain
- other format strings */
- dstrreplace(cmd, "%s", values, 0);
+ if ((dep = find_option(cur)))
+ option_get_command(depcmd, dep, optionset, section);
}
+ if (depcmd->len)
+ dstrcatf(cmd, "%s\n", depcmd->data);
+ }
+ free(copy);
+ free_dstr(depcmd);
+ return (cmd->len != 0);
}
-void build_cups_custom_ps_command(dstr_t *cmd, option_t *opt, const char *values)
-{
- param_t *param;
- int i;
- char **paramvalues = paramvalues_from_string(opt, values);
- dstrclear(cmd);
- for (param = opt->paramlist, i = 0; param; param = param->next, i++)
- dstrcatf(cmd, "%s ", paramvalues[i]);
- dstrcat(cmd, opt->custom_command);
- free_paramvalues(opt, paramvalues);
+int
+option_is_in_section(option_t *opt,
+ int section)
+{
+ if (opt->section == section)
+ return (1);
+ if (opt->section == SECTION_ANYSETUP &&
+ (section == SECTION_PAGESETUP || section == SECTION_DOCUMENTSETUP))
+ return (1);
+ return (0);
}
-void build_cups_custom_jcl_command(dstr_t *cmd, option_t *opt, const char *values)
+
+int
+option_is_custom_value(option_t *opt,
+ const char *value)
{
- param_t *param;
- int i;
- char orderstr[8];
- char **paramvalues = paramvalues_from_string(opt, values);
+ if (opt->type == TYPE_BOOL || opt->type == TYPE_ENUM)
+ return (0);
- dstrcpy(cmd, opt->custom_command);
- for (param = opt->paramlist, i = 0; param; param = param->next, i++) {
- snprintf(orderstr, 8, "\\%d", param->order);
- dstrreplace(cmd, orderstr, paramvalues[i], 0);
- }
- free_paramvalues(opt, paramvalues);
+ return (!option_has_choice(opt, value));
}
-int composite_get_command(dstr_t *cmd, option_t *opt, int optionset, int section)
-{
- char *copy, *cur, *p;
- option_t *dep;
- const char * valstr;
- dstr_t *depcmd;
-
- dstrclear(cmd);
- if (!option_is_composite(opt))
- return 0;
-
- if (!(valstr = option_get_value(opt, optionset)))
- return 0;
-
- depcmd = create_dstr();
- copy = strdup(valstr);
- /* Dependent options have been set to the right value in composite_set_values,
- so just find out which options depend on this composite and get their commands
- for "optionset" with option_get_command() */
- for (cur = strtok(copy, " \t"); cur; cur = strtok(NULL, " \t")) {
- dstrclear(depcmd);
- if ((p = strchr(cur, '='))) {
- *p++ = '\0';
- if ((dep = find_option(cur)))
- option_get_command(depcmd, dep, optionset, section);
- }
- else if (startswith(cur, "no") || startswith(cur, "No")) {
- if ((dep = find_option(&cur[2])))
- option_get_command(depcmd, dep, optionset, section);
- }
- else {
- if ((dep = find_option(cur)))
- option_get_command(depcmd, dep, optionset, section);
- }
- if (depcmd->len)
- dstrcatf(cmd, "%s\n", depcmd->data);
- }
- free(copy);
- free_dstr(depcmd);
- return cmd->len != 0;
-}
-int option_is_in_section(option_t *opt, int section)
+int
+option_get_command(dstr_t *cmd,
+ option_t *opt,
+ int optionset,
+ int section)
{
- if (opt->section == section)
- return 1;
- if (opt->section == SECTION_ANYSETUP && (section == SECTION_PAGESETUP || section == SECTION_DOCUMENTSETUP))
- return 1;
- return 0;
-}
+ const char *valstr;
+ choice_t *choice = NULL;
-int option_is_custom_value(option_t *opt, const char *value)
-{
- if (opt->type == TYPE_BOOL || opt->type == TYPE_ENUM)
- return 0;
+ dstrclear(cmd);
- return !option_has_choice(opt, value);
+ if (option_is_composite(opt))
+ return (composite_get_command(cmd, opt, optionset, section));
+
+ if (section >= 0 && !option_is_in_section(opt, section))
+ return (1); // empty command for this section
+
+ valstr = option_get_value(opt, optionset);
+ if (!valstr)
+ return (0);
+
+ // If the value is set to a predefined choice
+ choice = option_find_choice(opt, valstr);
+ if (choice && (*choice->command ||
+ ((opt->type != TYPE_INT) && (opt->type != TYPE_FLOAT))))
+ {
+ dstrcpy(cmd, choice->command);
+ return (1);
+ }
+
+ // Consider "None" as "not set" for enumerated choice options
+ if (opt->type == TYPE_ENUM && !strcasecmp(valstr, "None"))
+ return (0);
+
+ // Consider "None" as the empty string for string and password options
+ if ((opt->type == TYPE_STRING || opt->type == TYPE_PASSWORD) &&
+ !strcasecmp(valstr, "None"))
+ valstr = "";
+
+ // Custom value
+ if (option_use_foomatic_prototype(opt))
+ build_foomatic_custom_command(cmd, opt, valstr);
+ else
+ {
+ dstrcpy(cmd, opt->custom_command);
+ if ((option_get_section(opt) == SECTION_JCLSETUP) ||
+ (opt->style == 'J'))
+ build_cups_custom_jcl_command(cmd, opt, valstr);
+ else
+ build_cups_custom_ps_command(cmd, opt, valstr);
+ }
+
+ return (cmd->len != 0);
}
-int option_get_command(dstr_t *cmd, option_t *opt, int optionset, int section)
-{
- const char *valstr;
- choice_t *choice = NULL;
- dstrclear(cmd);
+void
+composite_set_values(option_t *opt,
+ int optionset,
+ const char *values)
+{
+ char *copy, *cur, *p;
+ option_t *dep;
+ value_t *val;
- if (option_is_composite(opt))
- return composite_get_command(cmd, opt, optionset, section);
-
- if (section >= 0 && !option_is_in_section(opt, section))
- return 1; /* empty command for this section */
-
- valstr = option_get_value(opt, optionset);
- if (!valstr)
- return 0;
-
- /* If the value is set to a predefined choice */
- choice = option_find_choice(opt, valstr);
- if (choice && (*choice->command ||
- ((opt->type != TYPE_INT) && (opt->type != TYPE_FLOAT)))) {
- dstrcpy(cmd, choice->command);
- return 1;
- }
-
- /* Consider "None" as "not set" for enumerated choice options */
- if (opt->type == TYPE_ENUM && !strcasecmp(valstr, "None"))
- return 0;
-
- /* Consider "None" as the empty string for string and password options */
- if ((opt->type == TYPE_STRING || opt->type == TYPE_PASSWORD) &&
- !strcasecmp(valstr, "None"))
- valstr = "";
-
- /* Custom value */
- if (option_use_foomatic_prototype(opt))
- build_foomatic_custom_command(cmd, opt, valstr);
- else {
- dstrcpy(cmd, opt->custom_command);
- if ((option_get_section(opt) == SECTION_JCLSETUP) ||
- (opt->style == 'J'))
- build_cups_custom_jcl_command(cmd, opt, valstr);
- else
- build_cups_custom_ps_command(cmd, opt, valstr);
- }
-
- return cmd->len != 0;
-}
-
-void composite_set_values(option_t *opt, int optionset, const char *values)
-{
- char *copy, *cur, *p;
- option_t *dep;
- value_t *val;
-
- copy = strdup(values);
- for (cur = strtok(copy, " \t"); cur; cur = strtok(NULL, " \t")) {
- if ((p = strchr(cur, '='))) {
- *p++ = '\0';
- if ((dep = find_option(cur))) {
- val = option_assure_value(dep, optionset);
- val->fromoption = opt;
- val->value = get_valid_value_string(dep, p);
- }
- else
- _log("Could not find option \"%s\" (set from composite \"%s\")", cur, opt->name);
- }
- else if (startswith(cur, "no") || startswith(cur, "No")) {
- if ((dep = find_option(&cur[2]))) {
- val = option_assure_value(dep, optionset);
- val->fromoption = opt;
- val->value = get_valid_value_string(dep, "0");
- }
- }
- else {
- if ((dep = find_option(cur))) {
- val = option_assure_value(dep, optionset);
- val->fromoption = opt;
- val->value = get_valid_value_string(dep, "1");
- }
- }
+ copy = strdup(values);
+ for (cur = strtok(copy, " \t"); cur; cur = strtok(NULL, " \t"))
+ {
+ if ((p = strchr(cur, '=')))
+ {
+ *p++ = '\0';
+ if ((dep = find_option(cur)))
+ {
+ val = option_assure_value(dep, optionset);
+ val->fromoption = opt;
+ val->value = get_valid_value_string(dep, p);
+ }
+ else
+ _log("Could not find option \"%s\" (set from composite \"%s\")",
+ cur, opt->name);
+ }
+ else if (startswith(cur, "no") || startswith(cur, "No"))
+ {
+ if ((dep = find_option(&cur[2])))
+ {
+ val = option_assure_value(dep, optionset);
+ val->fromoption = opt;
+ val->value = get_valid_value_string(dep, "0");
+ }
}
- free(copy);
+ else
+ {
+ if ((dep = find_option(cur)))
+ {
+ val = option_assure_value(dep, optionset);
+ val->fromoption = opt;
+ val->value = get_valid_value_string(dep, "1");
+ }
+ }
+ }
+ free(copy);
}
-int option_set_value(option_t *opt, int optionset, const char *value)
+
+int
+option_set_value(option_t *opt,
+ int optionset,
+ const char *value)
{
- value_t *val = option_assure_value(opt, optionset);
- char *newvalue;
- choice_t *choice;
- option_t *fromopt;
+ value_t *val = option_assure_value(opt, optionset);
+ char *newvalue;
+ choice_t *choice;
+ option_t *fromopt;
- newvalue = get_valid_value_string(opt, value);
- if (!newvalue)
- return 0;
+ newvalue = get_valid_value_string(opt, value);
+ if (!newvalue)
+ return (0);
- free(val->value);
- val->value = NULL;
+ free(val->value);
+ val->value = NULL;
- if (startswith(newvalue, "From") && (fromopt = find_option(&newvalue[4])) &&
- option_is_composite(fromopt)) {
- /* TODO only set the changed option, not all of them */
- choice = option_find_choice(fromopt,
- option_get_value(fromopt, optionset));
- composite_set_values(fromopt, optionset, choice->command);
- free(newvalue);
- } else
- val->value = newvalue;
+ if (startswith(newvalue, "From") && (fromopt = find_option(&newvalue[4])) &&
+ option_is_composite(fromopt))
+ {
+ // TODO only set the changed option, not all of them
+ choice = option_find_choice(fromopt,
+ option_get_value(fromopt, optionset));
+ composite_set_values(fromopt, optionset, choice->command);
+ free(newvalue);
+ }
+ else
+ val->value = newvalue;
- if (option_is_composite(opt)) {
- /* set dependent values */
- choice = option_find_choice(opt, value);
- if (choice && !isempty(choice->command))
- composite_set_values(opt, optionset, choice->command);
- }
- return 1;
+ if (option_is_composite(opt))
+ {
+ // set dependent values
+ choice = option_find_choice(opt, value);
+ if (choice && !isempty(choice->command))
+ composite_set_values(opt, optionset, choice->command);
+ }
+ return (1);
}
-int option_accepts_value(option_t *opt, const char *value)
+
+int
+option_accepts_value(option_t *opt,
+ const char *value)
{
- char *val = get_valid_value_string(opt, value);
- if (!val)
- return 0;
- free(val);
- return 1;
+ char *val = get_valid_value_string(opt, value);
+ if (!val)
+ return (0);
+ free(val);
+ return (1);
}
-int option_has_choice(option_t *opt, const char *choice)
+
+int
+option_has_choice(option_t *opt,
+ const char *choice)
{
- return option_find_choice(opt, choice) != NULL;
+ return (option_find_choice(opt, choice) != NULL);
}
-const char * option_text(option_t *opt)
+
+const char *
+option_text(option_t *opt)
{
- if (isempty(opt->text))
- return opt->text;
- return opt->text;
+ if (isempty(opt->text))
+ return (opt->text);
+ return (opt->text);
}
-int option_type(option_t *opt)
+
+int
+option_type(option_t *opt)
{
- return opt->type;
+ return (opt->type);
}
-void option_set_order(option_t *opt, double order)
+
+void
+option_set_order(option_t *opt,
+ double order)
{
- option_t *prev;
+ option_t *prev;
- /* remove opt from old position */
- if (opt == optionlist_sorted_by_order)
- optionlist_sorted_by_order = opt->next_by_order;
- else {
- for (prev = optionlist_sorted_by_order;
- prev && prev->next_by_order != opt;
- prev = prev->next_by_order);
- prev->next_by_order = opt->next_by_order;
- }
+ // remove opt from old position
+ if (opt == optionlist_sorted_by_order)
+ optionlist_sorted_by_order = opt->next_by_order;
+ else
+ {
+ for (prev = optionlist_sorted_by_order;
+ prev && prev->next_by_order != opt;
+ prev = prev->next_by_order);
+ prev->next_by_order = opt->next_by_order;
+ }
- opt->order = order;
+ opt->order = order;
- /* insert into new position */
- if (!optionlist_sorted_by_order)
- optionlist_sorted_by_order = opt;
- else if (optionlist_sorted_by_order->order > opt->order) {
- opt->next_by_order = optionlist_sorted_by_order;
- optionlist_sorted_by_order = opt;
- }
- else {
- for (prev = optionlist_sorted_by_order;
- prev->next_by_order && prev->next_by_order->order < opt->order;
- prev = prev->next_by_order);
- opt->next_by_order = prev->next_by_order;
- prev->next_by_order = opt;
- }
-}
-
-/* Set option from *FoomaticRIPOption keyword */
-void option_set_from_string(option_t *opt, const char *str)
-{
- char type[32], style[32];
- double order;
- int matches;
-
- matches = sscanf(str, "%31s %31s %c %lf", type, style, &opt->spot, &order);
- if (matches < 3) {
- _log("Can't read the value of *FoomaticRIPOption for \"%s\"", opt->name);
- return;
- }
- opt->type = type_from_string(type);
- opt->style = style_from_string(style);
-
- if (matches == 4)
- option_set_order(opt, order);
-}
-
-static choice_t * option_assure_choice(option_t *opt, const char *name)
-{
- choice_t *choice, *last = NULL;
-
- for (choice = opt->choicelist; choice; choice = choice->next) {
- if (!strcasecmp(choice->value, name))
- return choice;
- last = choice;
- }
- if (!choice) {
- choice = calloc(1, sizeof(choice_t));
- if (last)
- last->next = choice;
- else
- opt->choicelist = choice;
- strlcpy(choice->value, name, 128);
- }
- return choice;
-}
-
-static void unhtmlify(char *dest, size_t size, const char *src)
-{
- jobparams_t *job = get_current_job();
- char *pdest = dest;
- const char *psrc = src, *p = NULL;
- const char *repl;
- struct tm *t = localtime(&job->time);
- char tmpstr[16];
- size_t s, l, n;
-
- while (*psrc && pdest - dest < size - 1) {
-
- if (*psrc == '&') {
- psrc++;
- repl = NULL;
- p = NULL;
- l = 0;
-
- /* Replace HTML/XML entities by the original characters */
- if (!prefixcmp(psrc, "apos")) {
- repl = "\'";
- p = psrc + 4;
- } else if (!prefixcmp(psrc, "quot")) {
- repl = "\"";
- p = psrc + 4;
- } else if (!prefixcmp(psrc, "gt")) {
- repl = ">";
- p = psrc + 2;
- } else if (!prefixcmp(psrc, "lt")) {
- repl = "<";
- p = psrc + 2;
- } else if (!prefixcmp(psrc, "amp")) {
- repl = "&";
- p = psrc + 3;
-
- /* Replace special entities by job->data */
- } else if (!prefixcmp(psrc, "job")) {
- repl = job->id;
- p = psrc + 3;
- if (jobentitymaxlen != 0)
- l = jobentitymaxlen;
- } else if (!prefixcmp(psrc, "user")) {
- repl = job->user;
- p = psrc + 4;
- if (userentitymaxlen != 0)
- l = userentitymaxlen;
- } else if (!prefixcmp(psrc, "host")) {
- repl = job->host;
- p = psrc + 4;
- if (hostentitymaxlen != 0)
- l = hostentitymaxlen;
- } else if (!prefixcmp(psrc, "title")) {
- repl = job->title;
- p = psrc + 5;
- if (titleentitymaxlen != 0)
- l = titleentitymaxlen;
- } else if (!prefixcmp(psrc, "copies")) {
- repl = job->copies;
- p = psrc + 6;
- } else if (!prefixcmp(psrc, "rbinumcopies")) {
- if (job->rbinumcopies > 0) {
- snprintf(tmpstr, 16, "%d", job->rbinumcopies);
- repl = tmpstr;
- }
- else
- repl = job->copies;
- p = psrc + 12;
- }
- else if (!prefixcmp(psrc, "options")) {
- repl = job->optstr->data;
- p = psrc + 7;
- if (optionsentitymaxlen != 0)
- l = optionsentitymaxlen;
- } else if (!prefixcmp(psrc, "year")) {
- sprintf(tmpstr, "%04d", t->tm_year + 1900);
- repl = tmpstr;
- p = psrc + 4;
- }
- else if (!prefixcmp(psrc, "month")) {
- sprintf(tmpstr, "%02d", t->tm_mon + 1);
- repl = tmpstr;
- p = psrc + 5;
- }
- else if (!prefixcmp(psrc, "date")) {
- sprintf(tmpstr, "%02d", t->tm_mday);
- repl = tmpstr;
- p = psrc + 4;
- }
- else if (!prefixcmp(psrc, "hour")) {
- sprintf(tmpstr, "%02d", t->tm_hour);
- repl = tmpstr;
- p = psrc + 4;
- }
- else if (!prefixcmp(psrc, "min")) {
- sprintf(tmpstr, "%02d", t->tm_min);
- repl = tmpstr;
- p = psrc + 3;
- }
- else if (!prefixcmp(psrc, "sec")) {
- sprintf(tmpstr, "%02d", t->tm_sec);
- repl = tmpstr;
- p = psrc + 3;
- }
- if (p) {
- n = strtol(p, (char **)(&p), 0);
- if (n != 0)
- l = n;
- if (*p != ';')
- repl = NULL;
- } else
- repl = NULL;
- if (repl) {
- if ((l == 0) || (l > strlen(repl)))
- l = strlen(repl);
- s = size - (pdest - dest) - 1;
- strncpy(pdest, repl, s);
- if (s < l)
- pdest += s;
- else
- pdest += l;
- psrc = p + 1;
- }
- else {
- *pdest = '&';
- pdest++;
- }
- }
- else {
- *pdest = *psrc;
- pdest++;
- psrc++;
- }
- }
- *pdest = '\0';
-}
-
-/*
- * Checks whether 'code' contains active PostScript, i.e. not only comments
- */
-static int contains_active_postscript(const char *code)
-{
- char **line, **lines;
- int contains_ps = 0;
-
- if (!(lines = argv_split(code, "\n", NULL)))
- return 0;
-
- for (line = lines; *line && !contains_ps; line++)
- contains_ps = !isempty(*line) &&
- !startswith(skip_whitespace(*line), "%");
-
- argv_free(lines);
- return contains_ps;
-}
-
-void option_set_choice(option_t *opt, const char *name, const char *text,
- const char *code)
+ // insert into new position
+ if (!optionlist_sorted_by_order)
+ optionlist_sorted_by_order = opt;
+ else if (optionlist_sorted_by_order->order > opt->order)
+ {
+ opt->next_by_order = optionlist_sorted_by_order;
+ optionlist_sorted_by_order = opt;
+ }
+ else
+ {
+ for (prev = optionlist_sorted_by_order;
+ prev->next_by_order && prev->next_by_order->order < opt->order;
+ prev = prev->next_by_order);
+ opt->next_by_order = prev->next_by_order;
+ prev->next_by_order = opt;
+ }
+}
+
+
+// Set option from *FoomaticRIPOption keyword
+void
+option_set_from_string(option_t *opt,
+ const char *str)
{
- choice_t *choice;
+ char type[32], style[32];
+ double order;
+ int matches;
- if (opt->type == TYPE_BOOL) {
- if (is_true_string(name))
- choice = option_assure_choice(opt, "1");
- else
- choice = option_assure_choice(opt, "0");
- }
+ matches = sscanf(str, "%31s %31s %c %lf", type, style, &opt->spot, &order);
+ if (matches < 3)
+ {
+ _log("Can't read the value of *FoomaticRIPOption for \"%s\"", opt->name);
+ return;
+ }
+ opt->type = type_from_string(type);
+ opt->style = style_from_string(style);
+
+ if (matches == 4)
+ option_set_order(opt, order);
+}
+
+
+static choice_t *
+option_assure_choice(option_t *opt,
+ const char *name)
+{
+ choice_t *choice, *last = NULL;
+
+ for (choice = opt->choicelist; choice; choice = choice->next)
+ {
+ if (!strcasecmp(choice->value, name))
+ return (choice);
+ last = choice;
+ }
+ if (!choice)
+ {
+ choice = calloc(1, sizeof(choice_t));
+ if (last)
+ last->next = choice;
else
- choice = option_assure_choice(opt, name);
+ opt->choicelist = choice;
+ strlcpy(choice->value, name, 128);
+ }
+ return (choice);
+}
- if (text)
- strlcpy(choice->text, text, 128);
- if (!code)
+static void
+unhtmlify(char *dest,
+ size_t size,
+ const char *src)
+{
+ jobparams_t *job = get_current_job();
+ char *pdest = dest;
+ const char *psrc = src, *p = NULL;
+ const char *repl;
+ struct tm *t = localtime(&job->time);
+ char tmpstr[16];
+ size_t s, l, n;
+
+ while (*psrc && pdest - dest < size - 1)
+ {
+ if (*psrc == '&')
+ {
+ psrc++;
+ repl = NULL;
+ p = NULL;
+ l = 0;
+
+ // Replace HTML/XML entities by the original characters
+ if (!prefixcmp(psrc, "apos"))
+ {
+ repl = "\'";
+ p = psrc + 4;
+ }
+ else if (!prefixcmp(psrc, "quot"))
+ {
+ repl = "\"";
+ p = psrc + 4;
+ }
+ else if (!prefixcmp(psrc, "gt"))
+ {
+ repl = ">";
+ p = psrc + 2;
+ }
+ else if (!prefixcmp(psrc, "lt"))
+ {
+ repl = "<";
+ p = psrc + 2;
+ }
+ else if (!prefixcmp(psrc, "amp"))
+ {
+ repl = "&";
+ p = psrc + 3;
+ }
+ // Replace special entities by job->data
+ else if (!prefixcmp(psrc, "job"))
+ {
+ repl = job->id;
+ p = psrc + 3;
+ if (jobentitymaxlen != 0)
+ l = jobentitymaxlen;
+ }
+ else if (!prefixcmp(psrc, "user"))
+ {
+ repl = job->user;
+ p = psrc + 4;
+ if (userentitymaxlen != 0)
+ l = userentitymaxlen;
+ }
+ else if (!prefixcmp(psrc, "host"))
+ {
+ repl = job->host;
+ p = psrc + 4;
+ if (hostentitymaxlen != 0)
+ l = hostentitymaxlen;
+ }
+ else if (!prefixcmp(psrc, "title"))
+ {
+ repl = job->title;
+ p = psrc + 5;
+ if (titleentitymaxlen != 0)
+ l = titleentitymaxlen;
+ }
+ else if (!prefixcmp(psrc, "copies"))
+ {
+ repl = job->copies;
+ p = psrc + 6;
+ }
+ else if (!prefixcmp(psrc, "rbinumcopies"))
+ {
+ if (job->rbinumcopies > 0)
+ {
+ snprintf(tmpstr, 16, "%d", job->rbinumcopies);
+ repl = tmpstr;
+ }
+ else
+ repl = job->copies;
+ p = psrc + 12;
+ }
+ else if (!prefixcmp(psrc, "options"))
+ {
+ repl = job->optstr->data;
+ p = psrc + 7;
+ if (optionsentitymaxlen != 0)
+ l = optionsentitymaxlen;
+ }
+ else if (!prefixcmp(psrc, "year"))
+ {
+ sprintf(tmpstr, "%04d", t->tm_year + 1900);
+ repl = tmpstr;
+ p = psrc + 4;
+ }
+ else if (!prefixcmp(psrc, "month"))
+ {
+ sprintf(tmpstr, "%02d", t->tm_mon + 1);
+ repl = tmpstr;
+ p = psrc + 5;
+ }
+ else if (!prefixcmp(psrc, "date"))
+ {
+ sprintf(tmpstr, "%02d", t->tm_mday);
+ repl = tmpstr;
+ p = psrc + 4;
+ }
+ else if (!prefixcmp(psrc, "hour"))
+ {
+ sprintf(tmpstr, "%02d", t->tm_hour);
+ repl = tmpstr;
+ p = psrc + 4;
+ }
+ else if (!prefixcmp(psrc, "min"))
+ {
+ sprintf(tmpstr, "%02d", t->tm_min);
+ repl = tmpstr;
+ p = psrc + 3;
+ }
+ else if (!prefixcmp(psrc, "sec"))
+ {
+ sprintf(tmpstr, "%02d", t->tm_sec);
+ repl = tmpstr;
+ p = psrc + 3;
+ }
+ if (p)
+ {
+ n = strtol(p, (char **)(&p), 0);
+ if (n != 0)
+ l = n;
+ if (*p != ';')
+ repl = NULL;
+ }
+ else
+ repl = NULL;
+ if (repl)
+ {
+ if ((l == 0) || (l > strlen(repl)))
+ l = strlen(repl);
+ s = size - (pdest - dest) - 1;
+ strncpy(pdest, repl, s);
+ if (s < l)
+ pdest += s;
+ else
+ pdest += l;
+ psrc = p + 1;
+ }
+ else
+ {
+ *pdest = '&';
+ pdest++;
+ }
+ }
+ else
{
- _log("Warning: No code for choice \"%s\" of option \"%s\"\n",
- choice->text, opt->name);
- return;
+ *pdest = *psrc;
+ pdest++;
+ psrc++;
}
+ }
+ *pdest = '\0';
+}
+
+
+//
+// Checks whether 'code' contains active PostScript, i.e. not only comments
+//
- if (!startswith(code, "%% FoomaticRIPOptionSetting"))
- unhtmlify(choice->command, 65536, code);
+static int
+contains_active_postscript(const char *code)
+{
+ char **line, **lines;
+ int contains_ps = 0;
+
+ if (!(lines = argv_split(code, "\n", NULL)))
+ return (0);
+
+ for (line = lines; *line && !contains_ps; line++)
+ contains_ps = !isempty(*line) &&
+ !startswith(skip_whitespace(*line), "%");
+
+ argv_free(lines);
+ return (contains_ps);
}
-/*
- * Parameters
- */
-int param_set_allowed_chars(param_t *param, const char *value)
+void
+option_set_choice(option_t *opt,
+ const char *name,
+ const char *text,
+ const char *code)
{
- char rxstr[256], tmp[128];
+ choice_t *choice;
- param->allowedchars = malloc(sizeof(regex_t));
- unhtmlify(tmp, 128, value);
- snprintf(rxstr, 256, "^[%s]*$", tmp);
- if (regcomp(param->allowedchars, rxstr, 0) != 0) {
- regfree(param->allowedchars);
- param->allowedchars = NULL;
- return 0;
- }
- return 1;
+ if (opt->type == TYPE_BOOL)
+ {
+ if (is_true_string(name))
+ choice = option_assure_choice(opt, "1");
+ else
+ choice = option_assure_choice(opt, "0");
+ }
+ else
+ choice = option_assure_choice(opt, name);
+
+ if (text)
+ strlcpy(choice->text, text, 128);
+
+ if (!code)
+ {
+ _log("Warning: No code for choice \"%s\" of option \"%s\"\n",
+ choice->text, opt->name);
+ return;
+ }
+
+ if (!startswith(code, "%% FoomaticRIPOptionSetting"))
+ unhtmlify(choice->command, 65536, code);
}
-int param_set_allowed_regexp(param_t *param, const char *value)
+//
+// Parameters
+//
+
+int
+param_set_allowed_chars(param_t *param,
+ const char *value)
{
- char tmp[128];
+ char rxstr[256], tmp[128];
- param->allowedregexp = malloc(sizeof(regex_t));
- unhtmlify(tmp, 128, value);
- if (regcomp(param->allowedregexp, tmp, 0) != 0) {
- regfree(param->allowedregexp);
- param->allowedregexp = NULL;
- return 0;
- }
- return 1;
+ param->allowedchars = malloc(sizeof(regex_t));
+ unhtmlify(tmp, 128, value);
+ snprintf(rxstr, 256, "^[%s]*$", tmp);
+ if (regcomp(param->allowedchars, rxstr, 0) != 0)
+ {
+ regfree(param->allowedchars);
+ param->allowedchars = NULL;
+ return (0);
+ }
+ return (1);
}
-void option_set_custom_command(option_t *opt, const char *cmd)
+
+int
+param_set_allowed_regexp(param_t *param,
+ const char *value)
{
- size_t len = strlen(cmd) + 50;
- free(opt->custom_command);
- opt->custom_command = malloc(len);
- unhtmlify(opt->custom_command, len, cmd);
+ char tmp[128];
+
+ param->allowedregexp = malloc(sizeof(regex_t));
+ unhtmlify(tmp, 128, value);
+ if (regcomp(param->allowedregexp, tmp, 0) != 0)
+ {
+ regfree(param->allowedregexp);
+ param->allowedregexp = NULL;
+ return (0);
+ }
+ return (1);
}
-param_t * option_add_custom_param_from_string(option_t *opt,
- const char *name, const char *text, const char *str)
+
+void
+option_set_custom_command(option_t *opt,
+ const char *cmd)
{
- param_t *param = calloc(1, sizeof(param_t));
- param_t *p;
- char typestr[33];
- int n;
+ size_t len = strlen(cmd) + 50;
+ free(opt->custom_command);
+ opt->custom_command = malloc(len);
+ unhtmlify(opt->custom_command, len, cmd);
+}
- strlcpy(param->name, name, 128);
- strlcpy(param->text, text, 128);
- n = sscanf(str, "%d%15s%19s%19s",
- ¶m->order, typestr, param->min, param->max);
+param_t *
+option_add_custom_param_from_string(option_t *opt,
+ const char *name,
+ const char *text,
+ const char *str)
+{
+ param_t *param = calloc(1, sizeof(param_t));
+ param_t *p;
+ char typestr[33];
+ int n;
- if (n != 4) {
- _log("Could not parse custom parameter for '%s'!\n", opt->name);
- free(param);
- return NULL;
- }
+ strlcpy(param->name, name, 128);
+ strlcpy(param->text, text, 128);
- if (!strcmp(typestr, "curve"))
- param->type = TYPE_CURVE;
- else if (!strcmp(typestr, "invcurve"))
- param->type = TYPE_INVCURVE;
- else if (!strcmp(typestr, "int"))
- param->type = TYPE_INT;
- else if (!strcmp(typestr, "real"))
- param->type = TYPE_FLOAT;
- else if (!strcmp(typestr, "passcode"))
- param->type = TYPE_PASSCODE;
- else if (!strcmp(typestr, "password"))
- param->type = TYPE_PASSWORD;
- else if (!strcmp(typestr, "points"))
- param->type = TYPE_POINTS;
- else if (!strcmp(typestr, "string"))
- param->type = TYPE_STRING;
- else {
- _log("Unknown custom parameter type for param '%s' for option '%s'\n", param->name, opt->name);
- free(param);
- return NULL;
- }
+ n = sscanf(str, "%d%15s%19s%19s",
+ ¶m->order, typestr, param->min, param->max);
- param->next = NULL;
+ if (n != 4)
+ {
+ _log("Could not parse custom parameter for '%s'!\n", opt->name);
+ free(param);
+ return (NULL);
+ }
+
+ if (!strcmp(typestr, "curve"))
+ param->type = TYPE_CURVE;
+ else if (!strcmp(typestr, "invcurve"))
+ param->type = TYPE_INVCURVE;
+ else if (!strcmp(typestr, "int"))
+ param->type = TYPE_INT;
+ else if (!strcmp(typestr, "real"))
+ param->type = TYPE_FLOAT;
+ else if (!strcmp(typestr, "passcode"))
+ param->type = TYPE_PASSCODE;
+ else if (!strcmp(typestr, "password"))
+ param->type = TYPE_PASSWORD;
+ else if (!strcmp(typestr, "points"))
+ param->type = TYPE_POINTS;
+ else if (!strcmp(typestr, "string"))
+ param->type = TYPE_STRING;
+ else
+ {
+ _log("Unknown custom parameter type for param '%s' for option '%s'\n", param->name, opt->name);
+ free(param);
+ return (NULL);
+ }
- /* Insert param into opt->paramlist, sorted by order */
- if (!opt->paramlist)
- opt->paramlist = param;
- else if (opt->paramlist->order > param->order) {
- param->next = opt->paramlist;
- opt->paramlist = param;
- }
- else {
- for (p = opt->paramlist;
- p->next && p->next->order < param->order;
- p = p->next);
- param->next = p->next;
- p->next = param;
- }
+ param->next = NULL;
+
+ // Insert param into opt->paramlist, sorted by order
+ if (!opt->paramlist)
+ opt->paramlist = param;
+ else if (opt->paramlist->order > param->order)
+ {
+ param->next = opt->paramlist;
+ opt->paramlist = param;
+ }
+ else
+ {
+ for (p = opt->paramlist;
+ p->next && p->next->order < param->order;
+ p = p->next);
+ param->next = p->next;
+ p->next = param;
+ }
- opt->param_count++;
- return param;
+ opt->param_count++;
+ return (param);
}
-param_t * option_assure_foomatic_param(option_t *opt)
+
+param_t *
+option_assure_foomatic_param(option_t *opt)
{
- param_t *param;
+ param_t *param;
- if (opt->foomatic_param)
- return opt->foomatic_param;
+ if (opt->foomatic_param)
+ return (opt->foomatic_param);
- param = calloc(1, sizeof(param_t));
- strcpy(param->name, "foomatic-param");
- param->order = 0;
- param->type = opt->type;
+ param = calloc(1, sizeof(param_t));
+ strcpy(param->name, "foomatic-param");
+ param->order = 0;
+ param->type = opt->type;
- opt->foomatic_param = param;
- return param;
+ opt->foomatic_param = param;
+ return (param);
}
-/*
- * Optionsets
- */
+//
+// Optionsets
+//
-const char * optionset_name(int idx)
+const char *
+optionset_name(int idx)
{
- if (idx < 0 || idx >= optionset_count) {
- _log("Optionset with index %d does not exist\n", idx);
- return NULL;
- }
- return optionsets[idx];
+ if (idx < 0 || idx >= optionset_count)
+ {
+ _log("Optionset with index %d does not exist\n", idx);
+ return (NULL);
+ }
+ return (optionsets[idx]);
}
-int optionset(const char * name)
+
+int
+optionset(const char *name)
{
- int i;
+ int i;
- for (i = 0; i < optionset_count; i++) {
- if (!strcmp(optionsets[i], name))
- return i;
- }
+ for (i = 0; i < optionset_count; i ++)
+ {
+ if (!strcmp(optionsets[i], name))
+ return (i);
+ }
- if (optionset_count == optionset_alloc) {
- optionset_alloc *= 2;
- optionsets = realloc(optionsets, optionset_alloc * sizeof(char *));
- for (i = optionset_count; i < optionset_alloc; i++)
- optionsets[i] = NULL;
- }
+ if (optionset_count == optionset_alloc)
+ {
+ optionset_alloc *= 2;
+ optionsets = realloc(optionsets, optionset_alloc * sizeof(char *));
+ for (i = optionset_count; i < optionset_alloc; i++)
+ optionsets[i] = NULL;
+ }
- optionsets[optionset_count] = strdup(name);
- optionset_count++;
- return optionset_count -1;
+ optionsets[optionset_count] = strdup(name);
+ optionset_count++;
+ return (optionset_count - 1);
}
-void optionset_copy_values(int src_optset, int dest_optset)
+
+void
+optionset_copy_values(int src_optset,
+ int dest_optset)
{
- option_t *opt;
- value_t *val;
+ option_t *opt;
+ value_t *val;
- for (opt = optionlist; opt; opt = opt->next) {
- for (val = opt->valuelist; val; val = val->next) {
- if (val->optionset == src_optset) {
- option_set_value(opt, dest_optset, val->value);
- break;
- }
- }
+ for (opt = optionlist; opt; opt = opt->next)
+ {
+ for (val = opt->valuelist; val; val = val->next)
+ {
+ if (val->optionset == src_optset)
+ {
+ option_set_value(opt, dest_optset, val->value);
+ break;
+ }
}
+ }
}
-void optionset_delete_values(int optionset)
+
+void
+optionset_delete_values(int optionset)
{
- option_t *opt;
- value_t *val, *prev_val;
+ option_t *opt;
+ value_t *val, *prev_val;
- for (opt = optionlist; opt; opt = opt->next) {
- val = opt->valuelist;
- prev_val = NULL;
- while (val) {
- if (val->optionset == optionset) {
- if (prev_val)
- prev_val->next = val->next;
- else
- opt->valuelist = val->next;
- free_value(val);
- val = prev_val ? prev_val->next : opt->valuelist;
- break;
- } else {
- prev_val = val;
- val = val->next;
- }
- }
+ for (opt = optionlist; opt; opt = opt->next)
+ {
+ val = opt->valuelist;
+ prev_val = NULL;
+ while (val)
+ {
+ if (val->optionset == optionset)
+ {
+ if (prev_val)
+ prev_val->next = val->next;
+ else
+ opt->valuelist = val->next;
+ free_value(val);
+ val = prev_val ? prev_val->next : opt->valuelist;
+ break;
+ }
+ else
+ {
+ prev_val = val;
+ val = val->next;
+ }
}
+ }
}
-int optionset_equal(int optset1, int optset2, int exceptPS)
+
+int
+optionset_equal(int optset1,
+ int optset2,
+ int exceptPS)
{
- option_t *opt;
- const char *val1, *val2;
+ option_t *opt;
+ const char *val1, *val2;
- for (opt = optionlist; opt; opt = opt->next) {
- if (exceptPS && opt->style == 'G')
- continue;
+ for (opt = optionlist; opt; opt = opt->next)
+ {
+ if (exceptPS && opt->style == 'G')
+ continue;
- val1 = option_get_value(opt, optset1);
- val2 = option_get_value(opt, optset2);
-
- if (val1 && val2) { /* both entries exist */
- if (strcmp(val1, val2) != 0)
- return 0; /* but aren't equal */
- }
- else if (val1 || val2) /* one entry exists --> can't be equal */
- return 0;
- /* If no extry exists, the non-existing entries
- * are considered as equal */
- }
- return 1;
-}
-
-/*
- * read_ppd_file()
- */
-void read_ppd_file(const char *filename)
-{
- FILE *fh;
- const char *tmp;
- char *icc_qual2 = NULL;
- char *icc_qual3 = NULL;
- char line [256]; /* PPD line length is max 255 (excl. \0) */
- char *p;
- char key[128], name[64], text[64];
- dstr_t *value = create_dstr(); /* value can span multiple lines */
- double order;
- value_t *val;
- option_t *opt, *current_opt = NULL;
- param_t *param;
- icc_mapping_entry_t *entry;
-
- fh = fopen(filename, "r");
- if (!fh)
- rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Unable to open PPD file %s\n", filename);
- _log("Parsing PPD file ...\n");
-
- dstrassure(value, 256);
-
- qualifier_data = list_create();
- while (!feof(fh)) {
- tmp = fgets(line, 256, fh);
-
- if (line[0] != '*' || startswith(line, "*%"))
- continue;
-
- /* get the key */
- if (!(p = strchr(line, ':')))
- continue;
- *p = '\0';
-
- key[0] = name[0] = text[0] = '\0';
- sscanf(line, "*%127s%*[ \t]%63[^ \t/=)]%*1[/=]%63[^\n]", key, name, text);
-
- /* get the value */
- dstrclear(value);
- sscanf(p +1, " %255[^\r\n]", value->data);
- value->len = strlen(value->data);
- if (!value->len)
- _log("PPD: Missing value for key \"%s\"\n", line);
-
- while (1) {
- /* "&&" is the continue-on-next-line marker */
- if (dstrendswith(value, "&&")) {
- value->len -= 2;
- value->data[value->len] = '\0';
- }
- /* quoted but quotes are not yet closed */
- else if (value->data[0] == '\"' && !strchr(value->data +1, '\"'))
- dstrcat(value, "\n"); /* keep newlines in quoted string*/
- /* not quoted, or quotes already closed */
- else
- break;
-
- tmp = fgets(line, 256, fh);
- dstrcat(value, line);
- dstrremovenewline(value);
- }
-
- /* remove quotes */
- if (value->data[0] == '\"') {
- memmove(value->data, value->data +1, value->len +1);
- p = strrchr(value->data, '\"');
- if (!p) {
- _log("Invalid line: \"%s: ...\"\n", key);
- continue;
- }
- *p = '\0';
- }
- /* remove last newline */
- dstrremovenewline(value);
-
- /* remove last whitespace */
- dstrtrim_right(value);
-
- /* process key/value pairs */
- if (strcmp(key, "NickName") == 0) {
- unhtmlify(printer_model, 256, value->data);
- }
- else if (strcmp(key, "FoomaticIDs") == 0) {
- /* *FoomaticIDs: <printer ID> <driver ID> */
- sscanf(value->data, "%*[ \t]%127[^ \t]%*[ \t]%127[^ \t\n]",
- printer_id, driver);
- }
- else if (strcmp(key, "FoomaticRIPPostPipe") == 0) {
- if (!postpipe)
- postpipe = create_dstr();
- dstrassure(postpipe, value->len +128);
- unhtmlify(postpipe->data, postpipe->alloc, value->data);
- }
- else if (strcmp(key, "FoomaticRIPCommandLine") == 0) {
- unhtmlify(cmd, 4096, value->data);
- }
- else if (strcmp(key, "FoomaticRIPCommandLinePDF") == 0) {
- unhtmlify(cmd_pdf, 4096, value->data);
- }
- else if (!strcmp(key, "cupsFilter")) {
- /* cupsFilter: <code> */
- /* only save the filter for "application/vnd.cups-raster" */
- if (prefixcmp(value->data, "application/vnd.cups-raster") == 0) {
- p = strrchr(value->data, ' ');
- if (p)
- unhtmlify(cupsfilter, 256, p +1);
- }
- }
- else if (startswith(key, "Custom") && !strcasecmp(name, "true")) {
- /* Cups custom option: *CustomFoo True: "command" */
- if (startswith(&key[6], "JCL")) {
- opt = assure_option(&key[9]);
- opt->style = 'J';
- }
- else
- opt = assure_option(&key[6]);
- option_set_custom_command(opt, value->data);
- if (!strcmp(key, "CustomPageSize"))
- option_set_custom_command(assure_option("PageRegion"), value->data);
- }
- else if (startswith(key, "ParamCustom")) {
- /* Cups custom parameter:
- *ParamCustomFoo Name/Text: order type minimum maximum */
- if (startswith(&key[11], "JCL"))
- opt = assure_option(&key[14]);
- else
- opt = assure_option(&key[11]);
- option_add_custom_param_from_string(opt, name, text, value->data);
- }
- else if (!strcmp(key, "OpenUI") || !strcmp(key, "JCLOpenUI")) {
- /* "*[JCL]OpenUI *<option>[/<translation>]: <type>" */
- current_opt = assure_option(&name[1]);
- if (!isempty(text))
- strlcpy(current_opt->text, text, 128);
- if (startswith(key, "JCL"))
- current_opt->style = 'J';
- /* Set the argument type only if not defined yet,
- a definition in "*FoomaticRIPOption" has priority */
- if (current_opt->type == TYPE_NONE)
- current_opt->type = type_from_string(value->data);
- }
- else if (!strcmp(key, "CloseUI") || !strcmp(key, "JCLCloseUI")) {
- /* *[JCL]CloseUI: *<option> */
- if (!current_opt || !option_has_name(current_opt, value->data +1))
- _log("CloseUI found without corresponding OpenUI (%s).\n", value->data +1);
- current_opt = NULL;
- }
- else if (!strcmp(key, "FoomaticRIPOption")) {
- /* "*FoomaticRIPOption <option>: <type> <style> <spot> [<order>]"
- <order> only used for 1-choice enum options */
- option_set_from_string(assure_option(name), value->data);
- }
- else if (!strcmp(key, "FoomaticRIPOptionPrototype")) {
- /* "*FoomaticRIPOptionPrototype <option>: <code>"
- Used for numerical and string options only */
- opt = assure_option(name);
- opt->proto = malloc(65536);
- unhtmlify(opt->proto, 65536, value->data);
- }
- else if (!strcmp(key, "FoomaticRIPOptionRange")) {
- /* *FoomaticRIPOptionRange <option>: <min> <max>
- Used for numerical options only */
- param = option_assure_foomatic_param(assure_option(name));
- sscanf(value->data, "%19s %19s", param->min, param->max);
- }
- else if (!strcmp(key, "FoomaticRIPOptionMaxLength")) {
- /* "*FoomaticRIPOptionMaxLength <option>: <length>"
- Used for string options only */
- param = option_assure_foomatic_param(assure_option(name));
- sscanf(value->data, "%19s", param->max);
- }
- else if (!strcmp(key, "FoomaticRIPOptionAllowedChars")) {
- /* *FoomaticRIPOptionAllowedChars <option>: <code>
- Used for string options only */
- param = option_assure_foomatic_param(assure_option(name));
- param_set_allowed_chars(param, value->data);
- }
- else if (!strcmp(key, "FoomaticRIPOptionAllowedRegExp")) {
- /* "*FoomaticRIPOptionAllowedRegExp <option>: <code>"
- Used for string options only */
- param = option_assure_foomatic_param(assure_option(name));
- param_set_allowed_regexp(param, value->data);
- }
- else if (!strcmp(key, "OrderDependency")) {
- /* OrderDependency: <order> <section> *<option> */
- /* use 'text' to read <section> */
- sscanf(value->data, "%lf %63s *%63s", &order, text, name);
- opt = assure_option(name);
- opt->section = section_from_string(text);
- option_set_order(opt, order);
- }
-
- /* Default options are not yet validated (not all options/choices
- have been read yet) */
- else if (!prefixcmp(key, "Default")) {
- /* Default<option>: <value> */
-
- opt = assure_option(&key[7]);
- val = option_assure_value(opt, optionset("default"));
- free(val->value);
- val->value = strdup(value->data);
- }
- else if (!prefixcmp(key, "FoomaticRIPDefault")) {
- /* FoomaticRIPDefault<option>: <value>
- Used for numerical options only */
- opt = assure_option(&key[18]);
- val = option_assure_value(opt, optionset("default"));
- free(val->value);
- val->value = strdup(value->data);
- }
-
- /* Current argument */
- else if (current_opt && !strcmp(key, current_opt->name)) {
- /* *<option> <choice>[/translation]: <code> */
- option_set_choice(current_opt, name, text, value->data);
- }
- else if (!strcmp(key, "FoomaticRIPOptionSetting")) {
- /* "*FoomaticRIPOptionSetting <option>[=<choice>]: <code>
- For boolean options <choice> is not given */
- option_set_choice(assure_option(name),
- isempty(text) ? "true" : text, NULL, value->data);
- }
-
- /* "*(Foomatic|)JCL(Begin|ToPSInterpreter|End|Prefix): <code>"
- The printer supports PJL/JCL when there is such a line */
- else if (!prefixcmp(key, "JCLBegin") ||
- !prefixcmp(key, "FoomaticJCLBegin")) {
- unhexify(jclbegin, 256, value->data);
- if (!jclprefixset && strstr(jclbegin, "PJL") == NULL)
- jclprefix[0] = '\0';
- }
- else if (!prefixcmp(key, "JCLToPSInterpreter") ||
- !prefixcmp(key, "FoomaticJCLToPSInterpreter")) {
- unhexify(jcltointerpreter, 256, value->data);
- }
- else if (!prefixcmp(key, "JCLEnd") ||
- !prefixcmp(key, "FoomaticJCLEnd")) {
- unhexify(jclend, 256, value->data);
- }
- else if (!prefixcmp(key, "JCLPrefix") ||
- !prefixcmp(key, "FoomaticJCLPrefix")) {
- unhexify(jclprefix, 256, value->data);
- jclprefixset = 1;
- }
- else if (!prefixcmp(key, "% COMDATA #")) {
- /* old foomtic 2.0.x PPD file */
- _log("You are using an old Foomatic 2.0 PPD file, which is no "
- "longer supported by Foomatic >4.0. Exiting.\n");
- exit(1); /* TODO exit more gracefully */
- }
- else if (!strcmp(key, "FoomaticRIPJobEntityMaxLength")) {
- /* "*FoomaticRIPJobEntityMaxLength: <length>" */
- sscanf(value->data, "%d", &jobentitymaxlen);
- }
- else if (!strcmp(key, "FoomaticRIPUserEntityMaxLength")) {
- /* "*FoomaticRIPUserEntityMaxLength: <length>" */
- sscanf(value->data, "%d", &userentitymaxlen);
- }
- else if (!strcmp(key, "FoomaticRIPHostEntityMaxLength")) {
- /* "*FoomaticRIPHostEntityMaxLength: <length>" */
- sscanf(value->data, "%d", &hostentitymaxlen);
- }
- else if (!strcmp(key, "FoomaticRIPTitleEntityMaxLength")) {
- /* "*FoomaticRIPTitleEntityMaxLength: <length>" */
- sscanf(value->data, "%d", &titleentitymaxlen);
- }
- else if (!strcmp(key, "FoomaticRIPOptionsEntityMaxLength")) {
- /* "*FoomaticRIPOptionsEntityMaxLength: <length>" */
- sscanf(value->data, "%d", &optionsentitymaxlen);
- }
- else if (!strcmp(key, "cupsICCProfile")) {
- /* "*cupsICCProfile: <qualifier/Title> <filename>" */
- entry = calloc(1, sizeof(icc_mapping_entry_t));
- entry->qualifier = strdup(name);
- entry->filename = strdup(value->data);
- list_append (qualifier_data, entry);
- }
- else if (!strcmp(key, "cupsICCQualifier2")) {
- /* "*cupsICCQualifier2: <value>" */
- icc_qual2 = strdup(value->data);
- }
- else if (!strcmp(key, "cupsICCQualifier3")) {
- /* "*cupsICCQualifier3: <value>" */
- icc_qual3 = strdup(value->data);
- }
- }
-
- fclose(fh);
- free_dstr(value);
-
- /* Validate default options by resetting them with option_set_value() */
- for (opt = optionlist; opt; opt = opt->next) {
- val = option_find_value(opt, optionset("default"));
- if (val) {
- /* if fromopt is set, this value has already been validated */
- if (!val->fromoption)
- option_set_value(opt, optionset("default"), val->value);
- }
- else
- /* Make sure that this option has a default choice, even if none is
- defined in the PPD file */
- option_set_value(opt, optionset("default"), opt->choicelist->value);
- }
-
- /* create qualifier for this PPD */
- qualifier = calloc(4, sizeof(char*));
-
- /* get colorspace */
- tmp = option_get_value(find_option("ColorSpace"), optionset("default"));
- if (tmp == NULL)
- tmp = option_get_value(find_option("ColorModel"), optionset("default"));
- if (tmp == NULL)
- tmp = "";
- qualifier[0] = strdup(tmp);
-
- /* get selector2 */
- if (icc_qual2 == NULL)
- icc_qual2 = strdup("MediaType");
- tmp = option_get_value(find_option(icc_qual2), optionset("default"));
- if (tmp == NULL)
- tmp = "";
- qualifier[1] = strdup(tmp);
-
- /* get selectors */
- if (icc_qual3 == NULL)
- icc_qual3 = strdup("Resolution");
- tmp = option_get_value(find_option(icc_qual3), optionset("default"));
- if (tmp == NULL)
- tmp = "";
- qualifier[2] = strdup(tmp);
-
- free (icc_qual2);
- free (icc_qual3);
-}
-
-int ppd_supports_pdf()
-{
- option_t *opt;
-
- /* If at least one option inserts PostScript code, we cannot support PDF */
- for (opt = optionlist; opt; opt = opt->next)
- {
- choice_t *choice;
-
- if (!option_is_ps_command(opt) || option_is_composite(opt) ||
- (opt->type == TYPE_NONE))
- continue;
-
- for (choice = opt->choicelist; choice; choice = choice->next)
- if (contains_active_postscript(choice->command)) {
- _log(" PostScript option found: %s=%s: \"%s\"\n",
- opt->name, choice->value, choice->command);
- return 0;
- }
- }
-
- if (!isempty(cmd_pdf))
- return 1;
-
- /* Ghostscript also accepts PDF, use that if it is in the normal command
- * line */
- if (startswith(cmd, "gs"))
- {
- strncpy(cmd_pdf, cmd, 4096);
- if (strlen(cmd) > 4095)
- cmd_pdf[4095] = '\0';
- return 1;
- }
-
- _log(" Neither PDF renderer command line nor Ghostscript-based renderer command line found\n");
- return 0;
-}
-
-/* build a renderer command line, based on the given option set */
-int build_commandline(int optset, dstr_t *cmdline, int pdfcmdline)
-{
- option_t *opt;
- const char *userval;
- char *s, *p;
- dstr_t *cmdvar = create_dstr();
- dstr_t *open = create_dstr();
- dstr_t *close = create_dstr();
- char letters[] = "%A %B %C %D %E %F %G %H %I %J %K %L %M %W %X %Y %Z";
- int jcl = 0;
-
- dstr_t *local_jclprepend = create_dstr();
-
- dstrclear(prologprepend);
- dstrclear(setupprepend);
- dstrclear(pagesetupprepend);
-
- if (cmdline)
- dstrcpy(cmdline, pdfcmdline ? cmd_pdf : cmd);
-
- for (opt = optionlist_sorted_by_order; opt; opt = opt->next_by_order) {
- /* composite options have no direct influence, and all their dependents
- have already been set */
- if (option_is_composite(opt))
- continue;
-
- userval = option_get_value(opt, optset);
- option_get_command(cmdvar, opt, optset, -1);
-
- /* Insert the built snippet at the correct place */
- if (option_is_ps_command(opt)) {
- /* Place this Postscript command onto the prepend queue
- for the appropriate section. */
- if (cmdvar->len) {
- dstrcpyf(open, "[{\n%%%%BeginFeature: *%s ", opt->name);
- if (opt->type == TYPE_BOOL)
- dstrcatf(open, is_true_string(userval) ? "True\n" : "False\n");
- else
- dstrcatf(open, "%s\n", userval);
- dstrcpyf(close, "\n%%%%EndFeature\n} stopped cleartomark\n");
-
- switch (option_get_section(opt)) {
- case SECTION_PROLOG:
- dstrcatf(prologprepend, "%s%s%s", open->data, cmdvar->data, close->data);
- break;
-
- case SECTION_ANYSETUP:
- if (optset != optionset("currentpage"))
- dstrcatf(setupprepend, "%s%s%s", open->data, cmdvar->data, close->data);
- else if (strcmp(option_get_value(opt, optionset("header")), userval) != 0)
- dstrcatf(pagesetupprepend, "%s%s%s", open->data, cmdvar->data, close->data);
- break;
-
- case SECTION_DOCUMENTSETUP:
- dstrcatf(setupprepend, "%s%s%s", open->data, cmdvar->data, close->data);
- break;
-
- case SECTION_PAGESETUP:
- dstrcatf(pagesetupprepend, "%s%s%s", open->data, cmdvar->data, close->data);
- break;
-
- case SECTION_JCLSETUP: /* PCL/JCL argument */
- s = malloc(cmdvar->len +1);
- unhexify(s, cmdvar->len +1, cmdvar->data);
- dstrcatf(local_jclprepend, "%s", s);
- free(s);
- break;
-
- default:
- dstrcatf(setupprepend, "%s%s%s", open->data, cmdvar->data, close->data);
- }
- }
- }
- else if (option_is_jcl_arg(opt)) {
- jcl = 1;
- /* Put JCL commands onto JCL stack */
- if (cmdvar->len) {
- char *s = malloc(cmdvar->len +1);
- unhexify(s, cmdvar->len +1, cmdvar->data);
- if (!startswith(cmdvar->data, jclprefix))
- dstrcatf(local_jclprepend, "%s%s\n", jclprefix, s);
- else
- dstrcat(local_jclprepend, s);
- free(s);
- }
- }
- else if (option_is_commandline_arg(opt) && cmdline) {
- /* Insert the processed argument in the command line
- just before every occurrence of the spot marker. */
- p = malloc(3);
- snprintf(p, 3, "%%%c", opt->spot);
- s = malloc(cmdvar->len +3);
- snprintf(s, cmdvar->len +3, "%s%%%c", cmdvar->data, opt->spot);
- dstrreplace(cmdline, p, s, 0);
- free(p);
- free(s);
- }
-
- /* Insert option into command line of CUPS raster driver */
- if (cmdline && strstr(cmdline->data, "%Y")) {
- if (isempty(userval))
- continue;
- s = malloc(strlen(opt->name) + strlen(userval) + 20);
- sprintf(s, "%s=%s %%Y", opt->name, userval);
- dstrreplace(cmdline, "%Y", s, 0);
- free(s);
- }
- }
-
- /* Tidy up after computing option statements for all of P, J, and C types: */
-
- /* C type finishing */
- /* Pluck out all of the %n's from the command line prototype */
- if (cmdline) {
- s = strtok(letters, " ");
- do {
- dstrreplace(cmdline, s, "", 0);
- } while ((s = strtok(NULL, " ")));
- }
-
- /* J type finishing */
- /* Compute the proper stuff to say around the job */
- if (jcl && !jobhasjcl) {
- /* command to switch to the interpreter */
- dstrcatf(local_jclprepend, "%s", jcltointerpreter);
-
- /* Arrange for JCL RESET command at the end of job */
- dstrcpy(jclappend, jclend);
-
- argv_free(jclprepend);
- jclprepend = argv_split(local_jclprepend->data, "\r\n", NULL);
- }
-
- free_dstr(cmdvar);
- free_dstr(open);
- free_dstr(close);
- free_dstr(local_jclprepend);
-
- return !isempty(cmd);
-}
-
-/* if "comments" is set, add "%%BeginProlog...%%EndProlog" */
-void append_prolog_section(dstr_t *str, int optset, int comments)
-{
- /* Start comment */
- if (comments) {
- _log("\"Prolog\" section is missing, inserting it.\n");
- dstrcat(str, "%%BeginProlog\n");
- }
-
- /* Generate the option code (not necessary when CUPS is spooler and
- PostScript data is not converted from PDF) */
- if ((spooler != SPOOLER_CUPS) || pdfconvertedtops) {
- _log("Inserting option code into \"Prolog\" section.\n");
- build_commandline(optset, NULL, 0);
- dstrcat(str, prologprepend->data);
- }
-
- /* End comment */
- if (comments)
- dstrcat(str, "%%EndProlog\n");
-}
-
-void append_setup_section(dstr_t *str, int optset, int comments)
-{
- /* Start comment */
- if (comments) {
- _log("\"Setup\" section is missing, inserting it.\n");
- dstrcat(str, "%%BeginSetup\n");
- }
-
- /* Generate the option code (not necessary when CUPS is spooler and
- PostScript data is not converted from PDF) */
- if ((spooler != SPOOLER_CUPS) || pdfconvertedtops) {
- _log("Inserting option code into \"Setup\" section.\n");
- build_commandline(optset, NULL, 0);
- dstrcat(str, setupprepend->data);
+ val1 = option_get_value(opt, optset1);
+ val2 = option_get_value(opt, optset2);
+
+ if (val1 && val2) // both entries exist
+ {
+ if (strcmp(val1, val2) != 0)
+ return (0); // but aren't equal
+ }
+ else if (val1 || val2) // one entry exists --> can't be equal
+ return (0);
+ // If no extry exists, the non-existing entries
+ // are considered as equal
+ }
+ return (1);
+}
+
+
+//
+// read_ppd_file()
+//
+
+void
+read_ppd_file(const char *filename)
+{
+ FILE *fh;
+ const char *tmp;
+ char *icc_qual2 = NULL;
+ char *icc_qual3 = NULL;
+ char line [256]; // PPD line length is max 255 (excl. \0)
+ char *p;
+ char key[128], name[64], text[64];
+ dstr_t *value = create_dstr(); // value can span multiple lines
+ double order;
+ value_t *val;
+ option_t *opt, *current_opt = NULL;
+ param_t *param;
+ icc_mapping_entry_t *entry;
+
+ fh = fopen(filename, "r");
+ if (!fh)
+ rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Unable to open PPD file %s\n", filename);
+ _log("Parsing PPD file ...\n");
+
+ dstrassure(value, 256);
+
+ qualifier_data = list_create();
+ while (!feof(fh))
+ {
+ tmp = fgets(line, 256, fh);
+
+ if (line[0] != '*' || startswith(line, "*%"))
+ continue;
+
+ // get the key
+ if (!(p = strchr(line, ':')))
+ continue;
+ *p = '\0';
+
+ key[0] = name[0] = text[0] = '\0';
+ sscanf(line, "*%127s%*[ \t]%63[^ \t/=)]%*1[/=]%63[^\n]", key, name, text);
+
+ // get the value
+ dstrclear(value);
+ sscanf(p +1, " %255[^\r\n]", value->data);
+ value->len = strlen(value->data);
+ if (!value->len)
+ _log("PPD: Missing value for key \"%s\"\n", line);
+
+ while (1)
+ {
+ // "&&" is the continue-on-next-line marker
+ if (dstrendswith(value, "&&"))
+ {
+ value->len -= 2;
+ value->data[value->len] = '\0';
+ }
+ // quoted but quotes are not yet closed
+ else if (value->data[0] == '\"' && !strchr(value->data +1, '\"'))
+ dstrcat(value, "\n"); // keep newlines in quoted string
+ // not quoted, or quotes already closed
+ else
+ break;
+
+ tmp = fgets(line, 256, fh);
+ dstrcat(value, line);
+ dstrremovenewline(value);
+ }
+
+ // remove quotes
+ if (value->data[0] == '\"')
+ {
+ memmove(value->data, value->data +1, value->len +1);
+ p = strrchr(value->data, '\"');
+ if (!p)
+ {
+ _log("Invalid line: \"%s: ...\"\n", key);
+ continue;
+ }
+ *p = '\0';
+ }
+ // remove last newline
+ dstrremovenewline(value);
+
+ // remove last whitespace
+ dstrtrim_right(value);
+
+ // process key/value pairs
+ if (strcmp(key, "NickName") == 0)
+ {
+ unhtmlify(printer_model, 256, value->data);
+ }
+ else if (strcmp(key, "FoomaticIDs") == 0)
+ {
+ // *FoomaticIDs: <printer ID> <driver ID>
+ sscanf(value->data, "%*[ \t]%127[^ \t]%*[ \t]%127[^ \t\n]",
+ printer_id, driver);
+ }
+ else if (strcmp(key, "FoomaticRIPPostPipe") == 0)
+ {
+ if (!postpipe)
+ postpipe = create_dstr();
+ dstrassure(postpipe, value->len +128);
+ unhtmlify(postpipe->data, postpipe->alloc, value->data);
+ }
+ else if (strcmp(key, "FoomaticRIPCommandLine") == 0)
+ {
+ unhtmlify(cmd, 4096, value->data);
+ }
+ else if (strcmp(key, "FoomaticRIPCommandLinePDF") == 0)
+ {
+ unhtmlify(cmd_pdf, 4096, value->data);
+ }
+ else if (!strcmp(key, "cupsFilter"))
+ {
+ // cupsFilter: <code>
+ // only save the filter for "application/vnd.cups-raster"
+ if (prefixcmp(value->data, "application/vnd.cups-raster") == 0)
+ {
+ p = strrchr(value->data, ' ');
+ if (p)
+ unhtmlify(cupsfilter, 256, p +1);
+ }
+ }
+ else if (startswith(key, "Custom") && !strcasecmp(name, "true"))
+ {
+ // Cups custom option: *CustomFoo True: "command"
+ if (startswith(&key[6], "JCL"))
+ {
+ opt = assure_option(&key[9]);
+ opt->style = 'J';
+ }
+ else
+ opt = assure_option(&key[6]);
+ option_set_custom_command(opt, value->data);
+ if (!strcmp(key, "CustomPageSize"))
+ option_set_custom_command(assure_option("PageRegion"), value->data);
+ }
+ else if (startswith(key, "ParamCustom"))
+ {
+ // Cups custom parameter:
+ // *ParamCustomFoo Name/Text: order type minimum maximum
+ if (startswith(&key[11], "JCL"))
+ opt = assure_option(&key[14]);
+ else
+ opt = assure_option(&key[11]);
+ option_add_custom_param_from_string(opt, name, text, value->data);
+ }
+ else if (!strcmp(key, "OpenUI") || !strcmp(key, "JCLOpenUI"))
+ {
+ // "*[JCL]OpenUI *<option>[/<translation>]: <type>"
+ current_opt = assure_option(&name[1]);
+ if (!isempty(text))
+ strlcpy(current_opt->text, text, 128);
+ if (startswith(key, "JCL"))
+ current_opt->style = 'J';
+ // Set the argument type only if not defined yet,
+ // a definition in "*FoomaticRIPOption" has priority
+ if (current_opt->type == TYPE_NONE)
+ current_opt->type = type_from_string(value->data);
+ }
+ else if (!strcmp(key, "CloseUI") || !strcmp(key, "JCLCloseUI"))
+ {
+ // *[JCL]CloseUI: *<option>
+ if (!current_opt || !option_has_name(current_opt, value->data +1))
+ _log("CloseUI found without corresponding OpenUI (%s).\n",
+ value->data +1);
+ current_opt = NULL;
+ }
+ else if (!strcmp(key, "FoomaticRIPOption"))
+ {
+ // "*FoomaticRIPOption <option>: <type> <style> <spot> [<order>]"
+ // <order> only used for 1-choice enum options
+ option_set_from_string(assure_option(name), value->data);
+ }
+ else if (!strcmp(key, "FoomaticRIPOptionPrototype"))
+ {
+ // "*FoomaticRIPOptionPrototype <option>: <code>"
+ // Used for numerical and string options only
+ opt = assure_option(name);
+ opt->proto = malloc(65536);
+ unhtmlify(opt->proto, 65536, value->data);
+ }
+ else if (!strcmp(key, "FoomaticRIPOptionRange"))
+ {
+ // *FoomaticRIPOptionRange <option>: <min> <max>
+ // Used for numerical options only
+ param = option_assure_foomatic_param(assure_option(name));
+ sscanf(value->data, "%19s %19s", param->min, param->max);
+ }
+ else if (!strcmp(key, "FoomaticRIPOptionMaxLength"))
+ {
+ // "*FoomaticRIPOptionMaxLength <option>: <length>"
+ // Used for string options only
+ param = option_assure_foomatic_param(assure_option(name));
+ sscanf(value->data, "%19s", param->max);
+ }
+ else if (!strcmp(key, "FoomaticRIPOptionAllowedChars"))
+ {
+ // *FoomaticRIPOptionAllowedChars <option>: <code>
+ // Used for string options only
+ param = option_assure_foomatic_param(assure_option(name));
+ param_set_allowed_chars(param, value->data);
+ }
+ else if (!strcmp(key, "FoomaticRIPOptionAllowedRegExp"))
+ {
+ // "*FoomaticRIPOptionAllowedRegExp <option>: <code>"
+ // Used for string options only
+ param = option_assure_foomatic_param(assure_option(name));
+ param_set_allowed_regexp(param, value->data);
+ }
+ else if (!strcmp(key, "OrderDependency"))
+ {
+ // OrderDependency: <order> <section> *<option>
+ // use 'text' to read <section>
+ sscanf(value->data, "%lf %63s *%63s", &order, text, name);
+ opt = assure_option(name);
+ opt->section = section_from_string(text);
+ option_set_order(opt, order);
}
- /* End comment */
- if (comments)
- dstrcat(str, "%%EndSetup\n");
+ // Default options are not yet validated (not all options/choices
+ // have been read yet)
+ else if (!prefixcmp(key, "Default"))
+ {
+ // Default<option>: <value>
+ opt = assure_option(&key[7]);
+ val = option_assure_value(opt, optionset("default"));
+ free(val->value);
+ val->value = strdup(value->data);
+ }
+ else if (!prefixcmp(key, "FoomaticRIPDefault"))
+ {
+ // FoomaticRIPDefault<option>: <value>
+ // Used for numerical options only
+ opt = assure_option(&key[18]);
+ val = option_assure_value(opt, optionset("default"));
+ free(val->value);
+ val->value = strdup(value->data);
+ }
+
+ // Current argument
+ else if (current_opt && !strcmp(key, current_opt->name))
+ {
+ // *<option> <choice>[/translation]: <code>
+ option_set_choice(current_opt, name, text, value->data);
+ }
+ else if (!strcmp(key, "FoomaticRIPOptionSetting"))
+ {
+ // "*FoomaticRIPOptionSetting <option>[=<choice>]: <code>
+ // For boolean options <choice> is not given
+ option_set_choice(assure_option(name),
+ isempty(text) ? "true" : text, NULL, value->data);
+ }
+
+ // "*(Foomatic|)JCL(Begin|ToPSInterpreter|End|Prefix): <code>"
+ // The printer supports PJL/JCL when there is such a line
+ else if (!prefixcmp(key, "JCLBegin") ||
+ !prefixcmp(key, "FoomaticJCLBegin"))
+ {
+ unhexify(jclbegin, 256, value->data);
+ if (!jclprefixset && strstr(jclbegin, "PJL") == NULL)
+ jclprefix[0] = '\0';
+ }
+ else if (!prefixcmp(key, "JCLToPSInterpreter") ||
+ !prefixcmp(key, "FoomaticJCLToPSInterpreter"))
+ {
+ unhexify(jcltointerpreter, 256, value->data);
+ }
+ else if (!prefixcmp(key, "JCLEnd") ||
+ !prefixcmp(key, "FoomaticJCLEnd"))
+ {
+ unhexify(jclend, 256, value->data);
+ }
+ else if (!prefixcmp(key, "JCLPrefix") ||
+ !prefixcmp(key, "FoomaticJCLPrefix"))
+ {
+ unhexify(jclprefix, 256, value->data);
+ jclprefixset = 1;
+ }
+ else if (!prefixcmp(key, "% COMDATA #"))
+ {
+ // old foomtic 2.0.x PPD file
+ _log("You are using an old Foomatic 2.0 PPD file, which is no "
+ "longer supported by Foomatic >4.0. Exiting.\n");
+ exit(1); // TODO exit more gracefully
+ }
+ else if (!strcmp(key, "FoomaticRIPJobEntityMaxLength"))
+ {
+ // "*FoomaticRIPJobEntityMaxLength: <length>"
+ sscanf(value->data, "%d", &jobentitymaxlen);
+ }
+ else if (!strcmp(key, "FoomaticRIPUserEntityMaxLength"))
+ {
+ // "*FoomaticRIPUserEntityMaxLength: <length>"
+ sscanf(value->data, "%d", &userentitymaxlen);
+ }
+ else if (!strcmp(key, "FoomaticRIPHostEntityMaxLength"))
+ {
+ // "*FoomaticRIPHostEntityMaxLength: <length>"
+ sscanf(value->data, "%d", &hostentitymaxlen);
+ }
+ else if (!strcmp(key, "FoomaticRIPTitleEntityMaxLength"))
+ {
+ // "*FoomaticRIPTitleEntityMaxLength: <length>"
+ sscanf(value->data, "%d", &titleentitymaxlen);
+ }
+ else if (!strcmp(key, "FoomaticRIPOptionsEntityMaxLength"))
+ {
+ // "*FoomaticRIPOptionsEntityMaxLength: <length>"
+ sscanf(value->data, "%d", &optionsentitymaxlen);
+ }
+ else if (!strcmp(key, "cupsICCProfile"))
+ {
+ // "*cupsICCProfile: <qualifier/Title> <filename>"
+ entry = calloc(1, sizeof(icc_mapping_entry_t));
+ entry->qualifier = strdup(name);
+ entry->filename = strdup(value->data);
+ list_append (qualifier_data, entry);
+ }
+ else if (!strcmp(key, "cupsICCQualifier2"))
+ {
+ // "*cupsICCQualifier2: <value>"
+ icc_qual2 = strdup(value->data);
+ }
+ else if (!strcmp(key, "cupsICCQualifier3"))
+ {
+ // "*cupsICCQualifier3: <value>"
+ icc_qual3 = strdup(value->data);
+ }
+ }
+
+ fclose(fh);
+ free_dstr(value);
+
+ // Validate default options by resetting them with option_set_value()
+ for (opt = optionlist; opt; opt = opt->next)
+ {
+ val = option_find_value(opt, optionset("default"));
+ if (val)
+ {
+ // if fromopt is set, this value has already been validated
+ if (!val->fromoption)
+ option_set_value(opt, optionset("default"), val->value);
+ }
+ else
+ // Make sure that this option has a default choice, even if none is
+ // defined in the PPD file
+ option_set_value(opt, optionset("default"), opt->choicelist->value);
+ }
+
+ // create qualifier for this PPD
+ qualifier = calloc(4, sizeof(char*));
+
+ // get colorspace
+ tmp = option_get_value(find_option("ColorSpace"), optionset("default"));
+ if (tmp == NULL)
+ tmp = option_get_value(find_option("ColorModel"), optionset("default"));
+ if (tmp == NULL)
+ tmp = "";
+ qualifier[0] = strdup(tmp);
+
+ // get selector2
+ if (icc_qual2 == NULL)
+ icc_qual2 = strdup("MediaType");
+ tmp = option_get_value(find_option(icc_qual2), optionset("default"));
+ if (tmp == NULL)
+ tmp = "";
+ qualifier[1] = strdup(tmp);
+
+ // get selectors
+ if (icc_qual3 == NULL)
+ icc_qual3 = strdup("Resolution");
+ tmp = option_get_value(find_option(icc_qual3), optionset("default"));
+ if (tmp == NULL)
+ tmp = "";
+ qualifier[2] = strdup(tmp);
+
+ free (icc_qual2);
+ free (icc_qual3);
+}
+
+
+int
+ppd_supports_pdf()
+{
+ option_t *opt;
+
+ // If at least one option inserts PostScript code, we cannot support PDF
+ for (opt = optionlist; opt; opt = opt->next)
+ {
+ choice_t *choice;
+
+ if (!option_is_ps_command(opt) || option_is_composite(opt) ||
+ (opt->type == TYPE_NONE))
+ continue;
+
+ for (choice = opt->choicelist; choice; choice = choice->next)
+ if (contains_active_postscript(choice->command))
+ {
+ _log(" PostScript option found: %s=%s: \"%s\"\n",
+ opt->name, choice->value, choice->command);
+ return (0);
+ }
+ }
+
+ if (!isempty(cmd_pdf))
+ return (1);
+
+ // Ghostscript also accepts PDF, use that if it is in the normal command
+ // line
+ if (startswith(cmd, "gs"))
+ {
+ strncpy(cmd_pdf, cmd, 4096);
+ if (strlen(cmd) > 4095)
+ cmd_pdf[4095] = '\0';
+ return (1);
+ }
+
+ _log(" Neither PDF renderer command line nor Ghostscript-based renderer command line found\n");
+ return (0);
+}
+
+
+// build a renderer command line, based on the given option set
+int
+build_commandline(int optset,
+ dstr_t *cmdline,
+ int pdfcmdline)
+{
+ option_t *opt;
+ const char *userval;
+ char *s, *p;
+ dstr_t *cmdvar = create_dstr();
+ dstr_t *open = create_dstr();
+ dstr_t *close = create_dstr();
+ char letters[] = "%A %B %C %D %E %F %G %H %I %J %K %L %M %W %X %Y %Z";
+ int jcl = 0;
+
+ dstr_t *local_jclprepend = create_dstr();
+
+ dstrclear(prologprepend);
+ dstrclear(setupprepend);
+ dstrclear(pagesetupprepend);
+
+ if (cmdline)
+ dstrcpy(cmdline, pdfcmdline ? cmd_pdf : cmd);
+
+ for (opt = optionlist_sorted_by_order; opt; opt = opt->next_by_order)
+ {
+ // composite options have no direct influence, and all their dependents
+ // have already been set
+ if (option_is_composite(opt))
+ continue;
+
+ userval = option_get_value(opt, optset);
+ option_get_command(cmdvar, opt, optset, -1);
+
+ // Insert the built snippet at the correct place
+ if (option_is_ps_command(opt))
+ {
+ // Place this Postscript command onto the prepend queue
+ // for the appropriate section.
+ if (cmdvar->len)
+ {
+ dstrcpyf(open, "[{\n%%%%BeginFeature: *%s ", opt->name);
+ if (opt->type == TYPE_BOOL)
+ dstrcatf(open, is_true_string(userval) ? "True\n" : "False\n");
+ else
+ dstrcatf(open, "%s\n", userval);
+ dstrcpyf(close, "\n%%%%EndFeature\n} stopped cleartomark\n");
+
+ switch (option_get_section(opt))
+ {
+ case SECTION_PROLOG:
+ dstrcatf(prologprepend, "%s%s%s", open->data, cmdvar->data,
+ close->data);
+ break;
+
+ case SECTION_ANYSETUP:
+ if (optset != optionset("currentpage"))
+ dstrcatf(setupprepend, "%s%s%s", open->data, cmdvar->data,
+ close->data);
+ else if (strcmp(option_get_value(opt, optionset("header")),
+ userval) != 0)
+ dstrcatf(pagesetupprepend, "%s%s%s", open->data, cmdvar->data,
+ close->data);
+ break;
+
+ case SECTION_DOCUMENTSETUP:
+ dstrcatf(setupprepend, "%s%s%s", open->data, cmdvar->data,
+ close->data);
+ break;
+
+ case SECTION_PAGESETUP:
+ dstrcatf(pagesetupprepend, "%s%s%s", open->data, cmdvar->data,
+ close->data);
+ break;
+
+ case SECTION_JCLSETUP: // PCL/JCL argument
+ s = malloc(cmdvar->len +1);
+ unhexify(s, cmdvar->len +1, cmdvar->data);
+ dstrcatf(local_jclprepend, "%s", s);
+ free(s);
+ break;
+
+ default:
+ dstrcatf(setupprepend, "%s%s%s", open->data, cmdvar->data,
+ close->data);
+ }
+ }
+ }
+ else if (option_is_jcl_arg(opt))
+ {
+ jcl = 1;
+ // Put JCL commands onto JCL stack
+ if (cmdvar->len)
+ {
+ char *s = malloc(cmdvar->len +1);
+ unhexify(s, cmdvar->len +1, cmdvar->data);
+ if (!startswith(cmdvar->data, jclprefix))
+ dstrcatf(local_jclprepend, "%s%s\n", jclprefix, s);
+ else
+ dstrcat(local_jclprepend, s);
+ free(s);
+ }
+ }
+ else if (option_is_commandline_arg(opt) && cmdline)
+ {
+ // Insert the processed argument in the command line
+ // just before every occurrence of the spot marker.
+ p = malloc(3);
+ snprintf(p, 3, "%%%c", opt->spot);
+ s = malloc(cmdvar->len +3);
+ snprintf(s, cmdvar->len +3, "%s%%%c", cmdvar->data, opt->spot);
+ dstrreplace(cmdline, p, s, 0);
+ free(p);
+ free(s);
+ }
+
+ // Insert option into command line of CUPS raster driver
+ if (cmdline && strstr(cmdline->data, "%Y"))
+ {
+ if (isempty(userval))
+ continue;
+ s = malloc(strlen(opt->name) + strlen(userval) + 20);
+ sprintf(s, "%s=%s %%Y", opt->name, userval);
+ dstrreplace(cmdline, "%Y", s, 0);
+ free(s);
+ }
+ }
+
+ // Tidy up after computing option statements for all of P, J, and C types:
+
+ // C type finishing
+ // Pluck out all of the %n's from the command line prototype
+ if (cmdline)
+ {
+ s = strtok(letters, " ");
+ do
+ {
+ dstrreplace(cmdline, s, "", 0);
+ }
+ while ((s = strtok(NULL, " ")));
+ }
+
+ // J type finishing
+ // Compute the proper stuff to say around the job
+ if (jcl && !jobhasjcl)
+ {
+ // command to switch to the interpreter
+ dstrcatf(local_jclprepend, "%s", jcltointerpreter);
+
+ // Arrange for JCL RESET command at the end of job
+ dstrcpy(jclappend, jclend);
+
+ argv_free(jclprepend);
+ jclprepend = argv_split(local_jclprepend->data, "\r\n", NULL);
+ }
+
+ free_dstr(cmdvar);
+ free_dstr(open);
+ free_dstr(close);
+ free_dstr(local_jclprepend);
+
+ return (!isempty(cmd));
}
-void append_page_setup_section(dstr_t *str, int optset, int comments)
+
+// if "comments" is set, add "%%BeginProlog...%%EndProlog"
+void
+append_prolog_section(dstr_t *str,
+ int optset,
+ int comments)
{
- /* Start comment */
- if (comments) {
- _log("\"PageSetup\" section is missing, inserting it.\n");
- dstrcat(str, "%%BeginPageSetup\n");
- }
+ // Start comment
+ if (comments)
+ {
+ _log("\"Prolog\" section is missing, inserting it.\n");
+ dstrcat(str, "%%BeginProlog\n");
+ }
+
+ // Generate the option code (not necessary when CUPS is spooler and
+ // PostScript data is not converted from PDF)
+ if ((spooler != SPOOLER_CUPS) || pdfconvertedtops)
+ {
+ _log("Inserting option code into \"Prolog\" section.\n");
+ build_commandline(optset, NULL, 0);
+ dstrcat(str, prologprepend->data);
+ }
+
+ // End comment
+ if (comments)
+ dstrcat(str, "%%EndProlog\n");
+}
+
- /* Generate the option code (not necessary when CUPS is spooler) */
- _log("Inserting option code into \"PageSetup\" section.\n");
+void
+append_setup_section(dstr_t *str,
+ int optset,
+ int comments)
+{
+ // Start comment
+ if (comments)
+ {
+ _log("\"Setup\" section is missing, inserting it.\n");
+ dstrcat(str, "%%BeginSetup\n");
+ }
+
+ // Generate the option code (not necessary when CUPS is spooler and
+ // PostScript data is not converted from PDF)
+ if ((spooler != SPOOLER_CUPS) || pdfconvertedtops)
+ {
+ _log("Inserting option code into \"Setup\" section.\n");
build_commandline(optset, NULL, 0);
- dstrcat(str, pagesetupprepend->data);
+ dstrcat(str, setupprepend->data);
+ }
+
+ // End comment
+ if (comments)
+ dstrcat(str, "%%EndSetup\n");
+}
+
- /* End comment */
- if (comments)
- dstrcat(str, "%%EndPageSetup\n");
+void
+append_page_setup_section(dstr_t *str,
+ int optset,
+ int comments)
+{
+ // Start comment
+ if (comments)
+ {
+ _log("\"PageSetup\" section is missing, inserting it.\n");
+ dstrcat(str, "%%BeginPageSetup\n");
+ }
+
+ // Generate the option code (not necessary when CUPS is spooler)
+ _log("Inserting option code into \"PageSetup\" section.\n");
+ build_commandline(optset, NULL, 0);
+ dstrcat(str, pagesetupprepend->data);
+
+ // End comment
+ if (comments)
+ dstrcat(str, "%%EndPageSetup\n");
}
-typedef struct page_range {
- short even, odd;
- unsigned first, last;
- struct page_range *next;
+typedef struct page_range
+{
+ short even, odd;
+ unsigned first, last;
+ struct page_range *next;
} page_range_t;
-static page_range_t * parse_page_ranges(const char *ranges)
-{
- page_range_t *head = NULL, *tail = NULL;
- char *tokens, *tok;
- int cnt;
-
- tokens = strdup(ranges);
- for (tok = strtok(tokens, ","); tok; tok = strtok(NULL, ",")) {
- page_range_t *pr = calloc(1, sizeof(page_range_t));
-
- if (startswith(tok, "even"))
- pr->even = 1;
- else if (startswith(tok, "odd"))
- pr->odd = 1;
- else if ((cnt = sscanf(tok, "%u-%u", &pr->first, &pr->last))) {
- /* If 'last' has not been read, this could mean only one page (no
- * hyphen) or all pages to the end */
- if (cnt == 1 && !endswith(tok, "-"))
- pr->last = pr->first;
- else if (cnt == 2 && pr->first > pr->last) {
- unsigned tmp = pr->first;
- pr->first = pr->last;
- pr->last = tmp;
- }
- }
- else {
- _log("Invalid page range: %s\n", tok);
- free(pr);
- continue;
- }
-
- if (tail) {
- tail->next = pr;
- tail = pr;
- }
- else
- tail = head = pr;
- }
-
- free(tokens);
- return head;
-}
-
-static void free_page_ranges(page_range_t *ranges)
-{
- page_range_t *pr;
- while (ranges) {
- pr = ranges;
- ranges = ranges->next;
- free(pr);
- }
-}
-
-/* Parse a string containing page ranges and either check whether a
- given page is in the ranges or, if the given page number is zero,
- determine the score how specific this page range string is.*/
-int get_page_score(const char *pages, int page)
-{
- page_range_t *ranges = parse_page_ranges(pages);
- page_range_t *pr;
- int totalscore = 0;
- int pageinside = 0;
-
- for (pr = ranges; pr; pr = pr->next) {
- if (pr->even) {
- totalscore += 50000;
- if (page % 2 == 0)
- pageinside = 1;
- }
- else if (pr->odd) {
- totalscore += 50000;
- if (page % 2 == 1)
- pageinside = 1;
- }
- else if (pr->first == pr->last) { /* Single page */
- totalscore += 1;
- if (page == pr->first)
- pageinside = 1;
- }
- else if (pr->last == 0) { /* To the end of the document */
- totalscore += 100000;
- if (page >= pr->first)
- pageinside = 1;
- }
- else { /* Sequence of pages */
- totalscore += pr->last - pr->first +1;
- if (page >= pr->first && page <= pr->last)
- pageinside = 1;
- }
- }
-
- free_page_ranges(ranges);
-
- if (page == 0 || pageinside)
- return totalscore;
-
- return 0;
-}
-
-/* Set the options for a given page */
-void set_options_for_page(int optset, int page)
-{
- int score, bestscore;
- option_t *opt;
- value_t *val, *bestvalue;
- const char *ranges;
- const char *optsetname;
-
- for (opt = optionlist; opt; opt = opt->next) {
-
- bestscore = 10000000;
- bestvalue = NULL;
- for (val = opt->valuelist; val; val = val->next) {
-
- optsetname = optionset_name(val->optionset);
- if (!startswith(optsetname, "pages:"))
- continue;
-
- ranges = &optsetname[6]; /* after "pages:" */
- score = get_page_score(ranges, page);
- if (score && score < bestscore) {
- bestscore = score;
- bestvalue = val;
- }
- }
- if (bestvalue)
- option_set_value(opt, optset, bestvalue->value);
+static page_range_t *
+parse_page_ranges(const char *ranges)
+{
+ page_range_t *head = NULL, *tail = NULL;
+ char *tokens, *tok;
+ int cnt;
+
+ tokens = strdup(ranges);
+ for (tok = strtok(tokens, ","); tok; tok = strtok(NULL, ","))
+ {
+ page_range_t *pr = calloc(1, sizeof(page_range_t));
+
+ if (startswith(tok, "even"))
+ pr->even = 1;
+ else if (startswith(tok, "odd"))
+ pr->odd = 1;
+ else if ((cnt = sscanf(tok, "%u-%u", &pr->first, &pr->last)))
+ {
+ // If 'last' has not been read, this could mean only one page (no
+ // hyphen) or all pages to the end
+ if (cnt == 1 && !endswith(tok, "-"))
+ pr->last = pr->first;
+ else if (cnt == 2 && pr->first > pr->last)
+ {
+ unsigned tmp = pr->first;
+ pr->first = pr->last;
+ pr->last = tmp;
+ }
+ }
+ else
+ {
+ _log("Invalid page range: %s\n", tok);
+ free(pr);
+ continue;
}
+
+ if (tail)
+ {
+ tail->next = pr;
+ tail = pr;
+ }
+ else
+ tail = head = pr;
+ }
+
+ free(tokens);
+ return (head);
}
+
+static
+void free_page_ranges(page_range_t *ranges)
+{
+ page_range_t *pr;
+ while (ranges)
+ {
+ pr = ranges;
+ ranges = ranges->next;
+ free(pr);
+ }
+}
+
+
+// Parse a string containing page ranges and either check whether a
+// given page is in the ranges or, if the given page number is zero,
+// determine the score how specific this page range string is.
+int
+get_page_score(const char *pages,
+ int page)
+{
+ page_range_t *ranges = parse_page_ranges(pages);
+ page_range_t *pr;
+ int totalscore = 0;
+ int pageinside = 0;
+
+ for (pr = ranges; pr; pr = pr->next)
+ {
+ if (pr->even)
+ {
+ totalscore += 50000;
+ if (page % 2 == 0)
+ pageinside = 1;
+ }
+ else if (pr->odd)
+ {
+ totalscore += 50000;
+ if (page % 2 == 1)
+ pageinside = 1;
+ }
+ else if (pr->first == pr->last) // Single page
+ {
+ totalscore += 1;
+ if (page == pr->first)
+ pageinside = 1;
+ }
+ else if (pr->last == 0) // To the end of the document
+ {
+ totalscore += 100000;
+ if (page >= pr->first)
+ pageinside = 1;
+ }
+ else // Sequence of pages
+ {
+ totalscore += pr->last - pr->first +1;
+ if (page >= pr->first && page <= pr->last)
+ pageinside = 1;
+ }
+ }
+
+ free_page_ranges(ranges);
+
+ if (page == 0 || pageinside)
+ return (totalscore);
+
+ return (0);
+}
+
+
+// Set the options for a given page
+void
+set_options_for_page(int optset,
+ int page)
+{
+ int score, bestscore;
+ option_t *opt;
+ value_t *val, *bestvalue;
+ const char *ranges;
+ const char *optsetname;
+
+ for (opt = optionlist; opt; opt = opt->next)
+ {
+ bestscore = 10000000;
+ bestvalue = NULL;
+ for (val = opt->valuelist; val; val = val->next)
+ {
+ optsetname = optionset_name(val->optionset);
+ if (!startswith(optsetname, "pages:"))
+ continue;
+
+ ranges = &optsetname[6]; // after "pages:"
+ score = get_page_score(ranges, page);
+ if (score && score < bestscore)
+ {
+ bestscore = score;
+ bestvalue = val;
+ }
+ }
+
+ if (bestvalue)
+ option_set_value(opt, optset, bestvalue->value);
+ }
+}
-/* options.h
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// options.h
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#ifndef options_h
#define options_h
#include <regex.h>
#include "util.h"
-/* Option types */
+// Option types
#define TYPE_NONE 0
#define TYPE_ENUM 1
#define TYPE_PICKMANY 2
#define TYPE_PASSCODE 10
#define TYPE_POINTS 11
-/* Sections */
+// Sections
#define SECTION_ANYSETUP 1
#define SECTION_PAGESETUP 2
#define SECTION_PROLOG 3
-typedef struct choice_s {
- char value [128];
- char text [128];
- char command[65536];
- struct choice_s *next;
+typedef struct choice_s
+{
+ char value [128];
+ char text [128];
+ char command[65536];
+ struct choice_s *next;
} choice_t;
-/* Custom option parameter */
-typedef struct param_s {
- char name [128];
- char text [128]; /* formerly comment, changed to 'text' to
- be consistent with cups */
- int order;
+// Custom option parameter
+typedef struct param_s
+{
+ char name [128];
+ char text [128]; // formerly comment, changed to 'text' to
+ // be consistent with cups
+ int order;
- int type;
- char min[20], max[20]; /* contents depend on 'type' */
+ int type;
+ char min[20], max[20]; // contents depend on 'type'
- regex_t *allowedchars;
- regex_t *allowedregexp;
+ regex_t *allowedchars;
+ regex_t *allowedregexp;
- struct param_s *next;
+ struct param_s *next;
} param_t;
-/* Option */
-typedef struct option_s {
- char name [128];
- char text [128];
- char varname [128]; /* clean version of 'name' (no spaces etc.) */
- int type;
- int style;
- char spot;
- double order;
- int section;
-
- int notfirst; /* TODO remove */
-
- choice_t *choicelist;
-
- /* Foomatic PPD extensions */
- char *proto; /* *FoomaticRIPOptionPrototype: if this is set
- it will be used with only the first option
- in paramlist (there should be only one) */
- param_t *foomatic_param;
-
- /* CUPS custom options */
- char *custom_command; /* *CustomFoo */
- param_t *paramlist; /* for custom values, sorted by stack order */
- size_t param_count;
-
- struct value_s *valuelist;
-
- struct option_s *next;
- struct option_s *next_by_order;
+// Option
+typedef struct option_s
+{
+ char name [128];
+ char text [128];
+ char varname [128]; // clean version of 'name' (no spaces etc.)
+ int type;
+ int style;
+ char spot;
+ double order;
+ int section;
+
+ int notfirst; // TODO remove
+
+ choice_t *choicelist;
+
+ // Foomatic PPD extensions
+ char *proto; // *FoomaticRIPOptionPrototype: if this is set
+ // it will be used with only the first option
+ // in paramlist (there should be only one)
+ param_t *foomatic_param;
+
+ // CUPS custom options
+ char *custom_command; // *CustomFoo
+ param_t *paramlist; // for custom values, sorted by stack order
+ size_t param_count;
+
+ struct value_s *valuelist;
+
+ struct option_s *next;
+ struct option_s *next_by_order;
} option_t;
-
-/* A value for an option */
-typedef struct value_s {
- int optionset;
- char *value;
- option_t *fromoption; /* This is set when this value is set by a composite */
- struct value_s *next;
+// A value for an option
+typedef struct value_s
+{
+ int optionset;
+ char *value;
+ option_t *fromoption; // This is set when this value is set by a composite
+ struct value_s *next;
} value_t;
int option_is_commandline_arg(option_t *opt);
-int option_get_section(option_t *opt); /* TODO deprecated */
+int option_get_section(option_t *opt); // TODO deprecated
-/* handles ANYSETUP (for (PAGE|DOCUMENT)SETUP) */
+// handles ANYSETUP (for (PAGE|DOCUMENT)SETUP)
int option_is_in_section(option_t *opt, int section);
void options_init();
int option_set_value(option_t *opt, int optset, const char *value);
const char * option_get_value(option_t *opt, int optset);
-/* section == -1 for all sections */
+// section == -1 for all sections
int option_get_command(dstr_t *cmd, option_t *opt, int optset, int section);
int option_accepts_value(option_t *opt, const char *value);
char *get_icc_profile_for_qualifier(const char **qualifier);
const char **get_ppd_qualifier(void);
-#endif
-
+#endif // !options_h
-/* pdf.c
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// pdf.c
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#include "foomaticrip.h"
#include "util.h"
static int wait_for_renderer();
-int pdf_count_pages(const char *filename)
+int
+pdf_count_pages(const char *filename)
{
- char gscommand[CMDLINE_MAX];
- char output[63] = "";
- int pagecount;
- size_t bytes;
- char *p;
-
- snprintf(gscommand, CMDLINE_MAX, "%s -dNODISPLAY -dNOSAFER -dNOPAUSE -q -c "
- "'/pdffile (%s) (r) file runpdfbegin (PageCount: ) print "
- "pdfpagecount = quit'",
- gspath, filename);
-
- FILE *pd = popen(gscommand, "r");
- if (!pd)
- rip_die(EXIT_STARVED, "Failed to execute ghostscript to determine number of input pages!\n");
-
- bytes = fread_or_die(output, 1, sizeof(output), pd);
- pclose(pd);
-
- p = output;
- pagecount = -1;
- while (bytes > 0) {
- if (sscanf(p, "PageCount: %d", &pagecount) >= 1)
- break;
- p = memchr(p, '\n', bytes);
- if (p == NULL)
- break;
- p ++;
- bytes = sizeof(output) - (p - output);
- }
-
- return pagecount;
+ char gscommand[CMDLINE_MAX];
+ char output[63] = "";
+ int pagecount;
+ size_t bytes;
+ char *p;
+
+ snprintf(gscommand, CMDLINE_MAX, "%s -dNODISPLAY -dNOSAFER -dNOPAUSE -q -c "
+ "'/pdffile (%s) (r) file runpdfbegin (PageCount: ) print "
+ "pdfpagecount = quit'",
+ gspath, filename);
+
+ FILE *pd = popen(gscommand, "r");
+ if (!pd)
+ rip_die(EXIT_STARVED,
+ "Failed to execute ghostscript to determine number of input pages!\n");
+
+ bytes = fread_or_die(output, 1, sizeof(output), pd);
+ pclose(pd);
+
+ p = output;
+ pagecount = -1;
+ while (bytes > 0)
+ {
+ if (sscanf(p, "PageCount: %d", &pagecount) >= 1)
+ break;
+ p = memchr(p, '\n', bytes);
+ if (p == NULL)
+ break;
+ p ++;
+ bytes = sizeof(output) - (p - output);
+ }
+
+ return (pagecount);
}
pid_t kid3 = 0;
-static int start_renderer(const char *cmd)
+static int
+start_renderer(const char *cmd)
{
- if (kid3 != 0)
- wait_for_renderer();
+ if (kid3 != 0)
+ wait_for_renderer();
- _log("Starting renderer with command: %s\n", cmd);
- kid3 = start_process("kid3", exec_kid3, (void *)cmd, NULL, NULL);
- if (kid3 < 0)
- rip_die(EXIT_STARVED, "Could not start renderer\n");
+ _log("Starting renderer with command: %s\n", cmd);
+ kid3 = start_process("kid3", exec_kid3, (void *)cmd, NULL, NULL);
+ if (kid3 < 0)
+ rip_die(EXIT_STARVED, "Could not start renderer\n");
- return 1;
+ return (1);
}
-static int wait_for_renderer()
-{
- int status;
-
- waitpid(kid3, &status, 0);
-
- if (!WIFEXITED(status)) {
- _log("Kid3 did not finish normally.\n");
- exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
- }
-
- _log("Kid3 exit status: %d\n", WEXITSTATUS(status));
- if (WEXITSTATUS(status) != 0)
- exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
-
- kid3 = 0;
- return 1;
-}
-/*
- * Extract pages 'first' through 'last' from the pdf and write them into a
- * temporary file.
- */
-static int pdf_extract_pages(char filename[PATH_MAX],
- const char *pdffilename,
- int first,
- int last)
+static int
+wait_for_renderer()
{
- char gscommand[CMDLINE_MAX];
- char filename_arg[PATH_MAX], first_arg[50], last_arg[50];
- int fd;
+ int status;
- _log("Extracting pages %d through %d\n", first, last);
+ waitpid(kid3, &status, 0);
- snprintf(filename, PATH_MAX, "%s/foomatic-XXXXXX", temp_dir());
- if ((fd = mkstemp(filename)) == -1)
- rip_die(EXIT_STARVED, "Unable to create temporary file!\n");
- close (fd);
+ if (!WIFEXITED(status))
+ {
+ _log("Kid3 did not finish normally.\n");
+ exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
+ }
- snprintf(filename_arg, PATH_MAX, "-sOutputFile=%s", filename);
+ _log("Kid3 exit status: %d\n", WEXITSTATUS(status));
+ if (WEXITSTATUS(status) != 0)
+ exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
- first_arg[0] = '\0';
- last_arg[0] = '\0';
- if (first > 1)
- {
- snprintf(first_arg, 50, "-dFirstPage=%d", first);
- if (last >= first)
- snprintf(last_arg, 50, "-dLastPage=%d", last);
- }
+ kid3 = 0;
+ return (1);
+}
- snprintf(gscommand, CMDLINE_MAX, "%s -q -dNOPAUSE -dBATCH -dSAFER -dNOINTERPOLATE -dNOMEDIAATTRS"
- "-sDEVICE=pdfwrite -dShowAcroForm %s %s %s %s",
- gspath, filename_arg, first_arg, last_arg, pdffilename);
- FILE *pd = popen(gscommand, "r");
- if (!pd)
- rip_die(EXIT_STARVED, "Could not run ghostscript to extract the pages!\n");
- pclose(pd);
+//
+// Extract pages 'first' through 'last' from the pdf and write them into a
+// temporary file.
+//
- return 1;
+static int
+pdf_extract_pages(char filename[PATH_MAX],
+ const char *pdffilename,
+ int first,
+ int last)
+{
+ char gscommand[CMDLINE_MAX];
+ char filename_arg[PATH_MAX], first_arg[50], last_arg[50];
+ int fd;
+
+ _log("Extracting pages %d through %d\n", first, last);
+
+ snprintf(filename, PATH_MAX, "%s/foomatic-XXXXXX", temp_dir());
+ if ((fd = mkstemp(filename)) == -1)
+ rip_die(EXIT_STARVED, "Unable to create temporary file!\n");
+ close (fd);
+
+ snprintf(filename_arg, PATH_MAX, "-sOutputFile=%s", filename);
+
+ first_arg[0] = '\0';
+ last_arg[0] = '\0';
+ if (first > 1)
+ {
+ snprintf(first_arg, 50, "-dFirstPage=%d", first);
+ if (last >= first)
+ snprintf(last_arg, 50, "-dLastPage=%d", last);
+ }
+
+ snprintf(gscommand, CMDLINE_MAX, "%s -q -dNOPAUSE -dBATCH -dSAFER -dNOINTERPOLATE -dNOMEDIAATTRS"
+ "-sDEVICE=pdfwrite -dShowAcroForm %s %s %s %s",
+ gspath, filename_arg, first_arg, last_arg, pdffilename);
+
+ FILE *pd = popen(gscommand, "r");
+ if (!pd)
+ rip_die(EXIT_STARVED, "Could not run ghostscript to extract the pages!\n");
+ pclose(pd);
+
+ return (1);
}
-static int render_pages_with_generic_command(dstr_t *cmd,
- const char *filename,
- int firstpage,
- int lastpage)
+
+static int
+render_pages_with_generic_command(dstr_t *cmd,
+ const char *filename,
+ int firstpage,
+ int lastpage)
{
- char tmpfile[PATH_MAX];
- int result;
+ char tmpfile[PATH_MAX];
+ int result;
- /* TODO it might be a good idea to give pdf command lines the possibility
- * to get the file on the command line rather than piped through stdin
- * (maybe introduce a &filename; ??) */
+ // TODO it might be a good idea to give pdf command lines the possibility
+ // to get the file on the command line rather than piped through stdin
+ // (maybe introduce a &filename; ??)
- if (lastpage < 0) /* i.e. print the whole document */
- dstrcatf(cmd, " < %s", filename);
- else
- {
- if (!pdf_extract_pages(tmpfile, filename, firstpage, lastpage))
- rip_die(EXIT_STARVED, "Could not run ghostscript to extract the pages!\n");
- dstrcatf(cmd, " < %s", tmpfile);
- }
+ if (lastpage < 0) // i.e. print the whole document
+ dstrcatf(cmd, " < %s", filename);
+ else
+ {
+ if (!pdf_extract_pages(tmpfile, filename, firstpage, lastpage))
+ rip_die(EXIT_STARVED,
+ "Could not run ghostscript to extract the pages!\n");
+ dstrcatf(cmd, " < %s", tmpfile);
+ }
- result = start_renderer(cmd->data);
+ result = start_renderer(cmd->data);
- if (lastpage > 0)
- unlink(tmpfile);
+ if (lastpage > 0)
+ unlink(tmpfile);
- return result;
+ return (result);
}
-static int render_pages_with_ghostscript(dstr_t *cmd,
- size_t start_gs_cmd,
- size_t end_gs_cmd,
- const char *filename,
- int firstpage,
- int lastpage)
-{
- char *p;
- /* No need to create a temporary file, just give ghostscript the file and
- * first/last page on the command line */
+static int
+render_pages_with_ghostscript(dstr_t *cmd,
+ size_t start_gs_cmd,
+ size_t end_gs_cmd,
+ const char *filename,
+ int firstpage,
+ int lastpage)
+{
+ char *p;
- /* Some command lines want to read from stdin */
- for (p = &cmd->data[end_gs_cmd -1]; isspace(*p); p--)
- ;
- if (*p == '-')
- *p = ' ';
+ // No need to create a temporary file, just give ghostscript the file and
+ // first/last page on the command line
- dstrinsertf(cmd, end_gs_cmd, " %s ", filename);
+ // Some command lines want to read from stdin
+ for (p = &cmd->data[end_gs_cmd -1]; isspace(*p); p--);
+ if (*p == '-')
+ *p = ' ';
- dstrinsertf(cmd, start_gs_cmd + 2, " -dShowAcroForm ");
-
- if (firstpage > 1)
- {
- if (lastpage >= firstpage)
- dstrinsertf(cmd, start_gs_cmd +2,
- " -dFirstPage=%d -dLastPage=%d ",
- firstpage, lastpage);
- else
- dstrinsertf(cmd, start_gs_cmd +2,
- " -dFirstPage=%d ", firstpage);
- }
+ dstrinsertf(cmd, end_gs_cmd, " %s ", filename);
- return start_renderer(cmd->data);
-}
+ dstrinsertf(cmd, start_gs_cmd + 2, " -dShowAcroForm ");
-static int render_pages(const char *filename, int firstpage, int lastpage)
-{
- dstr_t *cmd = create_dstr();
- size_t start, end;
- int result;
-
- build_commandline(optionset("currentpage"), cmd, 1);
-
- extract_command(&start, &end, cmd->data, "gs");
- if (start == end)
- /* command is not Ghostscript */
- result = render_pages_with_generic_command(cmd,
- filename,
- firstpage,
- lastpage);
+ if (firstpage > 1)
+ {
+ if (lastpage >= firstpage)
+ dstrinsertf(cmd, start_gs_cmd +2,
+ " -dFirstPage=%d -dLastPage=%d ",
+ firstpage, lastpage);
else
- /* Ghostscript command, tell it which pages we want to render */
- result = render_pages_with_ghostscript(cmd,
- start,
- end,
- filename,
- firstpage,
- lastpage);
-
- free_dstr(cmd);
- return result;
+ dstrinsertf(cmd, start_gs_cmd +2,
+ " -dFirstPage=%d ", firstpage);
+ }
+
+ return (start_renderer(cmd->data));
}
-static int print_pdf_file(const char *filename)
+
+static int
+render_pages(const char *filename,
+ int firstpage,
+ int lastpage)
{
- int page_count, i;
- int firstpage;
+ dstr_t *cmd = create_dstr();
+ size_t start, end;
+ int result;
+
+ build_commandline(optionset("currentpage"), cmd, 1);
+
+ extract_command(&start, &end, cmd->data, "gs");
+ if (start == end)
+ // command is not Ghostscript
+ result = render_pages_with_generic_command(cmd,
+ filename,
+ firstpage,
+ lastpage);
+ else
+ // Ghostscript command, tell it which pages we want to render
+ result = render_pages_with_ghostscript(cmd,
+ start,
+ end,
+ filename,
+ firstpage,
+ lastpage);
+
+ free_dstr(cmd);
+ return (result);
+}
- page_count = pdf_count_pages(filename);
- if (page_count < 0)
- rip_die(EXIT_JOBERR, "Unable to determine number of pages, page count: %d\n", page_count);
- _log("File contains %d pages\n", page_count);
- if (page_count == 0)
+static int
+print_pdf_file(const char *filename)
+{
+ int page_count, i;
+ int firstpage;
+
+ page_count = pdf_count_pages(filename);
+
+ if (page_count < 0)
+ rip_die(EXIT_JOBERR,
+ "Unable to determine number of pages, page count: %d\n",
+ page_count);
+ _log("File contains %d pages\n", page_count);
+ if (page_count == 0)
+ {
+ _log("No pages left, outputting empty file.\n");
+ return (1);
+ }
+
+ optionset_copy_values(optionset("header"), optionset("currentpage"));
+ optionset_copy_values(optionset("currentpage"), optionset("previouspage"));
+ firstpage = 1;
+ for (i = 1; i <= page_count; i++)
+ {
+ set_options_for_page(optionset("currentpage"), i);
+ if (!optionset_equal(optionset("currentpage"),
+ optionset("previouspage"), 1))
{
- _log("No pages left, outputting empty file.\n");
- return 1;
+ render_pages(filename, firstpage, i);
+ firstpage = i;
}
-
- optionset_copy_values(optionset("header"), optionset("currentpage"));
optionset_copy_values(optionset("currentpage"), optionset("previouspage"));
- firstpage = 1;
- for (i = 1; i <= page_count; i++)
- {
- set_options_for_page(optionset("currentpage"), i);
- if (!optionset_equal(optionset("currentpage"), optionset("previouspage"), 1))
- {
- render_pages(filename, firstpage, i);
- firstpage = i;
- }
- optionset_copy_values(optionset("currentpage"), optionset("previouspage"));
- }
- if (firstpage == 1)
- render_pages(filename, 1, -1); /* Render the whole document */
- else
- render_pages(filename, firstpage, page_count);
+ }
+ if (firstpage == 1)
+ render_pages(filename, 1, -1); // Render the whole document
+ else
+ render_pages(filename, firstpage, page_count);
- wait_for_renderer();
+ wait_for_renderer();
- return 1;
+ return (1);
}
-int print_pdf(FILE *s,
- const char *alreadyread,
- size_t len,
- const char *filename,
- size_t startpos)
+
+int
+print_pdf(FILE *s,
+ const char *alreadyread,
+ size_t len,
+ const char *filename,
+ size_t startpos)
{
- char tmpfilename[PATH_MAX] = "";
- int result;
+ char tmpfilename[PATH_MAX] = "";
+ int result;
- /* If reading from stdin, write everything into a temporary file */
- /* TODO don't do this if there aren't any pagerange-limited options */
- if (s == stdin)
- {
- int fd;
- FILE *tmpfile;
+ // If reading from stdin, write everything into a temporary file
+ // TODO don't do this if there aren't any pagerange-limited options
+ if (s == stdin)
+ {
+ int fd;
+ FILE *tmpfile;
- snprintf(tmpfilename, PATH_MAX, "%s/foomatic-XXXXXX", temp_dir());
- fd = mkstemp(tmpfilename);
- if (fd < 0) {
- _log("Could not create temporary file: %s\n", strerror(errno));
- return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
- }
+ snprintf(tmpfilename, PATH_MAX, "%s/foomatic-XXXXXX", temp_dir());
+ fd = mkstemp(tmpfilename);
+ if (fd < 0)
+ {
+ _log("Could not create temporary file: %s\n", strerror(errno));
+ return (EXIT_PRNERR_NORETRY_BAD_SETTINGS);
+ }
- tmpfile = fdopen(fd, "r+");
- copy_file(tmpfile, stdin, alreadyread, len);
- fclose(tmpfile);
+ tmpfile = fdopen(fd, "r+");
+ copy_file(tmpfile, stdin, alreadyread, len);
+ fclose(tmpfile);
- filename = tmpfilename;
- }
+ filename = tmpfilename;
+ }
- result = print_pdf_file(filename);
+ result = print_pdf_file(filename);
- if (!isempty(tmpfilename))
- unlink(tmpfilename);
+ if (!isempty(tmpfilename))
+ unlink(tmpfilename);
- return result;
+ return (result);
}
-/* pdf.h
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// pdf.h
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#ifndef pdf_h
#define pdf_h
-int print_pdf(FILE *s, const char *alreadyread, size_t len, const char *filename, size_t startpos);
+int print_pdf(FILE *s, const char *alreadyread, size_t len,
+ const char *filename, size_t startpos);
int pdf_count_pages(const char *filename);
-#endif
-
+#endif // !pdf_h
-/* postscript.c
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// postscript.c
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#include "foomaticrip.h"
#include "util.h"
#define LT_BEGIN_FEATURE 1
#define LT_FOOMATIC_RIP_OPTION_SETTING 2
-int line_type(const char *line)
+
+
+int
+line_type(const char *line)
{
- const char *p;
- if (startswith(line, "%%BeginFeature:"))
- return LT_BEGIN_FEATURE;
- p = line;
- while (*p && isspace(*p)) p++;
- if (!startswith(p, "%%"))
- return 0;
- p += 2;
- while (*p && isspace(*p)) p++;
- if (startswith(p, "FoomaticRIPOptionSetting:"))
- return LT_FOOMATIC_RIP_OPTION_SETTING;
- return 0;
+ const char *p;
+ if (startswith(line, "%%BeginFeature:"))
+ return (LT_BEGIN_FEATURE);
+ p = line;
+ while (*p && isspace(*p)) p++;
+ if (!startswith(p, "%%"))
+ return (0);
+ p += 2;
+ while (*p && isspace(*p)) p++;
+ if (startswith(p, "FoomaticRIPOptionSetting:"))
+ return (LT_FOOMATIC_RIP_OPTION_SETTING);
+ return (0);
}
-/* Next, examine the PostScript job for traces of command-line and
- JCL options. PPD-aware applications and spoolers stuff option
- settings directly into the file, they do not necessarily send
- PPD options by the command line. Also stuff in PostScript code
- to apply option settings given by the command line and to set
- the defaults given in the PPD file.
-
- Examination strategy: read lines from STDIN until the first
- %%Page: comment appears and save them as @psheader. This is the
- page-independent header part of the PostScript file. The
- PostScript interpreter (renderer) must execute this part once
- before rendering any assortment of pages. Then pages can be
- printed in any arbitrary selection or order. All option
- settings we find here will be collected in the default option
- set for the RIP command line.
-
- Now the pages will be read and sent to the renderer, one after
- the other. Every page is read into memory until the
- %%EndPageSetup comment appears (or a certain amount of lines was
- read). So we can get option settings only valid for this
- page. If we have such settings we set them in the modified
- command set for this page.
-
- If the renderer is not running yet (first page) we start it with
- the command line built from the current modified command set and
- send the first page to it, in the end we leave the renderer
- running and keep input and output pipes open, so that it can
- accept further pages. If the renderer is still running from
- the previous page and the current modified command set is the
- same as the one for the previous page, we send the page. If
- the command set is different, we close the renderer, re-start
- it with the command line built from the new modified command
- set, send the header again, and then the page.
-
- After the last page the trailer (%%Trailer) is sent.
-
- The output pipe of this program stays open all the time so that
- the spooler does not assume that the job has finished when the
- renderer is re-started.
-
- Non DSC-conforming documents will be read until a certain line
- number is reached. Command line or JCL options inserted later
- will be ignored.
-
- If options are implemented by PostScript code supposed to be
- stuffed into the job's PostScript data we stuff the code for all
- these options into our job data, So all default settings made in
- the PPD file (the user can have edited the PPD file to change
- them) are taken care of and command line options get also
- applied. To give priority to settings made by applications we
- insert the options's code in the beginnings of their respective
- sections, so that sommething, which is already inserted, gets
- executed after our code. Missing sections are automatically
- created. In non-DSC-conforming files we insert the option code
- in the beginning of the file. This is the same policy as used by
- the "pstops" filter of CUPS.
-
- If CUPS is the spooler, the option settings were already
- inserted by the "pstops" filter, so we don't insert them
- again. The only thing we do is correcting settings of numerical
- options when they were set to a value not available as choice in
- the PPD file, As "pstops" does not support "real" numerical
- options, it sees these settings as an invalid choice and stays
- with the default setting. In this case we correct the setting in
- the first occurence of the option's code, as this one is the one
- added by CUPS, later occurences come from applications and
- should not be touched.
-
- If the input is not PostScript (if there is no "%!" after
- $maxlinestopsstart lines) we will abort the document with an error.
-*/
-
-/* PostScript sections */
+//
+// Next, examine the PostScript job for traces of command-line and
+// JCL options. PPD-aware applications and spoolers stuff option
+// settings directly into the file, they do not necessarily send
+// PPD options by the command line. Also stuff in PostScript code
+// to apply option settings given by the command line and to set
+// the defaults given in the PPD file.
+//
+// Examination strategy: read lines from STDIN until the first
+// %%Page: comment appears and save them as @psheader. This is the
+// page-independent header part of the PostScript file. The
+// PostScript interpreter (renderer) must execute this part once
+// before rendering any assortment of pages. Then pages can be
+// printed in any arbitrary selection or order. All option
+// settings we find here will be collected in the default option
+// set for the RIP command line.
+//
+// Now the pages will be read and sent to the renderer, one after
+// the other. Every page is read into memory until the
+// %%EndPageSetup comment appears (or a certain amount of lines was
+// read). So we can get option settings only valid for this
+// page. If we have such settings we set them in the modified
+// command set for this page.
+//
+// If the renderer is not running yet (first page) we start it with
+// the command line built from the current modified command set and
+// send the first page to it, in the end we leave the renderer
+// running and keep input and output pipes open, so that it can
+// accept further pages. If the renderer is still running from
+// the previous page and the current modified command set is the
+// same as the one for the previous page, we send the page. If
+// the command set is different, we close the renderer, re-start
+// it with the command line built from the new modified command
+// set, send the header again, and then the page.
+//
+// After the last page the trailer (%%Trailer) is sent.
+//
+// The output pipe of this program stays open all the time so that
+// the spooler does not assume that the job has finished when the
+// renderer is re-started.
+//
+// Non DSC-conforming documents will be read until a certain line
+// number is reached. Command line or JCL options inserted later
+// will be ignored.
+//
+// If options are implemented by PostScript code supposed to be
+// stuffed into the job's PostScript data we stuff the code for all
+// these options into our job data, So all default settings made in
+// the PPD file (the user can have edited the PPD file to change
+// them) are taken care of and command line options get also
+// applied. To give priority to settings made by applications we
+// insert the options's code in the beginnings of their respective
+// sections, so that sommething, which is already inserted, gets
+// executed after our code. Missing sections are automatically
+// created. In non-DSC-conforming files we insert the option code
+// in the beginning of the file. This is the same policy as used by
+// the "pstops" filter of CUPS.
+//
+// If CUPS is the spooler, the option settings were already
+// inserted by the "pstops" filter, so we don't insert them
+// again. The only thing we do is correcting settings of numerical
+// options when they were set to a value not available as choice in
+// the PPD file, As "pstops" does not support "real" numerical
+// options, it sees these settings as an invalid choice and stays
+// with the default setting. In this case we correct the setting in
+// the first occurence of the option's code, as this one is the one
+// added by CUPS, later occurences come from applications and
+// should not be touched.
+//
+// If the input is not PostScript (if there is no "%!" after
+// $maxlinestopsstart lines) we will abort the document with an error.
+//
+
+
+// PostScript sections
#define PS_SECTION_JCLSETUP 1
#define PS_SECTION_PROLOG 2
#define PS_SECTION_SETUP 3
#define MAX_NON_DSC_LINES_IN_HEADER 1000
#define MAX_LINES_FOR_PAGE_OPTIONS 200
-typedef struct {
- size_t pos;
+typedef struct
+{
+ size_t pos;
- FILE *file;
- const char *alreadyread;
- size_t len;
+ FILE *file;
+ const char *alreadyread;
+ size_t len;
} stream_t;
+
void _print_ps(stream_t *stream);
-int stream_next_line(dstr_t *line, stream_t *s)
+
+int
+stream_next_line(dstr_t *line,
+ stream_t *s)
{
- int c;
- size_t cnt = 0;
-
- dstrclear(line);
- while (s->pos < s->len) {
- c = s->alreadyread[s->pos++];
- dstrputc(line, c);
- cnt++;
- if (c == '\n')
- return cnt;
+ int c;
+ size_t cnt = 0;
+
+ dstrclear(line);
+ while (s->pos < s->len)
+ {
+ c = s->alreadyread[s->pos++];
+ dstrputc(line, c);
+ cnt++;
+ if (c == '\n')
+ return (cnt);
+ }
+
+ while ((c = fgetc(s->file)) != EOF)
+ {
+ dstrputc(line, c);
+ cnt++;
+ if (c == '\n')
+ return (cnt);
+ }
+ return (cnt);
+}
+
+
+int
+print_ps(FILE *file,
+ const char *alreadyread,
+ size_t len,
+ const char *filename)
+{
+ stream_t stream;
+ char gscommand[65536];
+ int pagefound = 0;
+ FILE *in, *out;
+ pid_t pid;
+ char buf[4096];
+ struct pollfd pfd;
+ size_t bytes, bytes_sent;
+ char *pos;
+ int pres;
+ dstr_t *line = create_dstr();
+ dstr_t *data_read = create_dstr();
+
+
+ // Define input data stream for reading
+ stream.pos = 0;
+ stream.file = file;
+ stream.alreadyread = alreadyread;
+ stream.len = len;
+
+ // If a buffer is supplied but with zero length, we are in streaming
+ // mode and do not pre-check for zero-page input, but print right away
+ if (alreadyread && len == 0)
+ // Simply print the file, without checking whether it has pages
+ _print_ps(&stream);
+ else
+ {
+ //
+ // Check whether the input file is not empty
+ //
+ // We only read the input data until discovering the first page, this
+ // way we can print PostScript files streaming, allowing for very large
+ // or even infinite PostScript jobs, making use of the fact that
+ // PostScript is a streamable data format.
+ //
+ // This also allows Printer Applications to work with foomatic-rip
+ // as they have to support streaming Apple/PWG Raster input data and
+ // infinite jobs in this format. This way we can simply encapsulate the
+ // Raster data in PostScript.
+ //
+ // Ghostscript command line to find out whether the PostScript input
+ // data actually produces pages. The "bbox" output device produces two
+ // lines of output per page on stderr. We suppress any general output
+ // lines ("-q") an redirect the "bbox" output to stdout, where we can
+ // read it.
+ //
+ // "-dDEVICEWIDTHPOINTS=1 -dDEVICEHEIGHTPOINTS=1" saves Ghostscript
+ // from needing to render the pages to find out the numbers in the input
+ // lines, we only need the boolean answer whether there are pages or
+ // not
+ //
+
+ snprintf(gscommand, 65536, "%s -q -dNOPAUSE -dBATCH -sDEVICE=bbox -dDEVICEWIDTHPOINTS=1 -dDEVICEHEIGHTPOINTS=1 -_ 2>&1",
+ CUPS_GHOSTSCRIPT);
+ // Launch Ghostscript an return file handles for stdin and stdout of the
+ // Ghostscript process
+ pid = start_system_process("Check PostScript input non-empty", gscommand,
+ &in, &out);
+ // We will observe Ghostscript's output with non-blocking poll(), prepare
+ // data structure
+ pfd.fd = fileno(out);
+ pfd.events = POLLIN;
+
+ // Read input as long as we do not find a page ("showpage" action in
+ // PostScript, makes the "bbox" device producing output)
+ while ((stream_next_line(line, &stream)) > 0)
+ {
+ // Save what we have already read, we need to re-feed it when actually
+ // rendering the job
+ dstrncat(data_read, line->data, line->len);
+ // Feed read line into Ghostscript
+ for (bytes = line->len, pos = line->data, bytes_sent = 0;
+ bytes_sent >= 0 && bytes_sent < bytes;
+ bytes -= bytes_sent, pos += bytes_sent)
+ bytes_sent = fwrite_or_die(pos, 1, bytes, in);
+ if (bytes_sent < 0)
+ break;
+ // Flush to make Ghostscript operate in as close to real-time as
+ // possible
+ fflush(in);
+ // Check if Ghostscript produced output, but do not block if not
+ // (timeout = 0)
+ pres = poll(&pfd, 1, 0);
+ if (pres < 0)
+ {
+ _log("Error reading Ghostscript output\n");
+ break;
+ }
+ else if (pres && (pfd.revents & POLLIN))
+ {
+ // Ghostscript produced output, meaning that the data read up to now
+ // has produced a page and so the file is not empty, stop reading
+ // further data
+ pagefound = 1;
+ break;
+ }
+ }
+
+ // If the input file has only a single page and the "showpage" is
+ // very close to the end of the file, it cannot have been
+ // discovered after the last bits of input data got
+ // read. Therefore we do an extra check here.
+ if (!pagefound)
+ {
+ pres = poll(&pfd, 1, 1000);
+ if (pres < 0)
+ _log("Error reading Ghostscript output\n");
+ else if (pres && (pfd.revents & POLLIN))
+ pagefound = 1;
}
- while ((c = fgetc(s->file)) != EOF) {
- dstrputc(line, c);
- cnt++;
- if (c == '\n')
- return cnt;
+ // Clean up and make Ghostscript stop by that
+ fclose(in);
+ fclose(out);
+ wait_for_process(pid);
+
+ if (pagefound)
+ {
+ _log("File not empty, contains at least one page.\n");
+
+ // Redefine stream for what we have read now
+ if (data_read->len < len)
+ dstrncat(data_read, buf + data_read->len, len - data_read->len);
+
+ stream.pos = 0;
+ stream.file = file;
+ stream.alreadyread = data_read->data;
+ stream.len = data_read->len;
+
+ // Print the file
+ _print_ps(&stream);
}
- return cnt;
+ else
+ _log("No pages left, outputting empty file.\n");
+
+ free_dstr(data_read);
+ }
+
+ return (1);
}
-int print_ps(FILE *file, const char *alreadyread, size_t len, const char *filename)
+
+void
+_print_ps(stream_t *stream)
{
- stream_t stream;
- char gscommand[65536];
- int pagefound = 0;
- FILE *in, *out;
- pid_t pid;
- char buf[4096];
- struct pollfd pfd;
- size_t bytes, bytes_sent;
- char *pos;
- int pres;
- dstr_t *line = create_dstr();
- dstr_t *data_read = create_dstr();
-
-
- /* Define input data stream for reading */
- stream.pos = 0;
- stream.file = file;
- stream.alreadyread = alreadyread;
- stream.len = len;
-
- /* If a buffer is supplied but with zero length, we are in streaming
- mode and do not pre-check for zero-page input, but print right away */
- if (alreadyread && len == 0)
- /* Simply print the file, without checking whether it has pages */
- _print_ps(&stream);
- else {
- /* Check whether the input file is not empty
-
- We only read the input data until discovering the first page, this
- way we can print PostScript files streaming, allowing for very large
- or even infinite PostScript jobs, making use of the fact that
- PostScript is a streamable data format.
-
- This also allows Printer Applications to work with foomatic-rip
- as they have to support streaming Apple/PWG Raster input data and
- infinite jobs in this format. This way we can simply encapsulate the
- Raster data in PostScript.
-
- Ghostscript command line to find out whether the PostScript input
- data actually produces pages. The "bbox" output device produces two
- lines of output per page on stderr. We suppress any general output
- lines ("-q") an redirect the "bbox" output to stdout, where we can
- read it.
-
- "-dDEVICEWIDTHPOINTS=1 -dDEVICEHEIGHTPOINTS=1" saves Ghostscript
- from needing to render the pages to find out the numbers in the input
- lines, we only need the boolean answer whether there are pages or
- not */
- snprintf(gscommand, 65536, "%s -q -dNOPAUSE -dBATCH -sDEVICE=bbox -dDEVICEWIDTHPOINTS=1 -dDEVICEHEIGHTPOINTS=1 -_ 2>&1",
- CUPS_GHOSTSCRIPT);
- /* Launch Ghostscript an return file handles for stdin and stdout of the
- Ghostscript process */
- pid = start_system_process("Check PostScript input non-empty", gscommand, &in, &out);
- /* We will observe Ghostscript's output with non-blocking poll(), prepare
- data structure */
- pfd.fd = fileno(out);
- pfd.events = POLLIN;
-
- /* Read input as long as we do not find a page ("showpage" action in
- PostScript, makes the "bbox" device producing output) */
- while ((stream_next_line(line, &stream)) > 0) {
- /* Save what we have already read, we need to re-feed it when actually
- rendering the job */
- dstrncat(data_read, line->data, line->len);
- /* Feed read line into Ghostscript */
- for (bytes = line->len, pos = line->data, bytes_sent = 0;
- bytes_sent >= 0 && bytes_sent < bytes;
- bytes -= bytes_sent, pos += bytes_sent)
- bytes_sent = fwrite_or_die(pos, 1, bytes, in);
- if (bytes_sent < 0)
- break;
- /* Flush to make Ghostscript operate in as close to real-time as
- possible */
- fflush(in);
- /* Check if Ghostscript produced output, but do not block if not
- (timeout = 0) */
- pres = poll(&pfd, 1, 0);
- if (pres < 0) {
- _log("Error reading Ghostscript output\n");
- break;
- } else if (pres && (pfd.revents & POLLIN)) {
- /* Ghostscript produced output, meaning that the data read up to now
- has produced a page and so the file is not empty, stop reading
- further data */
- pagefound = 1;
- break;
+ char *p;
+
+ int maxlines = 1000; // Maximum number of lines to be read when the
+ // documenent is not DSC-conforming.
+ // "$maxlines = 0" means that all will be read and
+ // examined. If it is discovered that the input
+ // file is DSC-conforming, this will be set to 0.
+
+ int maxlinestopsstart = 200; // That many lines are allowed until the
+ // "%!" indicating PS comes. These
+ // additional lines in the
+ // beginning are usually JCL
+ // commands. The lines will be
+ // ignored by our parsing but
+ // passed through.
+
+ int printprevpage = 0; // We set this when encountering "%%Page:" and the
+ // previous page is not printed yet. Then it will
+ // be printed and the new page will be prepared in
+ // the next run of the loop (we don't read a new
+ // line and don't increase the $linect then).
+
+ int linect = 0; // how many lines have we examined
+ int nonpslines = 0; // lines before "%!" found yet.
+ int more_stuff = 1; // there is more stuff in stdin
+ int saved = 0; // DSC line not precessed yet
+ int isdscjob = 0; // is the job dsc conforming
+ int inheader = 1; // Are we still in the header, before first
+ // "%%Page:" comment=
+
+ int optionsalsointoheader = 0; // 1: We are in a "%%BeginSetup...
+ // %%EndSetup" section after the first
+ // "%%Page:..." line (OpenOffice.org
+ // does this and intends the options here
+ // apply to the whole document and not
+ // only to the current page). We have to
+ // add all lines also to the end of the
+ // @psheader now and we have to set
+ // non-PostScript options also in the
+ // "header" optionset. 0: otherwise.
+
+ int insertoptions = 1; // If we find out that a file with a DSC magic
+ // string ("%!PS-Adobe-") is not really DSC-
+ // conforming, we insert the options directly
+ // after the line with the magic string. We use
+ // this variable to store the number of the line
+ // with the magic string
+
+ int prologfound = 0; // Did we find the
+ // "%%BeginProlog...%%EndProlog" section?
+ int setupfound = 0; // Did we find the
+ // "%%BeginSetup...%%EndSetup" section?
+ int pagesetupfound = 0; // special page setup handling needed
+
+ int inprolog = 0; // We are between "%%BeginProlog" and "%%EndProlog"
+ int insetup = 0; // We are between "%%BeginSetup" and "%%EndSetup"
+ int infeature = 0; // We are between "%%BeginFeature" and "%%EndFeature"
+
+ int optionreplaced = 0; // Will be set to 1 when we are in an
+ // option ("%%BeginFeature...
+ // %%EndFeature") which we have replaced.
+
+ int postscriptsection = PS_SECTION_JCLSETUP;
+ // In which section of the PostScript file
+ // are we currently ?
+
+ int nondsclines = 0; // Number of subsequent lines found which are at a
+ // non-DSC-conforming place, between the sections
+ // of the header.
+
+ int nestinglevel = 0; // Are we in the main document (0) or in an
+ // embedded document bracketed by "%%BeginDocument"
+ // and "%%EndDocument" (>0) We do not parse the
+ // PostScript in an embedded document.
+
+ int inpageheader = 0; // Are we in the header of a page,
+ // between "%%BeginPageSetup" and
+ // "%%EndPageSetup" (1) or not (0).
+
+ int passthru = 0; // 0: write data into psfifo,
+ // 1: pass data directly to the renderer
+
+ int lastpassthru = 0; // State of 'passthru' in previous line
+ // (to allow debug output when $passthru
+ // switches.
+
+ int ignorepageheader = 0; // Will be set to 1 as soon as active
+ // code (not between "%%BeginPageSetup"
+ // and "%%EndPageSetup") appears after a
+ // "%%Page:" comment. In this case
+ // "%%BeginPageSetup" and
+ // "%%EndPageSetup" is not allowed any
+ // more on this page and will be ignored.
+ // Will be set to 0 when a new "%%Page:"
+ // comment appears.
+
+ int optset = optionset("header"); // Where do the option settings which
+ // we have found go?
+
+ // current line
+ dstr_t *line = create_dstr();
+
+ dstr_t *onelinebefore = create_dstr();
+ dstr_t *twolinesbefore = create_dstr();
+
+ // The header of the PostScript file, to be send after each start of the
+ // renderer
+ dstr_t *psheader = create_dstr();
+
+ // The input FIFO, data which we have pulled from stdin for examination,
+ // but not send to the renderer yet
+ dstr_t *psfifo = create_dstr();
+
+ int ignoreline;
+
+ int ooo110 = 0; // Flag to work around an application bug
+
+ int currentpage = 0; // The page which we are currently printing
+
+ option_t *o;
+ const char *val;
+
+ int linetype;
+
+ dstr_t *linesafterlastbeginfeature = create_dstr();
+ // All codelines after the last "%%BeginFeature"
+
+ char optionname [128];
+ char value [128];
+ int fromcomposite = 0;
+
+ dstr_t *pdest;
+
+ double width, height;
+
+ pid_t rendererpid = 0;
+ FILE *rendererhandle = NULL;
+
+ int retval;
+
+ dstr_t *tmp = create_dstr();
+ jobhasjcl = 0;
+
+ // We do not parse the PostScript to find Foomatic options, we check
+ // only whether we have PostScript.
+ if (dontparse)
+ maxlines = 1;
+
+ _log("Reading PostScript input ...\n");
+
+ do
+ {
+ ignoreline = 0;
+
+ if (printprevpage || saved || stream_next_line(line, stream))
+ {
+ saved = 0;
+ if (linect == nonpslines)
+ {
+ // In the beginning should be the postscript leader,
+ // sometimes after some JCL commands
+ if (!(line->data[0] == '%' && line->data[1] == '!') &&
+ !(line->data[1] == '%' && line->data[2] == '!'))
+ // There can be a Windows control character before "%!"
+ {
+ nonpslines++;
+ if (maxlines == nonpslines)
+ maxlines ++;
+ jobhasjcl = 1;
+
+ if (nonpslines > maxlinestopsstart)
+ {
+ // This is not a PostScript job, abort it
+ _log("Job does not start with \"%%!\", is it Postscript?\n");
+ rip_die(EXIT_JOBERR, "Unknown data format.\n");
+ }
+ }
+ else
+ {
+ // Do we have a DSC-conforming document?
+ if ((line->data[0] == '%' && startswith(line->data, "%!PS-Adobe-")) ||
+ (line->data[1] == '%' && startswith(line->data, "%!PS-Adobe-")))
+ {
+ // Do not stop parsing the document
+ if (!dontparse)
+ {
+ maxlines = 0;
+ isdscjob = 1;
+ insertoptions = linect + 1;
+ // We have written into psfifo before, now we continue in
+ // psheader and move over the data which is already in psfifo
+ dstrcat(psheader, psfifo->data);
+ dstrclear(psfifo);
+ }
+ _log("--> This document is DSC-conforming!\n");
+ }
+ else
+ {
+ // Job is not DSC-conforming, stick in all PostScript
+ // option settings in the beginning
+ append_prolog_section(line, optset, 1);
+ append_setup_section(line, optset, 1);
+ append_page_setup_section(line, optset, 1);
+ prologfound = 1;
+ setupfound = 1;
+ pagesetupfound = 1;
+ }
}
}
-
- /* If the input file has only a single page and the "showpage" is
- very close to the end of the file, it cannot have been
- discovered after the last bits of input data got
- read. Therefore we do an extra check here. */
- if (!pagefound) {
- pres = poll(&pfd, 1, 1000);
- if (pres < 0)
- _log("Error reading Ghostscript output\n");
- else if (pres && (pfd.revents & POLLIN))
- pagefound = 1;
+ else
+ {
+ if (startswith(line->data, "%"))
+ {
+ if (startswith(line->data, "%%BeginDocument"))
+ {
+ // Beginning of an embedded document
+ // Note that Adobe Acrobat has a bug and so uses
+ // "%%BeginDocument " instead of "%%BeginDocument:"
+ nestinglevel++;
+ _log("Embedded document, nesting level now: %d\n", nestinglevel);
+ }
+ else if (nestinglevel > 0 &&
+ startswith(line->data, "%%EndDocument"))
+ {
+ // End of an embedded document
+ nestinglevel--;
+ _log("End of embedded document, nesting level now: %d\n",
+ nestinglevel);
+ }
+ else if (nestinglevel == 0 && startswith(line->data, "%%Creator"))
+ {
+ // Here we set flags to treat particular bugs of the
+ // PostScript produced by certain applications
+ p = strstr(line->data, "%%Creator") + 9;
+ while (*p && (isspace(*p) || *p == ':'))
+ p++;
+ if (!strcmp(p, "OpenOffice.org"))
+ {
+ p += 14;
+ while (*p && isspace(*p))
+ p++;
+ if (sscanf(p, "1.1.%d", &ooo110) == 1)
+ {
+ _log("Document created with OpenOffice.org 1.1.x\n");
+ ooo110 = 1;
+ }
+ }
+ else if (!strcmp(p, "StarOffice 8"))
+ {
+ p += 12;
+ _log("Document created with StarOffice 8\n");
+ ooo110 = 1;
+ }
+ }
+ else if (nestinglevel == 0 &&
+ startswith(line->data, "%%BeginProlog"))
+ {
+ // Note: Below is another place where a "Prolog" section
+ // start will be considered. There we assume start of the
+ // "Prolog" if the job is DSC-Conformimg, but an arbitrary
+ // comment starting with "%%Begin", but not a comment
+ // explicitly treated here, is found. This is done because
+ // many "dvips" (TeX/LaTeX) files miss the "%%BeginProlog"
+ // comment.
+ // Beginning of Prolog
+ _log("\n-----------\nFound: %%%%BeginProlog\n");
+ inprolog = 1;
+ if (inheader)
+ postscriptsection = PS_SECTION_PROLOG;
+ nondsclines = 0;
+ // Insert options for "Prolog"
+ if (!prologfound)
+ {
+ append_prolog_section(line, optset, 0);
+ prologfound = 1;
+ }
+ }
+ else if (nestinglevel == 0 && startswith(line->data, "%%EndProlog"))
+ {
+ // End of Prolog
+ _log("Found: %%%%EndProlog\n");
+ inprolog = 0;
+ insertoptions = linect +1;
+ }
+ else if (nestinglevel == 0 && startswith(line->data, "%%BeginSetup"))
+ {
+ // Beginning of Setup
+ _log("\n-----------\nFound: %%%%BeginSetup\n");
+ insetup = 1;
+ nondsclines = 0;
+ // We need to distinguish with the $inheader variable
+ // here whether we are in the header or on a page, as
+ // OpenOffice.org inserts a "%%BeginSetup...%%EndSetup"
+ // section after the first "%%Page:..." line and assumes
+ // this section to be valid for all pages.
+ if (inheader)
+ {
+ postscriptsection = PS_SECTION_SETUP;
+ // If there was no "Prolog" but there are
+ // options for the "Prolog", push a "Prolog"
+ // with these options onto the psfifo here
+ if (!prologfound)
+ {
+ dstrclear(tmp);
+ append_prolog_section(tmp, optset, 1);
+ dstrprepend(line, tmp->data);
+ prologfound = 1;
+ }
+ // Insert options for "DocumentSetup" or "AnySetup"
+ if (spooler != SPOOLER_CUPS && !setupfound)
+ {
+ // For non-CUPS spoolers or no spooler at all,
+ // we leave everythnig as it is
+ append_setup_section(line, optset, 0);
+ setupfound = 1;
+ }
+ }
+ else
+ {
+ // Found option settings must be stuffed into both
+ // the header and the currrent page now. They will
+ // be written into both the "header" and the
+ // "currentpage" optionsets and the PostScript code
+ // lines of this section will not only go into the
+ // output stream, but also added to the end of the
+ // @psheader, so that they get repeated (to preserve
+ // the embedded PostScript option settings) on a
+ // restart of the renderer due to command line
+ // option changes
+ optionsalsointoheader = 1;
+ _log("\"%%%%BeginSetup\" in page header\n");
+ }
+ }
+ else if (nestinglevel == 0 && startswith(line->data, "%%EndSetup"))
+ {
+ // End of Setup
+ _log("Found: %%%%EndSetup\n");
+ insetup = 0;
+ if (inheader)
+ insertoptions = linect + 1;
+ else
+ {
+ // The "%%BeginSetup...%%EndSetup" which
+ // OpenOffice.org has inserted after the first
+ // "%%Page:..." line ends here, so the following
+ // options go only onto the current page again
+ optionsalsointoheader = 0;
+ }
+ }
+ else if (nestinglevel == 0 && startswith(line->data, "%%Page:"))
+ {
+ if (!lastpassthru && !inheader)
+ {
+ // In the last line we were not in passthru mode,
+ // so the last page is not printed. Prepare to do
+ // it now.
+ printprevpage = 1;
+ passthru = 1;
+ _log("New page found but previous not printed, print it now.\n");
+ }
+ else
+ {
+ // the previous page is printed, so we can prepare
+ // the current one
+ _log("\n-----------\nNew page: %s", line->data);
+ printprevpage = 0;
+ currentpage++;
+ // We consider the beginning of the page already as
+ // page setup section, as some apps do not use
+ // "%%PageSetup" tags.
+ postscriptsection = PS_SECTION_PAGESETUP;
+
+ // TODO can this be removed?
+ // Save PostScript state before beginning the page
+ // $line .= "/foomatic-saved-state save def\n";
+
+ // Here begins a new page
+ if (inheader)
+ {
+ build_commandline(optset, NULL, 0);
+ // Here we add some stuff which still
+ // belongs into the header
+ dstrclear(tmp);
+
+ // If there was no "Setup" but there are
+ // options for the "Setup", push a "Setup"
+ // with these options onto the @psfifo here
+ if (!setupfound)
+ {
+ append_setup_section(tmp, optset, 1);
+ setupfound = 1;
+ }
+ // If there was no "Prolog" but there are
+ // options for the "Prolog", push a "Prolog"
+ // with these options onto the @psfifo here
+ if (!prologfound)
+ {
+ append_prolog_section(tmp, optset, 1);
+ prologfound = 1;
+ }
+ // Now we push this into the header
+ dstrcat(psheader, tmp->data);
+
+ // The first page starts, so header ends
+ inheader = 0;
+ nondsclines = 0;
+ // Option setting should go into the page
+ // specific option set now
+ optset = optionset("currentpage");
+ }
+ else
+ {
+ // Restore PostScript state after completing the
+ // previous page:
+ //
+ // foomatic-saved-state restore
+ // %%Page: ...
+ // /foomatic-saved-state save def
+ //
+ // Print this directly, so that if we need to
+ // restart the renderer for this page due to
+ // a command line change this is done under the
+ // old instance of the renderer
+ // rint $rendererhandle
+ // "foomatic-saved-state restore\n";
+
+ // Save the option settings of the previous page
+ optionset_copy_values(optionset("currentpage"),
+ optionset("previouspage"));
+ optionset_delete_values(optionset("currentpage"));
+ }
+ // Initialize the option set
+ optionset_copy_values(optionset("header"),
+ optionset("currentpage"));
+
+ // Set the command line options which apply only
+ // to given pages
+ set_options_for_page(optionset("currentpage"), currentpage);
+ pagesetupfound = 0;
+ if (spooler == SPOOLER_CUPS)
+ {
+ // Remove the "notfirst" flag from all options
+ // forseen for the "PageSetup" section, because
+ // when these are numerical options for CUPS.
+ // they have to be set to the correct value
+ // for every page
+ for (o = optionlist; o; o = o->next)
+ {
+ if (option_get_section(o ) == SECTION_PAGESETUP)
+ o->notfirst = 0;
+ }
+ }
+ // Now the page header comes, so buffer the data,
+ // because we must perhaps shut down and restart
+ // the renderer
+ passthru = 0;
+ ignorepageheader = 0;
+ optionsalsointoheader = 0;
+ }
+ }
+ else if (nestinglevel == 0 && !ignorepageheader &&
+ startswith(line->data, "%%BeginPageSetup"))
+ {
+ // Start of the page header, up to %%EndPageSetup
+ // nothing of the page will be drawn, page-specific
+ // option settngs (as letter-head paper for page 1)
+ // go here
+ _log("\nFound: %%%%BeginPageSetup\n");
+ passthru = 0;
+ inpageheader = 1;
+ postscriptsection = PS_SECTION_PAGESETUP;
+ optionsalsointoheader = (ooo110 && currentpage == 1) ? 1 : 0;
+ // Insert PostScript option settings
+ // (options for section "PageSetup")
+ if (isdscjob)
+ {
+ append_page_setup_section(line, optset, 0);
+ pagesetupfound = 1;
+ }
+ }
+ else if (nestinglevel == 0 && !ignorepageheader &&
+ startswith(line->data, "%%BeginPageSetup"))
+ {
+ // End of the page header, the page is ready to be printed
+ _log("Found: %%%%EndPageSetup\n");
+ _log("End of page header\n");
+ // We cannot for sure say that the page header ends here
+ // OpenOffice.org puts (due to a bug) a "%%BeginSetup...
+ // %%EndSetup" section after the first "%%Page:...". It
+ // is possible that CUPS inserts a "%%BeginPageSetup...
+ // %%EndPageSetup" before this section, which means that
+ // the options in the "%%BeginSetup...%%EndSetup"
+ // section are after the "%%EndPageSetup", so we
+ // continue for searching options up to the buffer size
+ // limit $maxlinesforpageoptions.
+ passthru = 0;
+ inpageheader = 0;
+ optionsalsointoheader = 0;
+ }
+ else if (nestinglevel == 0 && !optionreplaced &&
+ (!passthru || !isdscjob) &&
+ ((linetype = line_type(line->data)) &&
+ (linetype == LT_BEGIN_FEATURE ||
+ linetype == LT_FOOMATIC_RIP_OPTION_SETTING)))
+ {
+ // parse
+ if (linetype == LT_BEGIN_FEATURE)
+ {
+ dstrcpy(tmp, line->data);
+ p = strtok(tmp->data, " \t"); // %%BeginFeature:
+ p = strtok(NULL, " \t="); // Option
+ if (*p == '*') p++;
+ strlcpy(optionname, p, 128);
+ p = strtok(NULL, " \t\r\n"); // value
+ fromcomposite = 0;
+ strlcpy(value, p, 128);
+ }
+ else
+ { // LT_FOOMATIC_RIP_OPTION_SETTING
+ dstrcpy(tmp, line->data);
+ p = strstr(tmp->data, "FoomaticRIPOptionSetting:");
+ p = strtok(p, " \t"); // FoomaticRIPOptionSetting
+ p = strtok(NULL, " \t="); // Option
+ strlcpy(optionname, p, 128);
+ p = strtok(NULL, " \t\r\n"); // value
+ if (*p == '@')
+ { // fromcomposite
+ p++;
+ fromcomposite = 1;
+ }
+ else
+ fromcomposite = 0;
+ strlcpy(value, p, 128);
+ }
+
+ // Mark that we are in a "Feature" section
+ if (linetype == LT_BEGIN_FEATURE)
+ {
+ infeature = 1;
+ dstrclear(linesafterlastbeginfeature);
+ }
+
+ // OK, we have an option. If it's not a
+ // Postscript-style option (ie, it's command-line or
+ // JCL) then we should note that fact, since the
+ // attribute-to-filter option passing in CUPS is kind of
+ // funky, especially wrt boolean options.
+ _log("Found: %s", line->data);
+ if ((o = find_option(optionname)) &&
+ (o->type != TYPE_NONE))
+ {
+ _log(" Option: %s=%s%s\n", optionname,
+ fromcomposite ? "From" : "", value);
+ if (spooler == SPOOLER_CUPS &&
+ linetype == LT_BEGIN_FEATURE &&
+ !option_get_value(o, optionset("notfirst")) &&
+ strcmp((val = option_get_value(o, optset)) ? val : "",
+ value) != 0 &&
+ (inheader || option_get_section(o) == SECTION_PAGESETUP))
+ {
+ // We have the first occurence of an option
+ // setting and the spooler is CUPS, so this
+ // setting is inserted by "pstops" or
+ // "imagetops". The value from the command
+ // line was not inserted by "pstops" or
+ // "imagetops" so it seems to be not under
+ // the choices in the PPD. Possible
+ // reasons:
+ //
+ // - "pstops" and "imagetops" ignore settings
+ // of numerical or string options which are
+ // not one of the choices in the PPD file,
+ // and inserts the default value instead.
+ //
+ // - On the command line an option was applied
+ // only to selected pages:
+ // "-o <page ranges>:<option>=<values>
+ // This is not supported by CUPS, so not
+ // taken care of by "pstops".
+ //
+ // We must fix this here by replacing the
+ // setting inserted by "pstops" or "imagetops"
+ // with the exact setting given on the command
+ // line.
+ //
+ // $arg->{$optionset} is already
+ // range-checked, so do not check again here
+
+ // Insert DSC comment
+ pdest = (inheader && isdscjob) ? psheader : psfifo;
+ if (option_is_ps_command(o))
+ {
+ // PostScript option, insert the code
+ option_get_command(tmp, o, optset, -1);
+ if (!(val = option_get_value(o, optset)))
+ val = "";
+
+ // Boolean and enumerated choice options can only be set in
+ // the PageSetup section
+ if ((inheader && option_is_custom_value(o, val)) || !inheader)
+ {
+ if (o->type == TYPE_BOOL)
+ dstrcatf(pdest, "%%%%BeginFeature: *%s %s\n", o->name,
+ val && !strcmp(val, "1") ? "True" : "False");
+ else
+ dstrcatf(pdest, "%%%%BeginFeature: *%s %s\n", o->name,
+ val);
+
+ dstrcatf(pdest, "%s\n", tmp->data);
+
+ // We have replaced this option on the FIFO
+ optionreplaced = 1;
+ }
+ }
+ else
+ {
+ // Command line or JCL option
+ val = option_get_value(o, optset);
+
+ if (!inheader || option_is_custom_value(o, val))
+ {
+ dstrcatf(pdest, "%%%% FoomaticRIPOptionSetting: %s=%s\n",
+ o->name, val ? val : "");
+ optionreplaced = 1;
+ }
+ }
+
+ if (optionreplaced)
+ {
+ val = option_get_value(o, optset);
+ _log(" --> Correcting numerical/string option to %s=%s (Command line argument)\n",
+ o->name, val ? val : "");
+ }
+ }
+
+ // Mark that we have already found this option
+ o->notfirst = 1;
+ if (!optionreplaced)
+ {
+ if (o->style != 'G')
+ {
+ // Controlled by '<Composite>' setting of
+ // a member option of a composite option
+ if (fromcomposite)
+ {
+ dstrcpyf(tmp, "From%s", value);
+ strlcpy(value, tmp->data, 128);
+ }
+
+ // Non PostScript option
+ //Check whether it is valid
+ if (option_set_value(o, optset, value))
+ {
+ _log("Setting option\n");
+ strlcpy(value, option_get_value(o, optset), 128);
+ if (optionsalsointoheader)
+ option_set_value(o, optionset("header"), value);
+ if (o->type == TYPE_ENUM &&
+ (!strcmp(o->name, "PageSize") ||
+ !strcmp(o->name, "PageRegion")) &&
+ startswith(value, "Custom") &&
+ linetype == LT_FOOMATIC_RIP_OPTION_SETTING)
+ {
+ // Custom Page size
+ width = height = 0.0;
+ p = linesafterlastbeginfeature->data;
+ while (*p && isspace(*p)) p++;
+ width = strtod(p, &p);
+ while (*p && isspace(*p)) p++;
+ height = strtod(p, &p);
+ if (width && height)
+ {
+ dstrcpyf(tmp, "%s.%fx%f", value, width, height);
+ strlcpy(value, tmp->data, 128);
+ option_set_value(o, optset, value);
+ if (optionsalsointoheader)
+ option_set_value(o, optionset("header"), value);
+ }
+ }
+ // For a composite option insert the
+ // code from the member options with
+ // current setting "From<composite>"
+ // The code from the member options
+ // is chosen according to the setting
+ // of the composite option.
+ if (option_is_composite(o) &&
+ linetype == LT_FOOMATIC_RIP_OPTION_SETTING)
+ {
+ build_commandline(optset, NULL, 0);
+ // TODO can this be removed?
+ // TODO merge section and ps_section
+ if (postscriptsection == PS_SECTION_JCLSETUP)
+ option_get_command(tmp, o, optset, SECTION_JCLSETUP);
+ else if (postscriptsection == PS_SECTION_PROLOG)
+ option_get_command(tmp, o, optset, SECTION_PROLOG);
+ else if (postscriptsection == PS_SECTION_SETUP)
+ option_get_command(tmp, o, optset,
+ SECTION_DOCUMENTSETUP);
+ else if (postscriptsection == PS_SECTION_PAGESETUP)
+ option_get_command(tmp, o, optset, SECTION_PAGESETUP);
+ dstrcat(line, tmp->data);
+ }
+ }
+ else
+ _log(" --> Invalid option setting found in job\n");
+ }
+ else if (fromcomposite)
+ {
+ // PostScript option, but we have to look up
+ // the PostScript code to be inserted from
+ // the setting of a composite option, as
+ // this option is set to "Controlled by
+ // '<Composite>'".
+ // Set the option
+ dstrcpyf(tmp, "From%s", value);
+ strlcpy(value, tmp->data, 128);
+ if (option_set_value(o, optset, value))
+ {
+ _log(" --> Looking up setting in composite option %s\n",
+ value);
+ if (optionsalsointoheader)
+ option_set_value(o, optionset("header"), value);
+ // update composite options
+ build_commandline(optset, NULL, 0);
+ // Substitute PostScript comment by the real code
+ // TODO what exactly is the next line doing?
+ // dstrcpy(line, o->compositesubst->data);
+ }
+ else
+ _log(" --> Invalid option setting found in job\n");
+ }
+ else
+ // it is a PostScript style option with
+ // the code readily inserted, no option
+ // for the renderer command line/JCL to set,
+ // no lookup of a composite option needed,
+ // so nothing to do here...
+ _log(" --> Option will be set by PostScript interpreter\n");
+ }
+ }
+ else
+ // This option is unknown to us, WTF?
+ _log("Unknown option %s=%s found in the job\n",
+ optionname, value);
+ }
+ else if (nestinglevel == 0 &&
+ startswith(line->data, "%%EndFeature"))
+ {
+ // End of feature
+ infeature = 0;
+ // If the option setting was replaced, it ends here,
+ // too, and the next option is not necessarily also replaced
+ optionreplaced = 0;
+ dstrclear(linesafterlastbeginfeature);
+ }
+ else if (nestinglevel == 0 && isdscjob && !prologfound &&
+ startswith(line->data, "%%Begin"))
+ {
+ // In some PostScript files (especially when generated
+ // by "dvips" of TeX/LaTeX) the "%%BeginProlog" is
+ // missing, so assume that it was before the current
+ // line (the first line starting with "%%Begin".
+ _log("Job claims to be DSC-conforming, but \"%%%%BeginProlog\" "
+ "was missing before first line with another"
+ "\"%%%%BeginProlog\" comment (is this a TeX/LaTeX/dvips-generated"
+ " PostScript file?). Assuming start of \"Prolog\" here.\n");
+ // Beginning of Prolog
+ inprolog = 1;
+ nondsclines = 0;
+ // Insert options for "Prolog" before the current line
+ dstrcpyf(tmp, "%%%%BeginProlog\n");
+ append_prolog_section(tmp, optset, 0);
+ dstrprepend(line, tmp->data);
+ prologfound = 1;
+ }
+ else if (nestinglevel == 0 &&
+ (startswith(line->data, "%RBINumCopies:") ||
+ startswith(line->data, "%%RBINumCopies:")))
+ {
+ p = strchr(line->data, ':') + 1;
+ get_current_job()->rbinumcopies = atoi(p);
+ _log("Found %RBINumCopies: %d\n", get_current_job()->rbinumcopies);
+ }
+ else if (startswith(skip_whitespace(line->data), "%") ||
+ startswith(skip_whitespace(line->data), "$"))
+ // This is an unknown PostScript comment or a blank
+ // line, no active code
+ ignoreline = 1;
+ }
+ else
+ {
+ // This line is active PostScript code
+ if (infeature)
+ // Collect coe in a "%%BeginFeature: ... %%EndFeature"
+ // section, to get the values for a custom option
+ // setting
+ dstrcat(linesafterlastbeginfeature, line->data);
+ if (inheader)
+ {
+ if (!inprolog && !insetup)
+ {
+ // Outside the "Prolog" and "Setup" section
+ // a correct DSC-conforming document has no
+ // active PostScript code, so consider the
+ // file as non-DSC-conforming when there are
+ // too many of such lines.
+ nondsclines++;
+ if (nondsclines > MAX_NON_DSC_LINES_IN_HEADER)
+ {
+ // Consider document as not DSC-conforming
+ _log("This job seems not to be DSC-conforming, "
+ "DSC-comment for next section not found, "
+ "stopping to parse the rest, passing it "
+ "directly to the renderer.\n");
+ // Stop scanning for further option settings
+ maxlines = 1;
+ isdscjob = 0;
+ // Insert defaults and command line settings in
+ // the beginning of the job or after the last valid
+ // section
+ dstrclear(tmp);
+ if (!prologfound)
+ append_prolog_section(tmp, optset, 1);
+ if (!setupfound)
+ append_setup_section(tmp, optset, 1);
+ if (!pagesetupfound)
+ append_page_setup_section(tmp, optset, 1);
+ dstrinsert(psheader, line_start(psheader->data,
+ insertoptions), tmp->data);
+ prologfound = 1;
+ setupfound = 1;
+ pagesetupfound = 1;
+ }
+ }
+ }
+ else if (!inpageheader)
+ {
+ // PostScript code inside a page, but not between
+ // "%%BeginPageSetup" and "%%EndPageSetup", so
+ // we are perhaps already drawing onto a page now
+ if (startswith(onelinebefore->data, "%%Page"))
+ _log("No page header or page header not DSC-conforming\n");
+ // Stop buffering lines to search for options
+ // placed not DSC-conforming
+ if (line_count(psfifo->data) >= MAX_LINES_FOR_PAGE_OPTIONS)
+ {
+ _log("Stopping search for page header options\n");
+ passthru = 1;
+ // If there comes a page header now, ignore it
+ ignorepageheader = 1;
+ optionsalsointoheader = 0;
+ }
+ // Insert PostScript option settings (options for the
+ // section "PageSetup"
+ if (isdscjob && !pagesetupfound)
+ {
+ append_page_setup_section(psfifo, optset, 1);
+ pagesetupfound = 1;
+ }
+ }
+ }
}
- /* Clean up and make Ghostscript stop by that */
- fclose(in);
- fclose(out);
- wait_for_process(pid);
+ // Debug Info
+ if (lastpassthru != passthru)
+ {
+ if (passthru)
+ _log("Found: %s --> Output goes directly to the renderer now.\n\n",
+ line->data);
+ else
+ _log("Found: %s --> Output goes to the FIFO buffer now.\n\n",
+ line->data);
+ }
- if (pagefound) {
- _log("File not empty, contains at least one page.\n");
+ // We are in an option which was replaced, do not output the current line
+ if (optionreplaced)
+ dstrclear(line);
+
+ // If we are in a "%%BeginSetup...%%EndSetup" section after
+ // the first "%%Page:..." and the current line belongs to
+ // an option setting, we have to copy the line also to the
+ // @psheader.
+ if (optionsalsointoheader &&
+ (infeature || startswith(line->data, "%%EndFeature")))
+ dstrcat(psheader, line->data);
+
+ // Store or send the current line
+ if (inheader && isdscjob)
+ {
+ // We are still in the PostScript header, collect all lines
+ // in @psheader
+ dstrcat(psheader, line->data);
+ }
+ else
+ {
+ if (passthru && isdscjob)
+ {
+ if (!lastpassthru)
+ {
+ //
+ // We enter passthru mode with this line, so the
+ // command line can have changed, check it and close
+ // the renderer if needed
+ //
+ if (rendererpid &&
+ !optionset_equal(optionset("currentpage"),
+ optionset("previouspage"), 0))
+ {
+ _log("Command line/JCL options changed, restarting renderer\n");
+ retval = close_renderer_handle(rendererhandle, rendererpid);
+ if (retval != EXIT_PRINTED)
+ rip_die(retval, "Error closing renderer\n");
+ rendererpid = 0;
+ }
+ }
+
+ // Flush psfifo and send line directly to the renderer
+ if (!rendererpid)
+ {
+ // No renderer running, start it
+ dstrcpy(tmp, psheader->data);
+ dstrcat(tmp, psfifo->data);
+ get_renderer_handle(tmp, &rendererhandle, &rendererpid);
+ // psfifo is sent out, flush it
+ dstrclear(psfifo);
+ }
+
+ if (!isempty(psfifo->data))
+ {
+ // Send psfifo to renderer
+ fwrite_or_die(psfifo->data, psfifo->len, 1, rendererhandle);
+ // flush psfifo
+ dstrclear(psfifo);
+ }
+
+ // Send line to renderer
+ if (!printprevpage)
+ {
+ fwrite_or_die(line->data, line->len, 1, rendererhandle);
+
+ while (stream_next_line(line, stream) > 0)
+ {
+ if (startswith(line->data, "%%"))
+ {
+ _log("Found: %s", line->data);
+ _log(" --> Continue DSC parsing now.\n\n");
+ saved = 1;
+ break;
+ }
+ else
+ {
+ fwrite_or_die(line->data, line->len, 1, rendererhandle);
+ linect++;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Push the line onto the stack to split up later
+ dstrcat(psfifo, line->data);
+ }
+ }
- /* Redefine stream for what we have read now */
- if (data_read->len < len)
- dstrncat(data_read, buf + data_read->len, len - data_read->len);
+ if (!printprevpage)
+ linect++;
+ }
+ else
+ {
+ // EOF!
+ more_stuff = 0;
+
+ // No PostScript header in the whole file? Then it's not
+ // PostScript, convert it.
+ // We open the file converter here when the file has less
+ // lines than the amount which we search for the PostScript
+ // header ($maxlinestopsstart).
+ if (linect <= nonpslines)
+ {
+ // This is not a PostScript job, abort it
+ _log("Job does not start with \"%%!\", is it Postscript?\n");
+ rip_die(EXIT_JOBERR, "Unknown data format.\n");
+ }
+ }
- stream.pos = 0;
- stream.file = file;
- stream.alreadyread = data_read->data;
- stream.len = data_read->len;
+ lastpassthru = passthru;
- /* Print the file */
- _print_ps(&stream);
- } else
- _log("No pages left, outputting empty file.\n");
+ if (!ignoreline && !printprevpage)
+ {
+ dstrcpy(twolinesbefore, onelinebefore->data);
+ dstrcpy(onelinebefore, line->data);
+ }
- free_dstr(data_read);
+ }
+ while ((maxlines == 0 || linect < maxlines) && more_stuff != 0);
+
+ // Some buffer still containing data? Send it out to the renderer
+ if (more_stuff || inheader || !isempty(psfifo->data))
+ {
+ // Flush psfifo and send the remaining data to the renderer, this
+ // only happens with non-DSC-conforming jobs or non-Foomatic PPDs
+ if (more_stuff)
+ _log("Stopped parsing the PostScript data, "
+ "sending rest directly to the renderer.\n");
+ else
+ _log("Flushing FIFO.\n");
+
+ if (inheader)
+ {
+ build_commandline(optset, NULL, 0);
+ // No page initialized yet? Copy the "header" option set into the
+ // "currentpage" option set, so that the renderer will find the
+ // options settings.
+ optionset_copy_values(optionset("header"), optionset("currentpage"));
+ optset = optionset("currentpage");
+
+ // If not done yet, insert defaults and command line settings
+ // in the beginning of the job or after the last valid section
+ dstrclear(tmp);
+ if (!prologfound)
+ append_prolog_section(tmp, optset, 1);
+ if (!setupfound)
+ append_setup_section(tmp, optset, 1);
+ if (!pagesetupfound)
+ append_page_setup_section(tmp, optset, 1);
+ dstrinsert(psheader, line_start(psheader->data, insertoptions),
+ tmp->data);
+
+ prologfound = 1;
+ setupfound = 1;
+ pagesetupfound = 1;
}
- return 1;
-}
+ if (rendererpid > 0 &&
+ !optionset_equal(optionset("currentpage"),
+ optionset("previouspage"), 0))
+ {
+ _log("Command line/JCL options changed, restarting renderer\n");
+ retval = close_renderer_handle(rendererhandle, rendererpid);
+ if (retval != EXIT_PRINTED)
+ rip_die(retval, "Error closing renderer\n");
+ rendererpid = 0;
+ }
-void _print_ps(stream_t *stream)
-{
- char *p;
-
- int maxlines = 1000; /* Maximum number of lines to be read when the
- documenent is not DSC-conforming.
- "$maxlines = 0" means that all will be read and
- examined. If it is discovered that the input
- file is DSC-conforming, this will be set to 0. */
-
- int maxlinestopsstart = 200; /* That many lines are allowed until the
- "%!" indicating PS comes. These
- additional lines in the
- beginning are usually JCL
- commands. The lines will be
- ignored by our parsing but
- passed through. */
-
- int printprevpage = 0; /* We set this when encountering "%%Page:" and the
- previous page is not printed yet. Then it will
- be printed and the new page will be prepared in
- the next run of the loop (we don't read a new
- line and don't increase the $linect then). */
-
- int linect = 0; /* how many lines have we examined */
- int nonpslines = 0; /* lines before "%!" found yet. */
- int more_stuff = 1; /* there is more stuff in stdin */
- int saved = 0; /* DSC line not precessed yet */
- int isdscjob = 0; /* is the job dsc conforming */
- int inheader = 1; /* Are we still in the header, before first
- "%%Page:" comment= */
-
- int optionsalsointoheader = 0; /* 1: We are in a "%%BeginSetup...
- %%EndSetup" section after the first
- "%%Page:..." line (OpenOffice.org
- does this and intends the options here
- apply to the whole document and not
- only to the current page). We have to
- add all lines also to the end of the
- @psheader now and we have to set
- non-PostScript options also in the
- "header" optionset. 0: otherwise. */
-
- int insertoptions = 1; /* If we find out that a file with a DSC magic
- string ("%!PS-Adobe-") is not really DSC-
- conforming, we insert the options directly
- after the line with the magic string. We use
- this variable to store the number of the line
- with the magic string */
-
- int prologfound = 0; /* Did we find the
- "%%BeginProlog...%%EndProlog" section? */
- int setupfound = 0; /* Did we find the
- %%BeginSetup...%%EndSetup" section? */
- int pagesetupfound = 0; /* special page setup handling needed */
-
- int inprolog = 0; /* We are between "%%BeginProlog" and "%%EndProlog" */
- int insetup = 0; /* We are between "%%BeginSetup" and "%%EndSetup" */
- int infeature = 0; /* We are between "%%BeginFeature" and "%%EndFeature" */
-
- int optionreplaced = 0; /* Will be set to 1 when we are in an
- option ("%%BeginFeature...
- %%EndFeature") which we have replaced. */
-
- int postscriptsection = PS_SECTION_JCLSETUP; /* In which section of the PostScript file
- are we currently ? */
-
- int nondsclines = 0; /* Number of subsequent lines found which are at a
- non-DSC-conforming place, between the sections
- of the header.*/
-
- int nestinglevel = 0; /* Are we in the main document (0) or in an
- embedded document bracketed by "%%BeginDocument"
- and "%%EndDocument" (>0) We do not parse the
- PostScript in an embedded document. */
-
- int inpageheader = 0; /* Are we in the header of a page,
- between "%%BeginPageSetup" and
- "%%EndPageSetup" (1) or not (0). */
-
- int passthru = 0; /* 0: write data into psfifo,
- 1: pass data directly to the renderer */
-
- int lastpassthru = 0; /* State of 'passthru' in previous line
- (to allow debug output when $passthru
- switches. */
-
- int ignorepageheader = 0; /* Will be set to 1 as soon as active
- code (not between "%%BeginPageSetup"
- and "%%EndPageSetup") appears after a
- "%%Page:" comment. In this case
- "%%BeginPageSetup" and
- "%%EndPageSetup" is not allowed any
- more on this page and will be ignored.
- Will be set to 0 when a new "%%Page:"
- comment appears. */
-
- int optset = optionset("header"); /* Where do the option settings which
- we have found go? */
-
- /* current line */
- dstr_t *line = create_dstr();
-
- dstr_t *onelinebefore = create_dstr();
- dstr_t *twolinesbefore = create_dstr();
-
- /* The header of the PostScript file, to be send after each start of the renderer */
- dstr_t *psheader = create_dstr();
-
- /* The input FIFO, data which we have pulled from stdin for examination,
- but not send to the renderer yet */
- dstr_t *psfifo = create_dstr();
-
- int ignoreline;
-
- int ooo110 = 0; /* Flag to work around an application bug */
-
- int currentpage = 0; /* The page which we are currently printing */
-
- option_t *o;
- const char *val;
-
- int linetype;
-
- dstr_t *linesafterlastbeginfeature = create_dstr(); /* All codelines after the last "%%BeginFeature" */
-
- char optionname [128];
- char value [128];
- int fromcomposite = 0;
-
- dstr_t *pdest;
-
- double width, height;
-
- pid_t rendererpid = 0;
- FILE *rendererhandle = NULL;
-
- int retval;
-
- dstr_t *tmp = create_dstr();
- jobhasjcl = 0;
-
- /* We do not parse the PostScript to find Foomatic options, we check
- only whether we have PostScript. */
- if (dontparse)
- maxlines = 1;
-
- _log("Reading PostScript input ...\n");
-
- do {
- ignoreline = 0;
-
- if (printprevpage || saved || stream_next_line(line, stream)) {
- saved = 0;
- if (linect == nonpslines) {
- /* In the beginning should be the postscript leader,
- sometimes after some JCL commands */
- if ( !(line->data[0] == '%' && line->data[1] == '!') &&
- !(line->data[1] == '%' && line->data[2] == '!')) /* There can be a Windows control character before "%!" */
- {
- nonpslines++;
- if (maxlines == nonpslines)
- maxlines ++;
- jobhasjcl = 1;
-
- if (nonpslines > maxlinestopsstart) {
- /* This is not a PostScript job, abort it */
- _log("Job does not start with \"%%!\", is it Postscript?\n");
- rip_die(EXIT_JOBERR, "Unknown data format.\n");
- }
- }
- else {
- /* Do we have a DSC-conforming document? */
- if ((line->data[0] == '%' && startswith(line->data, "%!PS-Adobe-")) ||
- (line->data[1] == '%' && startswith(line->data, "%!PS-Adobe-")))
- {
- /* Do not stop parsing the document */
- if (!dontparse) {
- maxlines = 0;
- isdscjob = 1;
- insertoptions = linect + 1;
- /* We have written into psfifo before, now we continue in
- psheader and move over the data which is already in psfifo */
- dstrcat(psheader, psfifo->data);
- dstrclear(psfifo);
- }
- _log("--> This document is DSC-conforming!\n");
- }
- else {
- /* Job is not DSC-conforming, stick in all PostScript
- option settings in the beginning */
- append_prolog_section(line, optset, 1);
- append_setup_section(line, optset, 1);
- append_page_setup_section(line, optset, 1);
- prologfound = 1;
- setupfound = 1;
- pagesetupfound = 1;
- }
- }
- }
- else {
- if (startswith(line->data, "%")) {
- if (startswith(line->data, "%%BeginDocument")) {
- /* Beginning of an embedded document
- Note that Adobe Acrobat has a bug and so uses
- "%%BeginDocument " instead of "%%BeginDocument:" */
- nestinglevel++;
- _log("Embedded document, nesting level now: %d\n", nestinglevel);
- }
- else if (nestinglevel > 0 && startswith(line->data, "%%EndDocument")) {
- /* End of an embedded document */
- nestinglevel--;
- _log("End of embedded document, nesting level now: %d\n", nestinglevel);
- }
- else if (nestinglevel == 0 && startswith(line->data, "%%Creator")) {
- /* Here we set flags to treat particular bugs of the
- PostScript produced by certain applications */
- p = strstr(line->data, "%%Creator") + 9;
- while (*p && (isspace(*p) || *p == ':')) p++;
- if (!strcmp(p, "OpenOffice.org")) {
- p += 14;
- while (*p && isspace(*p)) p++;
- if (sscanf(p, "1.1.%d", &ooo110) == 1) {
- _log("Document created with OpenOffice.org 1.1.x\n");
- ooo110 = 1;
- }
- } else if (!strcmp(p, "StarOffice 8")) {
- p += 12;
- _log("Document created with StarOffice 8\n");
- ooo110 = 1;
- }
- }
- else if (nestinglevel == 0 && startswith(line->data, "%%BeginProlog")) {
- /* Note: Below is another place where a "Prolog" section
- start will be considered. There we assume start of the
- "Prolog" if the job is DSC-Conformimg, but an arbitrary
- comment starting with "%%Begin", but not a comment
- explicitly treated here, is found. This is done because
- many "dvips" (TeX/LaTeX) files miss the "%%BeginProlog"
- comment.
- Beginning of Prolog */
- _log("\n-----------\nFound: %%%%BeginProlog\n");
- inprolog = 1;
- if (inheader)
- postscriptsection = PS_SECTION_PROLOG;
- nondsclines = 0;
- /* Insert options for "Prolog" */
- if (!prologfound) {
- append_prolog_section(line, optset, 0);
- prologfound = 1;
- }
- }
- else if (nestinglevel == 0 && startswith(line->data, "%%EndProlog")) {
- /* End of Prolog */
- _log("Found: %%%%EndProlog\n");
- inprolog = 0;
- insertoptions = linect +1;
- }
- else if (nestinglevel == 0 && startswith(line->data, "%%BeginSetup")) {
- /* Beginning of Setup */
- _log("\n-----------\nFound: %%%%BeginSetup\n");
- insetup = 1;
- nondsclines = 0;
- /* We need to distinguish with the $inheader variable
- here whether we are in the header or on a page, as
- OpenOffice.org inserts a "%%BeginSetup...%%EndSetup"
- section after the first "%%Page:..." line and assumes
- this section to be valid for all pages. */
- if (inheader) {
- postscriptsection = PS_SECTION_SETUP;
- /* If there was no "Prolog" but there are
- options for the "Prolog", push a "Prolog"
- with these options onto the psfifo here */
- if (!prologfound) {
- dstrclear(tmp);
- append_prolog_section(tmp, optset, 1);
- dstrprepend(line, tmp->data);
- prologfound = 1;
- }
- /* Insert options for "DocumentSetup" or "AnySetup" */
- if (spooler != SPOOLER_CUPS && !setupfound) {
- /* For non-CUPS spoolers or no spooler at all,
- we leave everythnig as it is */
- append_setup_section(line, optset, 0);
- setupfound = 1;
- }
- }
- else {
- /* Found option settings must be stuffed into both
- the header and the currrent page now. They will
- be written into both the "header" and the
- "currentpage" optionsets and the PostScript code
- lines of this section will not only go into the
- output stream, but also added to the end of the
- @psheader, so that they get repeated (to preserve
- the embedded PostScript option settings) on a
- restart of the renderer due to command line
- option changes */
- optionsalsointoheader = 1;
- _log("\"%%%%BeginSetup\" in page header\n");
- }
- }
- else if (nestinglevel == 0 && startswith(line->data, "%%EndSetup")) {
- /* End of Setup */
- _log("Found: %%%%EndSetup\n");
- insetup = 0;
- if (inheader)
- insertoptions = linect +1;
- else {
- /* The "%%BeginSetup...%%EndSetup" which
- OpenOffice.org has inserted after the first
- "%%Page:..." line ends here, so the following
- options go only onto the current page again */
- optionsalsointoheader = 0;
- }
- }
- else if (nestinglevel == 0 && startswith(line->data, "%%Page:")) {
- if (!lastpassthru && !inheader) {
- /* In the last line we were not in passthru mode,
- so the last page is not printed. Prepare to do
- it now. */
- printprevpage = 1;
- passthru = 1;
- _log("New page found but previous not printed, print it now.\n");
- }
- else {
- /* the previous page is printed, so we can prepare
- the current one */
- _log("\n-----------\nNew page: %s", line->data);
- printprevpage = 0;
- currentpage++;
- /* We consider the beginning of the page already as
- page setup section, as some apps do not use
- "%%PageSetup" tags. */
- postscriptsection = PS_SECTION_PAGESETUP;
-
- /* TODO can this be removed?
- Save PostScript state before beginning the page
- $line .= "/foomatic-saved-state save def\n"; */
-
- /* Here begins a new page */
- if (inheader) {
- build_commandline(optset, NULL, 0);
- /* Here we add some stuff which still
- belongs into the header */
- dstrclear(tmp);
-
- /* If there was no "Setup" but there are
- options for the "Setup", push a "Setup"
- with these options onto the @psfifo here */
- if (!setupfound) {
- append_setup_section(tmp, optset, 1);
- setupfound = 1;
- }
- /* If there was no "Prolog" but there are
- options for the "Prolog", push a "Prolog"
- with these options onto the @psfifo here */
- if (!prologfound) {
- append_prolog_section(tmp, optset, 1);
- prologfound = 1;
- }
- /* Now we push this into the header */
- dstrcat(psheader, tmp->data);
-
- /* The first page starts, so header ends */
- inheader = 0;
- nondsclines = 0;
- /* Option setting should go into the page
- specific option set now */
- optset = optionset("currentpage");
- }
- else {
- /* Restore PostScript state after completing the
- previous page:
-
- foomatic-saved-state restore
- %%Page: ...
- /foomatic-saved-state save def
-
- Print this directly, so that if we need to
- restart the renderer for this page due to
- a command line change this is done under the
- old instance of the renderer
- rint $rendererhandle
- "foomatic-saved-state restore\n"; */
-
- /* Save the option settings of the previous page */
- optionset_copy_values(optionset("currentpage"), optionset("previouspage"));
- optionset_delete_values(optionset("currentpage"));
- }
- /* Initialize the option set */
- optionset_copy_values(optionset("header"), optionset("currentpage"));
-
- /* Set the command line options which apply only
- to given pages */
- set_options_for_page(optionset("currentpage"), currentpage);
- pagesetupfound = 0;
- if (spooler == SPOOLER_CUPS) {
- /* Remove the "notfirst" flag from all options
- forseen for the "PageSetup" section, because
- when these are numerical options for CUPS.
- they have to be set to the correct value
- for every page */
- for (o = optionlist; o; o = o->next) {
- if (option_get_section(o ) == SECTION_PAGESETUP)
- o->notfirst = 0;
- }
- }
- /* Now the page header comes, so buffer the data,
- because we must perhaps shut down and restart
- the renderer */
- passthru = 0;
- ignorepageheader = 0;
- optionsalsointoheader = 0;
- }
- }
- else if (nestinglevel == 0 && !ignorepageheader &&
- startswith(line->data, "%%BeginPageSetup")) {
- /* Start of the page header, up to %%EndPageSetup
- nothing of the page will be drawn, page-specific
- option settngs (as letter-head paper for page 1)
- go here*/
- _log("\nFound: %%%%BeginPageSetup\n");
- passthru = 0;
- inpageheader = 1;
- postscriptsection = PS_SECTION_PAGESETUP;
- optionsalsointoheader = (ooo110 && currentpage == 1) ? 1 : 0;
- /* Insert PostScript option settings
- (options for section "PageSetup") */
- if (isdscjob) {
- append_page_setup_section(line, optset, 0);
- pagesetupfound = 1;
- }
- }
- else if (nestinglevel == 0 && !ignorepageheader &&
- startswith(line->data, "%%BeginPageSetup")) {
- /* End of the page header, the page is ready to be printed */
- _log("Found: %%%%EndPageSetup\n");
- _log("End of page header\n");
- /* We cannot for sure say that the page header ends here
- OpenOffice.org puts (due to a bug) a "%%BeginSetup...
- %%EndSetup" section after the first "%%Page:...". It
- is possible that CUPS inserts a "%%BeginPageSetup...
- %%EndPageSetup" before this section, which means that
- the options in the "%%BeginSetup...%%EndSetup"
- section are after the "%%EndPageSetup", so we
- continue for searching options up to the buffer size
- limit $maxlinesforpageoptions. */
- passthru = 0;
- inpageheader = 0;
- optionsalsointoheader = 0;
- }
- else if (nestinglevel == 0 && !optionreplaced && (!passthru || !isdscjob) &&
- ((linetype = line_type(line->data)) &&
- (linetype == LT_BEGIN_FEATURE || linetype == LT_FOOMATIC_RIP_OPTION_SETTING))) {
-
- /* parse */
- if (linetype == LT_BEGIN_FEATURE) {
- dstrcpy(tmp, line->data);
- p = strtok(tmp->data, " \t"); /* %%BeginFeature: */
- p = strtok(NULL, " \t="); /* Option */
- if (*p == '*') p++;
- strlcpy(optionname, p, 128);
- p = strtok(NULL, " \t\r\n"); /* value */
- fromcomposite = 0;
- strlcpy(value, p, 128);
- }
- else { /* LT_FOOMATIC_RIP_OPTION_SETTING */
- dstrcpy(tmp, line->data);
- p = strstr(tmp->data, "FoomaticRIPOptionSetting:");
- p = strtok(p, " \t"); /* FoomaticRIPOptionSetting */
- p = strtok(NULL, " \t="); /* Option */
- strlcpy(optionname, p, 128);
- p = strtok(NULL, " \t\r\n"); /* value */
- if (*p == '@') { /* fromcomposite */
- p++;
- fromcomposite = 1;
- }
- else
- fromcomposite = 0;
- strlcpy(value, p, 128);
- }
-
- /* Mark that we are in a "Feature" section */
- if (linetype == LT_BEGIN_FEATURE) {
- infeature = 1;
- dstrclear(linesafterlastbeginfeature);
- }
-
- /* OK, we have an option. If it's not a
- Postscript-style option (ie, it's command-line or
- JCL) then we should note that fact, since the
- attribute-to-filter option passing in CUPS is kind of
- funky, especially wrt boolean options. */
- _log("Found: %s", line->data);
- if ((o = find_option(optionname)) &&
- (o->type != TYPE_NONE)) {
- _log(" Option: %s=%s%s\n", optionname, fromcomposite ? "From" : "", value);
- if (spooler == SPOOLER_CUPS &&
- linetype == LT_BEGIN_FEATURE &&
- !option_get_value(o, optionset("notfirst")) &&
- strcmp((val = option_get_value(o, optset)) ? val : "", value) != 0 &&
- (inheader || option_get_section(o) == SECTION_PAGESETUP)) {
-
- /* We have the first occurence of an option
- setting and the spooler is CUPS, so this
- setting is inserted by "pstops" or
- "imagetops". The value from the command
- line was not inserted by "pstops" or
- "imagetops" so it seems to be not under
- the choices in the PPD. Possible
- reasons:
-
- - "pstops" and "imagetops" ignore settings
- of numerical or string options which are
- not one of the choices in the PPD file,
- and inserts the default value instead.
-
- - On the command line an option was applied
- only to selected pages:
- "-o <page ranges>:<option>=<values>
- This is not supported by CUPS, so not
- taken care of by "pstops".
-
- We must fix this here by replacing the
- setting inserted by "pstops" or "imagetops"
- with the exact setting given on the command
- line. */
-
- /* $arg->{$optionset} is already
- range-checked, so do not check again here
- Insert DSC comment */
- pdest = (inheader && isdscjob) ? psheader : psfifo;
- if (option_is_ps_command(o)) {
- /* PostScript option, insert the code */
-
- option_get_command(tmp, o, optset, -1);
- if (!(val = option_get_value(o, optset)))
- val = "";
-
- /* Boolean and enumerated choice options can only be set in the
- * PageSetup section */
- if ((inheader && option_is_custom_value(o, val)) || !inheader)
- {
- if (o->type == TYPE_BOOL)
- dstrcatf(pdest, "%%%%BeginFeature: *%s %s\n", o->name,
- val && !strcmp(val, "1") ? "True" : "False");
- else
- dstrcatf(pdest, "%%%%BeginFeature: *%s %s\n", o->name, val);
-
- dstrcatf(pdest, "%s\n", tmp->data);
-
- /* We have replaced this option on the FIFO */
- optionreplaced = 1;
- }
- }
- else { /* Command line or JCL option */
- val = option_get_value(o, optset);
-
- if (!inheader || option_is_custom_value(o, val)) {
- dstrcatf(pdest, "%%%% FoomaticRIPOptionSetting: %s=%s\n",
- o->name, val ? val : "");
- optionreplaced = 1;
- }
- }
-
- if (optionreplaced) {
- val = option_get_value(o, optset);
- _log(" --> Correcting numerical/string option to %s=%s (Command line argument)\n",
- o->name, val ? val : "");
- }
- }
-
- /* Mark that we have already found this option */
- o->notfirst = 1;
- if (!optionreplaced) {
- if (o->style != 'G') {
- /* Controlled by '<Composite>' setting of
- a member option of a composite option */
- if (fromcomposite) {
- dstrcpyf(tmp, "From%s", value);
- strlcpy(value, tmp->data, 128);
- }
-
- /* Non PostScript option
- Check whether it is valid */
- if (option_set_value(o, optset, value)) {
- _log("Setting option\n");
- strlcpy(value, option_get_value(o, optset), 128);
- if (optionsalsointoheader)
- option_set_value(o, optionset("header"), value);
- if (o->type == TYPE_ENUM &&
- (!strcmp(o->name, "PageSize") || !strcmp(o->name, "PageRegion")) &&
- startswith(value, "Custom") &&
- linetype == LT_FOOMATIC_RIP_OPTION_SETTING) {
- /* Custom Page size */
- width = height = 0.0;
- p = linesafterlastbeginfeature->data;
- while (*p && isspace(*p)) p++;
- width = strtod(p, &p);
- while (*p && isspace(*p)) p++;
- height = strtod(p, &p);
- if (width && height) {
- dstrcpyf(tmp, "%s.%fx%f", value, width, height);
- strlcpy(value, tmp->data, 128);
- option_set_value(o, optset, value);
- if (optionsalsointoheader)
- option_set_value(o, optionset("header"), value);
- }
- }
- /* For a composite option insert the
- code from the member options with
- current setting "From<composite>"
- The code from the member options
- is chosen according to the setting
- of the composite option. */
- if (option_is_composite(o) && linetype == LT_FOOMATIC_RIP_OPTION_SETTING) {
- build_commandline(optset, NULL, 0); /* TODO can this be removed? */
-
- /* TODO merge section and ps_section */
- if (postscriptsection == PS_SECTION_JCLSETUP)
- option_get_command(tmp, o, optset, SECTION_JCLSETUP);
- else if (postscriptsection == PS_SECTION_PROLOG)
- option_get_command(tmp, o, optset, SECTION_PROLOG);
- else if (postscriptsection == PS_SECTION_SETUP)
- option_get_command(tmp, o, optset, SECTION_DOCUMENTSETUP);
- else if (postscriptsection == PS_SECTION_PAGESETUP)
- option_get_command(tmp, o, optset, SECTION_PAGESETUP);
- dstrcat(line, tmp->data);
- }
- }
- else
- _log(" --> Invalid option setting found in job\n");
- }
- else if (fromcomposite) {
- /* PostScript option, but we have to look up
- the PostScript code to be inserted from
- the setting of a composite option, as
- this option is set to "Controlled by
- '<Composite>'". */
- /* Set the option */
- dstrcpyf(tmp, "From%s", value);
- strlcpy(value, tmp->data, 128);
- if (option_set_value(o, optset, value)) {
- _log(" --> Looking up setting in composite option %s\n", value);
- if (optionsalsointoheader)
- option_set_value(o, optionset("header"), value);
- /* update composite options */
- build_commandline(optset, NULL, 0);
- /* Substitute PostScript comment by the real code */
- /* TODO what exactly is the next line doing? */
- /* dstrcpy(line, o->compositesubst->data); */
- }
- else
- _log(" --> Invalid option setting found in job\n");
- }
- else
- /* it is a PostScript style option with
- the code readily inserted, no option
- for the renderer command line/JCL to set,
- no lookup of a composite option needed,
- so nothing to do here... */
- _log(" --> Option will be set by PostScript interpreter\n");
- }
- }
- else
- /* This option is unknown to us, WTF? */
- _log("Unknown option %s=%s found in the job\n", optionname, value);
- }
- else if (nestinglevel == 0 && startswith(line->data, "%%EndFeature")) {
- /* End of feature */
- infeature = 0;
- /* If the option setting was replaced, it ends here,
- too, and the next option is not necessarily also replaced */
- optionreplaced = 0;
- dstrclear(linesafterlastbeginfeature);
- }
- else if (nestinglevel == 0 && isdscjob && !prologfound &&
- startswith(line->data, "%%Begin")) {
- /* In some PostScript files (especially when generated
- by "dvips" of TeX/LaTeX) the "%%BeginProlog" is
- missing, so assume that it was before the current
- line (the first line starting with "%%Begin". */
- _log("Job claims to be DSC-conforming, but \"%%%%BeginProlog\" "
- "was missing before first line with another"
- "\"%%%%BeginProlog\" comment (is this a TeX/LaTeX/dvips-generated"
- " PostScript file?). Assuming start of \"Prolog\" here.\n");
- /* Beginning of Prolog */
- inprolog = 1;
- nondsclines = 0;
- /* Insert options for "Prolog" before the current line */
- dstrcpyf(tmp, "%%%%BeginProlog\n");
- append_prolog_section(tmp, optset, 0);
- dstrprepend(line, tmp->data);
- prologfound = 1;
- }
- else if (nestinglevel == 0 && (
- startswith(line->data, "%RBINumCopies:") ||
- startswith(line->data, "%%RBINumCopies:"))) {
- p = strchr(line->data, ':') +1;
- get_current_job()->rbinumcopies = atoi(p);
- _log("Found %RBINumCopies: %d\n", get_current_job()->rbinumcopies);
- }
- else if (startswith(skip_whitespace(line->data), "%") ||
- startswith(skip_whitespace(line->data), "$"))
- /* This is an unknown PostScript comment or a blank
- line, no active code */
- ignoreline = 1;
- }
- else {
- /* This line is active PostScript code */
- if (infeature)
- /* Collect coe in a "%%BeginFeature: ... %%EndFeature"
- section, to get the values for a custom option
- setting */
- dstrcat(linesafterlastbeginfeature, line->data);
-
- if (inheader) {
- if (!inprolog && !insetup) {
- /* Outside the "Prolog" and "Setup" section
- a correct DSC-conforming document has no
- active PostScript code, so consider the
- file as non-DSC-conforming when there are
- too many of such lines. */
- nondsclines++;
- if (nondsclines > MAX_NON_DSC_LINES_IN_HEADER) {
- /* Consider document as not DSC-conforming */
- _log("This job seems not to be DSC-conforming, "
- "DSC-comment for next section not found, "
- "stopping to parse the rest, passing it "
- "directly to the renderer.\n");
- /* Stop scanning for further option settings */
- maxlines = 1;
- isdscjob = 0;
- /* Insert defaults and command line settings in
- the beginning of the job or after the last valid
- section */
- dstrclear(tmp);
- if (!prologfound)
- append_prolog_section(tmp, optset, 1);
- if (!setupfound)
- append_setup_section(tmp, optset, 1);
- if (!pagesetupfound)
- append_page_setup_section(tmp, optset, 1);
- dstrinsert(psheader, line_start(psheader->data, insertoptions), tmp->data);
-
- prologfound = 1;
- setupfound = 1;
- pagesetupfound = 1;
- }
- }
- }
- else if (!inpageheader) {
- /* PostScript code inside a page, but not between
- "%%BeginPageSetup" and "%%EndPageSetup", so
- we are perhaps already drawing onto a page now */
- if (startswith(onelinebefore->data, "%%Page"))
- _log("No page header or page header not DSC-conforming\n");
- /* Stop buffering lines to search for options
- placed not DSC-conforming */
- if (line_count(psfifo->data) >= MAX_LINES_FOR_PAGE_OPTIONS) {
- _log("Stopping search for page header options\n");
- passthru = 1;
- /* If there comes a page header now, ignore it */
- ignorepageheader = 1;
- optionsalsointoheader = 0;
- }
- /* Insert PostScript option settings (options for the
- * section "PageSetup" */
- if (isdscjob && !pagesetupfound) {
- append_page_setup_section(psfifo, optset, 1);
- pagesetupfound = 1;
- }
- }
- }
- }
-
- /* Debug Info */
- if (lastpassthru != passthru) {
- if (passthru)
- _log("Found: %s --> Output goes directly to the renderer now.\n\n", line->data);
- else
- _log("Found: %s --> Output goes to the FIFO buffer now.\n\n", line->data);
- }
-
- /* We are in an option which was replaced, do not output the current line */
- if (optionreplaced)
- dstrclear(line);
-
- /* If we are in a "%%BeginSetup...%%EndSetup" section after
- the first "%%Page:..." and the current line belongs to
- an option setting, we have to copy the line also to the
- @psheader. */
- if (optionsalsointoheader && (infeature || startswith(line->data, "%%EndFeature")))
- dstrcat(psheader, line->data);
-
- /* Store or send the current line */
- if (inheader && isdscjob) {
- /* We are still in the PostScript header, collect all lines
- in @psheader */
- dstrcat(psheader, line->data);
- }
- else {
- if (passthru && isdscjob) {
- if (!lastpassthru) {
- /*
- * We enter passthru mode with this line, so the
- * command line can have changed, check it and close
- * the renderer if needed
- */
- if (rendererpid && !optionset_equal(optionset("currentpage"), optionset("previouspage"), 0)) {
- _log("Command line/JCL options changed, restarting renderer\n");
- retval = close_renderer_handle(rendererhandle, rendererpid);
- if (retval != EXIT_PRINTED)
- rip_die(retval, "Error closing renderer\n");
- rendererpid = 0;
- }
- }
-
- /* Flush psfifo and send line directly to the renderer */
- if (!rendererpid) {
- /* No renderer running, start it */
- dstrcpy(tmp, psheader->data);
- dstrcat(tmp, psfifo->data);
- get_renderer_handle(tmp, &rendererhandle, &rendererpid);
- /* psfifo is sent out, flush it */
- dstrclear(psfifo);
- }
-
- if (!isempty(psfifo->data)) {
- /* Send psfifo to renderer */
- fwrite_or_die(psfifo->data, psfifo->len, 1, rendererhandle);
- /* flush psfifo */
- dstrclear(psfifo);
- }
-
- /* Send line to renderer */
- if (!printprevpage) {
- fwrite_or_die(line->data, line->len, 1, rendererhandle);
-
- while (stream_next_line(line, stream) > 0) {
- if (startswith(line->data, "%%")) {
- _log("Found: %s", line->data);
- _log(" --> Continue DSC parsing now.\n\n");
- saved = 1;
- break;
- }
- else {
- fwrite_or_die(line->data, line->len, 1, rendererhandle);
- linect++;
- }
- }
- }
- }
- else {
- /* Push the line onto the stack to split up later */
- dstrcat(psfifo, line->data);
- }
- }
-
- if (!printprevpage)
- linect++;
- }
- else {
- /* EOF! */
- more_stuff = 0;
-
- /* No PostScript header in the whole file? Then it's not
- PostScript, convert it.
- We open the file converter here when the file has less
- lines than the amount which we search for the PostScript
- header ($maxlinestopsstart). */
- if (linect <= nonpslines) {
- /* This is not a PostScript job, abort it */
- _log("Job does not start with \"%%!\", is it Postscript?\n");
- rip_die(EXIT_JOBERR, "Unknown data format.\n");
- }
- }
-
- lastpassthru = passthru;
-
- if (!ignoreline && !printprevpage) {
- dstrcpy(twolinesbefore, onelinebefore->data);
- dstrcpy(onelinebefore, line->data);
- }
-
- } while ((maxlines == 0 || linect < maxlines) && more_stuff != 0);
-
- /* Some buffer still containing data? Send it out to the renderer */
- if (more_stuff || inheader || !isempty(psfifo->data)) {
- /* Flush psfifo and send the remaining data to the renderer, this
- only happens with non-DSC-conforming jobs or non-Foomatic PPDs */
- if (more_stuff)
- _log("Stopped parsing the PostScript data, "
- "sending rest directly to the renderer.\n");
- else
- _log("Flushing FIFO.\n");
-
- if (inheader) {
- build_commandline(optset, NULL, 0);
- /* No page initialized yet? Copy the "header" option set into the
- "currentpage" option set, so that the renderer will find the
- options settings. */
- optionset_copy_values(optionset("header"), optionset("currentpage"));
- optset = optionset("currentpage");
-
- /* If not done yet, insert defaults and command line settings
- in the beginning of the job or after the last valid section */
- dstrclear(tmp);
- if (!prologfound)
- append_prolog_section(tmp, optset, 1);
- if (!setupfound)
- append_setup_section(tmp, optset, 1);
- if (!pagesetupfound)
- append_page_setup_section(tmp, optset, 1);
- dstrinsert(psheader, line_start(psheader->data, insertoptions), tmp->data);
-
- prologfound = 1;
- setupfound = 1;
- pagesetupfound = 1;
- }
-
- if (rendererpid > 0 && !optionset_equal(optionset("currentpage"), optionset("previouspage"), 0)) {
- _log("Command line/JCL options changed, restarting renderer\n");
- retval = close_renderer_handle(rendererhandle, rendererpid);
- if (retval != EXIT_PRINTED)
- rip_die(retval, "Error closing renderer\n");
- rendererpid = 0;
- }
-
- if (!rendererpid) {
- dstrcpy(tmp, psheader->data);
- dstrcat(tmp, psfifo->data);
- get_renderer_handle(tmp, &rendererhandle, &rendererpid);
- /* We have sent psfifo now */
- dstrclear(psfifo);
- }
-
- if (psfifo->len) {
- /* Send psfifo to the renderer */
- fwrite_or_die(psfifo->data, psfifo->len, 1, rendererhandle);
- dstrclear(psfifo);
- }
-
- /* Print the rest of the input data */
- if (more_stuff) {
- while (stream_next_line(tmp, stream))
- fwrite_or_die(tmp->data, tmp->len, 1, rendererhandle);
- }
+ if (!rendererpid)
+ {
+ dstrcpy(tmp, psheader->data);
+ dstrcat(tmp, psfifo->data);
+ get_renderer_handle(tmp, &rendererhandle, &rendererpid);
+ // We have sent psfifo now
+ dstrclear(psfifo);
}
- /* At every "%%Page:..." comment we have saved the PostScript state
- and we have increased the page number. So if the page number is
- non-zero we had at least one "%%Page:..." comment and so we have
- to give a restore the PostScript state.
- if ($currentpage > 0) {
- print $rendererhandle "foomatic-saved-state restore\n";
- } */
-
- /* Close the renderer */
- if (rendererpid) {
- retval = close_renderer_handle(rendererhandle, rendererpid);
- if (retval != EXIT_PRINTED)
- rip_die(retval, "Error closing renderer\n");
- rendererpid = 0;
+ if (psfifo->len)
+ {
+ // Send psfifo to the renderer
+ fwrite_or_die(psfifo->data, psfifo->len, 1, rendererhandle);
+ dstrclear(psfifo);
}
- free_dstr(line);
- free_dstr(onelinebefore);
- free_dstr(twolinesbefore);
- free_dstr(psheader);
- free_dstr(psfifo);
- free_dstr(tmp);
+ // Print the rest of the input data
+ if (more_stuff)
+ {
+ while (stream_next_line(tmp, stream))
+ fwrite_or_die(tmp->data, tmp->len, 1, rendererhandle);
+ }
+ }
+
+ // At every "%%Page:..." comment we have saved the PostScript state
+ // and we have increased the page number. So if the page number is
+ // non-zero we had at least one "%%Page:..." comment and so we have
+ // to give a restore the PostScript state.
+ // if ($currentpage > 0) {
+ // print $rendererhandle "foomatic-saved-state restore\n";
+ // }
+
+ // Close the renderer
+ if (rendererpid)
+ {
+ retval = close_renderer_handle(rendererhandle, rendererpid);
+ if (retval != EXIT_PRINTED)
+ rip_die(retval, "Error closing renderer\n");
+ rendererpid = 0;
+ }
+
+ free_dstr(line);
+ free_dstr(onelinebefore);
+ free_dstr(twolinesbefore);
+ free_dstr(psheader);
+ free_dstr(psfifo);
+ free_dstr(tmp);
}
-/*
- * Run the renderer command line (and if defined also the postpipe) and returns
- * a file handle for stuffing in the PostScript data.
- */
-void get_renderer_handle(const dstr_t *prepend, FILE **fd, pid_t *pid)
+
+//
+// Run the renderer command line (and if defined also the postpipe) and returns
+// a file handle for stuffing in the PostScript data.
+//
+
+void
+get_renderer_handle(const dstr_t *prepend,
+ FILE **fd,
+ pid_t *pid)
{
- pid_t kid3;
- FILE *kid3in;
- dstr_t *cmdline = create_dstr();
+ pid_t kid3;
+ FILE *kid3in;
+ dstr_t *cmdline = create_dstr();
- /* Build the command line and get the JCL commands */
- build_commandline(optionset("currentpage"), cmdline, 0);
- massage_gs_commandline(cmdline);
+ // Build the command line and get the JCL commands
+ build_commandline(optionset("currentpage"), cmdline, 0);
+ massage_gs_commandline(cmdline);
- _log("\nStarting renderer with command: \"%s\"\n", cmdline->data);
- kid3 = start_process("kid3", exec_kid3, (void *)cmdline->data, &kid3in, NULL);
- if (kid3 < 0)
- rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Cannot fork for kid3\n");
+ _log("\nStarting renderer with command: \"%s\"\n", cmdline->data);
+ kid3 = start_process("kid3", exec_kid3, (void *)cmdline->data, &kid3in, NULL);
+ if (kid3 < 0)
+ rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Cannot fork for kid3\n");
- /* Feed the PostScript header and the FIFO contents */
- if (prepend)
- fwrite_or_die(prepend->data, prepend->len, 1, kid3in);
+ // Feed the PostScript header and the FIFO contents
+ if (prepend)
+ fwrite_or_die(prepend->data, prepend->len, 1, kid3in);
- /* We are the parent, return glob to the file handle */
- *fd = kid3in;
- *pid = kid3;
+ // We are the parent, return glob to the file handle
+ *fd = kid3in;
+ *pid = kid3;
- free_dstr(cmdline);
+ free_dstr(cmdline);
}
-/* Close the renderer process and wait until all kid processes finish */
-int close_renderer_handle(FILE *rendererhandle, pid_t rendererpid)
+
+// Close the renderer process and wait until all kid processes finish
+int
+close_renderer_handle(FILE *rendererhandle,
+ pid_t rendererpid)
{
- int status;
+ int status;
- _log("\nClosing renderer\n");
- fclose(rendererhandle);
+ _log("\nClosing renderer\n");
+ fclose(rendererhandle);
- status = wait_for_process(rendererpid);
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
- else
- return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
+ status = wait_for_process(rendererpid);
+ if (WIFEXITED(status))
+ return (WEXITSTATUS(status));
+ else
+ return (EXIT_PRNERR_NORETRY_BAD_SETTINGS);
}
-
-/* postscript.h
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// postscript.h
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#ifndef postscript_h
#define postscript_h
-int print_ps(FILE *s, const char *alreadyread, size_t len, const char *filename);
-
-#endif
+int print_ps(FILE *s, const char *alreadyread, size_t len,
+ const char *filename);
+#endif // !postscript_h
-/* process.c
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// process.c
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#include "foomaticrip.h"
#include "process.h"
#include <stdlib.h>
#include <signal.h>
+
int kidgeneration = 0;
-struct process {
- char name[64];
- pid_t pid;
- int isgroup;
+struct process
+{
+ char name[64];
+ pid_t pid;
+ int isgroup;
};
#define MAX_CHILDS 4
-struct process procs[MAX_CHILDS] = {
+struct process procs[MAX_CHILDS] =
+{
{ "", -1, 0 },
{ "", -1, 0 },
{ "", -1, 0 },
{ "", -1, 0 }
};
-void add_process(const char *name, int pid, int isgroup)
+
+void
+add_process(const char *name,
+ int pid,
+ int isgroup)
{
- int i;
- for (i = 0; i < MAX_CHILDS; i++) {
- if (procs[i].pid == -1) {
- strlcpy(procs[i].name, name, 64);
- procs[i].pid = pid;
- procs[i].isgroup = isgroup;
- return;
- }
+ int i;
+ for (i = 0; i < MAX_CHILDS; i++)
+ {
+ if (procs[i].pid == -1)
+ {
+ strlcpy(procs[i].name, name, 64);
+ procs[i].pid = pid;
+ procs[i].isgroup = isgroup;
+ return;
}
- rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Didn't think there would be that many child processes... Exiting.\n");
+ }
+ rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
+ "Didn't think there would be that many child processes... Exiting.\n");
}
-int find_process(int pid)
+
+int
+find_process(int pid)
{
- int i;
- for (i = 0; i < MAX_CHILDS; i++)
- if (procs[i].pid == pid)
- return i;
- return -1;
+ int i;
+ for (i = 0; i < MAX_CHILDS; i++)
+ if (procs[i].pid == pid)
+ return (i);
+ return (-1);
}
-void clear_proc_list()
+
+void
+clear_proc_list()
{
- int i;
- for (i = 0; i < MAX_CHILDS; i++)
- procs[i].pid = -1;
+ int i;
+ for (i = 0; i < MAX_CHILDS; i++)
+ procs[i].pid = -1;
}
-void kill_all_processes()
+
+void
+kill_all_processes()
{
- int i;
-
- for (i = 0; i < MAX_CHILDS; i++) {
- if (procs[i].pid == -1)
- continue;
- _log("Killing %s\n", procs[i].name);
- kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 15);
- sleep(1 << (3 - kidgeneration));
- kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 9);
- }
- clear_proc_list();
+ int i;
+
+ for (i = 0; i < MAX_CHILDS; i++)
+ {
+ if (procs[i].pid == -1)
+ continue;
+ _log("Killing %s\n", procs[i].name);
+ kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 15);
+ sleep(1 << (3 - kidgeneration));
+ kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 9);
+ }
+ clear_proc_list();
}
-static pid_t _start_process(const char *name,
- int (*proc_func)(FILE *, FILE *, void *),
- void *user_arg, FILE **pipe_in, FILE **pipe_out,
- int createprocessgroup)
-{
- pid_t pid;
- int pfdin[2], pfdout[2];
- int ret;
- FILE *in, *out;
+static pid_t
+_start_process(const char *name,
+ int (*proc_func)(FILE *, FILE *, void *),
+ void *user_arg,
+ FILE **pipe_in,
+ FILE **pipe_out,
+ int createprocessgroup)
+{
+ pid_t pid;
+ int pfdin[2], pfdout[2];
+ int ret;
+ FILE *in, *out;
+
+ if (pipe_in)
+ if (pipe(pfdin) < 0)
+ return (-1);
+ if (pipe_out)
+ if (pipe(pfdout) < 0)
+ return (-1);
+
+ _log("Starting process \"%s\" (generation %d)\n", name, kidgeneration +1);
+
+ pid = fork();
+ if (pid < 0)
+ {
+ _log("Could not fork for %s\n", name);
if (pipe_in)
- if (pipe(pfdin) < 0)
- return -1;
+ {
+ close(pfdin[0]);
+ close(pfdin[1]);
+ }
if (pipe_out)
- if (pipe(pfdout) < 0)
- return -1;
-
- _log("Starting process \"%s\" (generation %d)\n", name, kidgeneration +1);
-
- pid = fork();
- if (pid < 0) {
- _log("Could not fork for %s\n", name);
- if (pipe_in) {
- close(pfdin[0]);
- close(pfdin[1]);
- }
- if (pipe_out) {
- close(pfdout[0]);
- close(pfdout[1]);
- }
- return -1;
+ {
+ close(pfdout[0]);
+ close(pfdout[1]);
}
+ return (-1);
+ }
- if (pid == 0) { /* Child */
-
- // Reset sigpipe behavior to default for all children
- signal(SIGPIPE, SIG_DFL);
-
- if (pipe_in) {
- close(pfdin[1]);
- in = fdopen(pfdin[0], "r");
- }
- else
- in = NULL;
-
- if (pipe_out) {
- close(pfdout[0]);
- out = fdopen(pfdout[1], "w");
- }
- else
- out = NULL;
-
- if (createprocessgroup)
- setpgid(0, 0);
-
- kidgeneration++;
+ if (pid == 0)
+ {
+ // Child
- /* The subprocess list is only valid for the parent. Clear it. */
- clear_proc_list();
+ // Reset sigpipe behavior to default for all children
+ signal(SIGPIPE, SIG_DFL);
- ret = proc_func(in, out, user_arg);
- exit(ret);
+ if (pipe_in)
+ {
+ close(pfdin[1]);
+ in = fdopen(pfdin[0], "r");
}
+ else
+ in = NULL;
- /* Parent */
- if (pipe_in) {
- close(pfdin[0]);
- *pipe_in = fdopen(pfdin[1], "w");
- if (!*pipe_in)
- _log("fdopen: %s\n", strerror(errno));
- }
- if (pipe_out) {
- close(pfdout[1]);
- *pipe_out = fdopen(pfdout[0], "r");
- if (!*pipe_out)
- _log("fdopen: %s\n", strerror(errno));
+ if (pipe_out)
+ {
+ close(pfdout[0]);
+ out = fdopen(pfdout[1], "w");
}
+ else
+ out = NULL;
- /* Add the child process to the list of open processes (to be able to kill
- * them in case of a signal. */
- add_process(name, pid, createprocessgroup);
+ if (createprocessgroup)
+ setpgid(0, 0);
- return pid;
-}
+ kidgeneration ++;
-int exec_command(FILE *in, FILE *out, void *cmd)
-{
- if (in && dup2(fileno(in), fileno(stdin)) < 0)
- rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "%s: Could not dup stdin\n", (const char *)cmd);
- if (out && dup2(fileno(out), fileno(stdout)) < 0)
- rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "%s: Could not dup stdout\n", (const char *)cmd);
-
- execl(get_modern_shell(), get_modern_shell(), "-e", "-c", (const char *)cmd, (char *)NULL);
+ // The subprocess list is only valid for the parent. Clear it.
+ clear_proc_list();
- _log("Error: Executing \"%s -c %s\" failed (%s).\n", get_modern_shell(), (const char *)cmd, strerror(errno));
- return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
+ ret = proc_func(in, out, user_arg);
+ exit(ret);
+ }
+
+ // Parent
+ if (pipe_in)
+ {
+ close(pfdin[0]);
+ *pipe_in = fdopen(pfdin[1], "w");
+ if (!*pipe_in)
+ _log("fdopen: %s\n", strerror(errno));
+ }
+ if (pipe_out)
+ {
+ close(pfdout[1]);
+ *pipe_out = fdopen(pfdout[0], "r");
+ if (!*pipe_out)
+ _log("fdopen: %s\n", strerror(errno));
+ }
+
+ // Add the child process to the list of open processes (to be able to kill
+ // them in case of a signal.
+ add_process(name, pid, createprocessgroup);
+
+ return (pid);
}
-pid_t start_system_process(const char *name, const char *command, FILE **fdin, FILE **fdout)
+
+int
+exec_command(FILE *in,
+ FILE *out,
+ void *cmd)
{
- return _start_process(name, exec_command, (void*)command, fdin, fdout, 1);
+ if (in && dup2(fileno(in), fileno(stdin)) < 0)
+ rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
+ "%s: Could not dup stdin\n", (const char *)cmd);
+ if (out && dup2(fileno(out), fileno(stdout)) < 0)
+ rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
+ "%s: Could not dup stdout\n", (const char *)cmd);
+
+ execl(get_modern_shell(), get_modern_shell(), "-e", "-c",
+ (const char *)cmd, (char *)NULL);
+
+ _log("Error: Executing \"%s -c %s\" failed (%s).\n", get_modern_shell(),
+ (const char *)cmd, strerror(errno));
+ return (EXIT_PRNERR_NORETRY_BAD_SETTINGS);
}
-pid_t start_process(const char *name, int (*proc_func)(FILE *, FILE *, void *), void *user_arg, FILE **fdin, FILE **fdout)
+
+pid_t
+start_system_process(const char *name,
+ const char *command,
+ FILE **fdin,
+ FILE **fdout)
{
- return _start_process(name, proc_func, user_arg, fdin, fdout, 0);
+ return (_start_process(name, exec_command, (void*)command, fdin, fdout, 1));
}
-int wait_for_process(int pid)
-{
- int i;
- int status;
- i = find_process(pid);
- if (i < 0) {
- _log("No such process \"%d\"", pid);
- return -1;
- }
+pid_t
+start_process(const char *name,
+ int (*proc_func)(FILE *, FILE *, void *),
+ void *user_arg,
+ FILE **fdin,
+ FILE **fdout)
+{
+ return (_start_process(name, proc_func, user_arg, fdin, fdout, 0));
+}
- waitpid(procs[i].pid, &status, 0);
- if (WIFEXITED(status))
- _log("%s exited with status %d\n", procs[i].name, WEXITSTATUS(status));
- else if (WIFSIGNALED(status))
- _log("%s received signal %d\n", procs[i].name, WTERMSIG(status));
- /* remove from process list */
- procs[i].pid = -1;
- return status;
+int
+wait_for_process(int pid)
+{
+ int i;
+ int status;
+
+ i = find_process(pid);
+ if (i < 0)
+ {
+ _log("No such process \"%d\"", pid);
+ return (-1);
+ }
+
+ waitpid(procs[i].pid, &status, 0);
+ if (WIFEXITED(status))
+ _log("%s exited with status %d\n", procs[i].name, WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ _log("%s received signal %d\n", procs[i].name, WTERMSIG(status));
+
+ // remove from process list
+ procs[i].pid = -1;
+ return (status);
}
-int run_system_process(const char *name, const char *command)
+
+int
+run_system_process(const char *name,
+ const char *command)
{
- int pid = start_system_process(name, command, NULL, NULL);
- return wait_for_process(pid);
+ int pid = start_system_process(name, command, NULL, NULL);
+ return (wait_for_process(pid));
}
-
-/* process.h
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// process.h
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#ifndef process_h
#define process_h
#include <sys/types.h>
#include <sys/wait.h>
-pid_t start_process(const char *name, int (*proc_func)(), void *user_arg, FILE **fdin, FILE **fdout);
-pid_t start_system_process(const char *name, const char *command, FILE **fdin, FILE **fdout);
-/* returns command's return status (see waitpid(2)) */
+pid_t start_process(const char *name, int (*proc_func)(), void *user_arg,
+ FILE **fdin, FILE **fdout);
+pid_t start_system_process(const char *name, const char *command, FILE **fdin,
+ FILE **fdout);
+
+// returns command's return status (see waitpid(2))
int run_system_process(const char *name, const char *command);
-pid_t create_pipe_process(const char *name,
- FILE *src,
- FILE *dest,
- const char *alreadyread,
- size_t alreadyread_len);
+pid_t create_pipe_process(const char *name, FILE *src, FILE *dest,
+ const char *alreadyread, size_t alreadyread_len);
int wait_for_process(int pid);
void kill_all_processes();
-#endif
-
+#endif // !process_h
-/* renderer.c
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// renderer.c
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
+
#include <config.h>
#include <signal.h>
#include <ctype.h>
#include "process.h"
#include "options.h"
-/*
- * Check whether we have a Ghostscript version with redirection of the standard
- * output of the PostScript programs via '-sstdout=%stderr'
- */
-int test_gs_output_redirection()
-{
- char gstestcommand[CMDLINE_MAX];
- char output[10] = "";
- int bytes;
-
- snprintf(gstestcommand, CMDLINE_MAX,
- "%s -dQUIET -dSAFER -dNOPAUSE "
- "-dBATCH -dNOMEDIAATTRS -sDEVICE=ps2write -sstdout=%%stderr "
- "-sOutputFile=/dev/null -c '(hello\n) print flush' 2>&1", gspath);
-
- FILE *pd = popen(gstestcommand, "r");
- if (!pd) {
- _log("Failed to execute ghostscript!\n");
- return 0;
- }
- bytes = fread_or_die(output, 1, 10, pd);
- pclose(pd);
+//
+// Check whether we have a Ghostscript version with redirection of the standard
+// output of the PostScript programs via '-sstdout=%stderr'
+//
- if (bytes > 0 && startswith(output, "hello"))
- return 1;
-
- return 0;
-}
-
-/*
- * Massage arguments to make ghostscript execute properly as a filter, with
- * output on stdout and errors on stderr etc. (This function does what
- * foomatic-gswrapper used to do)
- */
-void massage_gs_commandline(dstr_t *cmd)
+int
+test_gs_output_redirection()
{
- int gswithoutputredirection = test_gs_output_redirection();
- size_t start, end;
- dstr_t *gscmd, *cmdcopy;
-
- extract_command(&start, &end, cmd->data, "gs");
- if (start == end) /* cmd doesn't call ghostscript */
- return;
-
- gscmd = create_dstr();
- dstrncpy(gscmd, &cmd->data[start], end - start);
-
- /* If Ghostscript does not support redirecting the standard output
- of the PostScript program to standard error with '-sstdout=%stderr', sen
- the job output data to fd 3; errors will be on 2(stderr) and job ps
- program interpreter output on 1(stdout). */
- if (gswithoutputredirection)
- dstrreplace(gscmd, "-sOutputFile=- ", "-sOutputFile=%stdout ", 0);
- else
- dstrreplace(gscmd, "-sOutputFile=- ", "-sOutputFile=/dev/fd/3 ", 0);
-
- /* Use always buffered input. This works around a Ghostscript
- bug which prevents printing encrypted PDF files with Adobe Reader 8.1.1
- and Ghostscript built as shared library (Ghostscript bug #689577, Ubuntu
- bug #172264) */
- if (dstrendswith(gscmd, " -"))
- dstrcat(gscmd, "_");
- else
- dstrreplace(gscmd, " - ", " -_ ", 0);
- dstrreplace(gscmd, " /dev/fd/0", " -_ ", 0);
+ char gstestcommand[CMDLINE_MAX];
+ char output[10] = "";
+ int bytes;
- /* Turn *off* -q (quiet!); now that stderr is useful! :) */
- dstrreplace(gscmd, " -q ", " ", 0);
+ snprintf(gstestcommand, CMDLINE_MAX,
+ "%s -dQUIET -dSAFER -dNOPAUSE "
+ "-dBATCH -dNOMEDIAATTRS -sDEVICE=ps2write -sstdout=%%stderr "
+ "-sOutputFile=/dev/null -c '(hello\n) print flush' 2>&1", gspath);
- /* Escape any quotes, and then quote everything just to be sure...
- Escaping a single quote inside single quotes is a bit complex as the
- shell takes everything literal there. So we have to assemble it by
- concatinating different quoted strings. Finally we get e.g.: 'x'"'"'y'
- or ''"'"'xy' or 'xy'"'"'' or ... */
- /* dstrreplace(cmd, "'", "'\"'\"'"); TODO tbd */
+ FILE *pd = popen(gstestcommand, "r");
+ if (!pd)
+ {
+ _log("Failed to execute ghostscript!\n");
+ return (0);
+ }
- dstrremove(gscmd, 0, 2); /* Remove 'gs' */
- if (gswithoutputredirection)
- {
- dstrprepend(gscmd, " -sstdout=%stderr ");
- dstrprepend(gscmd, gspath);
- }
- else
- {
- dstrprepend(gscmd, gspath);
- dstrcat(gscmd, " 3>&1 1>&2");
- }
+ bytes = fread_or_die(output, 1, 10, pd);
+ pclose(pd);
- /* put gscmd back into cmd, between 'start' and 'end' */
- cmdcopy = create_dstr();
- dstrcpy(cmdcopy, cmd->data);
+ if (bytes > 0 && startswith(output, "hello"))
+ return (1);
- dstrncpy(cmd, cmdcopy->data, start);
- dstrcat(cmd, gscmd->data);
- dstrcat(cmd, &cmdcopy->data[end]);
+ return (0);
+}
- free_dstr(gscmd);
- free_dstr(cmdcopy);
- /* If the renderer command line contains the "echo" command, replace the
- * "echo" by the user-chosen $myecho (important for non-GNU systems where
- * GNU echo is in a special path */
- dstrreplace(cmd, "echo", echopath, 0); /* TODO search for \wecho\w */
-}
+//
+// Massage arguments to make ghostscript execute properly as a filter, with
+// output on stdout and errors on stderr etc. (This function does what
+// foomatic-gswrapper used to do)
+//
-char * read_line(FILE *stream, size_t *readbytes)
+void
+massage_gs_commandline(dstr_t *cmd)
{
- char *line;
- size_t alloc = 64, len = 0;
- int c;
-
- line = malloc(alloc);
-
- while ((c = fgetc(stream)) != EOF) {
- if (len >= alloc -1) {
- alloc *= 2;
- line = realloc(line, alloc);
- }
- line[len] = (char)c;
- len++;
- if (c == '\n')
- break;
- }
-
- line[len] = '\0';
- *readbytes = len;
- return line;
+ int gswithoutputredirection = test_gs_output_redirection();
+ size_t start, end;
+ dstr_t *gscmd, *cmdcopy;
+
+ extract_command(&start, &end, cmd->data, "gs");
+ if (start == end) // cmd doesn't call ghostscript
+ return;
+
+ gscmd = create_dstr();
+ dstrncpy(gscmd, &cmd->data[start], end - start);
+
+ // If Ghostscript does not support redirecting the standard output
+ // of the PostScript program to standard error with '-sstdout=%stderr', sen
+ // the job output data to fd 3; errors will be on 2(stderr) and job ps
+ // program interpreter output on 1(stdout).
+ if (gswithoutputredirection)
+ dstrreplace(gscmd, "-sOutputFile=- ", "-sOutputFile=%stdout ", 0);
+ else
+ dstrreplace(gscmd, "-sOutputFile=- ", "-sOutputFile=/dev/fd/3 ", 0);
+
+ // Use always buffered input. This works around a Ghostscript
+ // bug which prevents printing encrypted PDF files with Adobe Reader 8.1.1
+ // and Ghostscript built as shared library (Ghostscript bug #689577, Ubuntu
+ // bug #172264)
+ if (dstrendswith(gscmd, " -"))
+ dstrcat(gscmd, "_");
+ else
+ dstrreplace(gscmd, " - ", " -_ ", 0);
+ dstrreplace(gscmd, " /dev/fd/0", " -_ ", 0);
+
+ // Turn *off* -q (quiet!); now that stderr is useful! :)
+ dstrreplace(gscmd, " -q ", " ", 0);
+
+ // Escape any quotes, and then quote everything just to be sure...
+ // Escaping a single quote inside single quotes is a bit complex as the
+ // shell takes everything literal there. So we have to assemble it by
+ // concatinating different quoted strings. Finally we get e.g.: 'x'"'"'y'
+ // or ''"'"'xy' or 'xy'"'"'' or ...
+ // dstrreplace(cmd, "'", "'\"'\"'"); TODO tbd
+
+ dstrremove(gscmd, 0, 2); // Remove 'gs'
+ if (gswithoutputredirection)
+ {
+ dstrprepend(gscmd, " -sstdout=%stderr ");
+ dstrprepend(gscmd, gspath);
+ }
+ else
+ {
+ dstrprepend(gscmd, gspath);
+ dstrcat(gscmd, " 3>&1 1>&2");
+ }
+
+ // put gscmd back into cmd, between 'start' and 'end'
+ cmdcopy = create_dstr();
+ dstrcpy(cmdcopy, cmd->data);
+
+ dstrncpy(cmd, cmdcopy->data, start);
+ dstrcat(cmd, gscmd->data);
+ dstrcat(cmd, &cmdcopy->data[end]);
+
+ free_dstr(gscmd);
+ free_dstr(cmdcopy);
+
+ // If the renderer command line contains the "echo" command, replace the
+ // "echo" by the user-chosen $myecho (important for non-GNU systems where
+ // GNU echo is in a special path
+ dstrreplace(cmd, "echo", echopath, 0); // TODO search for \wecho\w
}
-void write_binary_data(FILE *stream, const char *data, size_t bytes)
+
+char *
+read_line(FILE *stream,
+ size_t *readbytes)
{
- int i;
- for (i=0; i < bytes; i++)
+ char *line;
+ size_t alloc = 64, len = 0;
+ int c;
+
+ line = malloc(alloc);
+
+ while ((c = fgetc(stream)) != EOF)
+ {
+ if (len >= alloc -1)
{
- fputc(data[i], stream);
+ alloc *= 2;
+ line = realloc(line, alloc);
}
+ line[len] = (char)c;
+ len++;
+ if (c == '\n')
+ break;
+ }
+
+ line[len] = '\0';
+ *readbytes = len;
+ return (line);
}
-/*
- * Read all lines containing 'jclstr' from 'stream' (actually, one more) and
- * return them in a zero terminated array.
- */
-static char ** read_jcl_lines(FILE *stream, const char *jclstr,
- size_t *readbinarybytes)
+
+void
+write_binary_data(FILE *stream,
+ const char *data,
+ size_t bytes)
{
- char *line;
- char **result;
- size_t alloc = 8, cnt = 0;
+ int i;
+ for (i=0; i < bytes; i++)
+ {
+ fputc(data[i], stream);
+ }
+}
+
- result = malloc(alloc * sizeof(char *));
+//
+// Read all lines containing 'jclstr' from 'stream' (actually, one more) and
+// return them in a zero terminated array.
+//
- /* read from the renderer output until the first non-JCL line appears */
- while ((line = read_line(stream, readbinarybytes)))
+static char **
+read_jcl_lines(FILE *stream,
+ const char *jclstr,
+ size_t *readbinarybytes)
+{
+ char *line;
+ char **result;
+ size_t alloc = 8, cnt = 0;
+
+ result = malloc(alloc * sizeof(char *));
+
+ // read from the renderer output until the first non-JCL line appears
+ while ((line = read_line(stream, readbinarybytes)))
+ {
+ if (cnt >= alloc -1)
{
- if (cnt >= alloc -1)
- {
- alloc *= 2;
- result = realloc(result, alloc * sizeof(char *));
- }
- result[cnt] = line;
- if (!strstr(line, jclstr))
- break;
- /* Remove newline from the end of a line containing JCL */
- result[cnt][*readbinarybytes - 1] = '\0';
- cnt++;
+ alloc *= 2;
+ result = realloc(result, alloc * sizeof(char *));
}
-
+ result[cnt] = line;
+ if (!strstr(line, jclstr))
+ break;
+ // Remove newline from the end of a line containing JCL
+ result[cnt][*readbinarybytes - 1] = '\0';
cnt++;
- result[cnt] = NULL;
- return result;
+ }
+
+ cnt++;
+ result[cnt] = NULL;
+ return (result);
}
-static int jcl_keywords_equal(const char *jclline1, const char *jclline2,
- const char *jclstr)
-{
- char *j1, *j2, *p1, *p2;
- j1 = strstr(jclline1, jclstr);
- if (!j1) return 0;
- if (!(p1 = strchr(skip_whitespace(j1), '=')))
- p1 = j1 + strlen(j1);
+static int
+jcl_keywords_equal(const char *jclline1,
+ const char *jclline2,
+ const char *jclstr)
+{
+ char *j1, *j2, *p1, *p2;
+
+ j1 = strstr(jclline1, jclstr);
+ if (!j1)
+ return (0);
+ if (!(p1 = strchr(skip_whitespace(j1), '=')))
+ p1 = j1 + strlen(j1);
+ p1--;
+ while (p1 > j1 && isspace(*p1))
p1--;
- while (p1 > j1 && isspace(*p1))
- p1--;
- j2 = strstr(jclline2, jclstr);
- if (!j2) return 0;
- if (!(p2 = strchr(skip_whitespace(j2), '=')))
- p2 = j2 + strlen(j2);
+ j2 = strstr(jclline2, jclstr);
+ if (!j2)
+ return (0);
+ if (!(p2 = strchr(skip_whitespace(j2), '=')))
+ p2 = j2 + strlen(j2);
+ p2--;
+ while (p2 > j2 && isspace(*p2))
p2--;
- while (p2 > j2 && isspace(*p2))
- p2--;
- if (p1 - j1 != p2 - j2) return 0;
- return strncmp(j1, j2, p1 - j1 + 1) == 0;
+ if (p1 - j1 != p2 - j2)
+ return (0);
+
+ return (strncmp(j1, j2, p1 - j1 + 1) == 0);
}
-/*
- * Finds the keyword of line in opts
- */
-static const char * jcl_options_find_keyword(char **opts, const char *line,
- const char *jclstr)
-{
- if (!opts)
- return NULL;
+//
+// Finds the keyword of line in opts
+//
- while (*opts)
- {
- if (jcl_keywords_equal(*opts, line, jclstr))
- return *opts;
- opts++;
- }
- return NULL;
+static const char *
+jcl_options_find_keyword(char **opts,
+ const char *line,
+ const char *jclstr)
+{
+ if (!opts)
+ return (NULL);
+
+ while (*opts)
+ {
+ if (jcl_keywords_equal(*opts, line, jclstr))
+ return (*opts);
+ opts ++;
+ }
+ return (NULL);
}
-static void argv_write(FILE *stream, char **argv, const char *sep)
+
+static void
+argv_write(FILE *stream,
+ char **argv,
+ const char *sep)
{
- if (!argv)
- return;
+ if (!argv)
+ return;
- while (*argv)
- fprintf(stream, "%s%s", *argv++, sep);
+ while (*argv)
+ fprintf(stream, "%s%s", *argv++, sep);
}
-/*
- * Merges 'original_opts' and 'pref_opts' and writes them to 'stream'. Header /
- * footer is taken from 'original_opts'. If both have the same options, the one
- * from 'pref_opts' is preferred
- * Returns true, if original_opts was not empty
- */
-static int write_merged_jcl_options(FILE *stream,
- char **original_opts,
- char **opts,
- size_t readbinarybytes,
- const char *jclstr)
-{
- char *p = strstr(original_opts[0], jclstr);
- char header[128];
- char **optsp1 = NULL, **optsp2 = NULL;
- /* No JCL options in original_opts, just prepend opts */
- if (argv_count(original_opts) == 1)
- {
- fprintf(stream, "%s", jclbegin);
- argv_write(stream, opts, "\n");
- write_binary_data(stream, original_opts[0], readbinarybytes);
- return 0;
- }
+//
+// Merges 'original_opts' and 'pref_opts' and writes them to 'stream'. Header /
+// footer is taken from 'original_opts'. If both have the same options, the one
+// from 'pref_opts' is preferred
+// Returns true, if original_opts was not empty
+//
- if (argv_count(original_opts) == 2)
+static int
+write_merged_jcl_options(FILE *stream,
+ char **original_opts,
+ char **opts,
+ size_t readbinarybytes,
+ const char *jclstr)
+{
+ char *p = strstr(original_opts[0], jclstr);
+ char header[128];
+ char **optsp1 = NULL, **optsp2 = NULL;
+
+ // No JCL options in original_opts, just prepend opts
+ if (argv_count(original_opts) == 1)
+ {
+ fprintf(stream, "%s", jclbegin);
+ argv_write(stream, opts, "\n");
+ write_binary_data(stream, original_opts[0], readbinarybytes);
+ return (0);
+ }
+
+ if (argv_count(original_opts) == 2)
+ {
+ // If we have only one line of JCL it is probably something like the
+ // "@PJL ENTER LANGUAGE=..." line which has to be in the end, but it
+ // also contains the "<esc>%-12345X" which has to be in the beginning
+ // of the job
+ if (p)
+ fwrite_or_die(original_opts[0], 1, p - original_opts[0], stream);
+ else
+ fprintf(stream, "%s\n", original_opts[0]);
+
+ argv_write(stream, opts, "\n");
+
+ if (p)
+ fprintf(stream, "%s\n", p);
+
+ write_binary_data(stream, original_opts[1], readbinarybytes);
+ return (1);
+ }
+
+ // Write jcl header
+ strncpy(header, original_opts[0], p - original_opts[0]);
+ header[p - original_opts[0]] = '\0';
+ fprintf(stream, "%s", header);
+
+ // Insert the JCL commands from the PPD file right before the first
+ // "@PJL SET ..." line from the, if there are no "@PJL SET ..." lines,
+ // directly before "@PJL ENTER LANGUAGE ...", otherwise after the JCL
+ // commands from the driver
+ for (optsp1 = original_opts; *(optsp1 + 1); optsp1++)
+ {
+ if (optsp2 == NULL &&
+ ((strstr(*optsp1, "ENTER LANGUAGE") != NULL) ||
+ (strncasecmp(*optsp1, "@PJL SET ", 9) == 0)))
{
- /* If we have only one line of JCL it is probably something like the
- * "@PJL ENTER LANGUAGE=..." line which has to be in the end, but it
- * also contains the "<esc>%-12345X" which has to be in the beginning
- * of the job */
- if (p)
- fwrite_or_die(original_opts[0], 1, p - original_opts[0], stream);
- else
- fprintf(stream, "%s\n", original_opts[0]);
-
- argv_write(stream, opts, "\n");
-
- if (p)
- fprintf(stream, "%s\n", p);
-
- write_binary_data(stream, original_opts[1], readbinarybytes);
- return 1;
+ for (optsp2 = opts; *optsp2; optsp2++)
+ if (!jcl_options_find_keyword(original_opts, *optsp2, jclstr))
+ fprintf(stream, "%s\n", *optsp2);
}
+ if (optsp1 != original_opts) p = *optsp1;
+ if (!p)
+ _log("write_merged_jcl_options() dereferences NULL pointer p\n");
+ if (jcl_options_find_keyword(opts, p, jclstr))
+ fprintf(stream, "%s\n", jcl_options_find_keyword(opts, p, jclstr));
+ else
+ fprintf(stream, "%s\n", p);
+ }
+ if (optsp2 == NULL)
+ for (optsp2 = opts; *optsp2; optsp2++)
+ if (!jcl_options_find_keyword(original_opts, *optsp2, jclstr))
+ fprintf(stream, "%s\n", *optsp2);
- /* Write jcl header */
- strncpy(header, original_opts[0], p - original_opts[0]);
- header[p - original_opts[0]] = '\0';
- fprintf(stream, "%s", header);
-
- /* Insert the JCL commands from the PPD file right before the first
- "@PJL SET ..." line from the, if there are no "@PJL SET ..." lines,
- directly before "@PJL ENTER LANGUAGE ...", otherwise after the JCL
- commands from the driver */
- for (optsp1 = original_opts; *(optsp1 + 1); optsp1++) {
- if (optsp2 == NULL &&
- ((strstr(*optsp1, "ENTER LANGUAGE") != NULL) ||
- (strncasecmp(*optsp1, "@PJL SET ", 9) == 0))) {
- for (optsp2 = opts; *optsp2; optsp2++)
- if (!jcl_options_find_keyword(original_opts, *optsp2, jclstr))
- fprintf(stream, "%s\n", *optsp2);
- }
- if (optsp1 != original_opts) p = *optsp1;
- if (!p)
- _log("write_merged_jcl_options() dereferences NULL pointer p\n");
- if (jcl_options_find_keyword(opts, p, jclstr))
- fprintf(stream, "%s\n", jcl_options_find_keyword(opts, p, jclstr));
- else
- fprintf(stream, "%s\n", p);
- }
- if (optsp2 == NULL)
- for (optsp2 = opts; *optsp2; optsp2++)
- if (!jcl_options_find_keyword(original_opts, *optsp2, jclstr))
- fprintf(stream, "%s\n", *optsp2);
-
- write_binary_data(stream, *optsp1, readbinarybytes);
+ write_binary_data(stream, *optsp1, readbinarybytes);
- return 1;
+ return (1);
}
-void log_jcl()
+
+void
+log_jcl()
{
- char **opt;
+ char **opt;
- _log("JCL: %s", jclbegin);
- if (jclprepend)
- for (opt = jclprepend; *opt; opt++)
- _log("%s\n", *opt);
+ _log("JCL: %s", jclbegin);
+ if (jclprepend)
+ for (opt = jclprepend; *opt; opt++)
+ _log("%s\n", *opt);
- _log("<job data> %s\n\n", jclappend->data);
+ _log("<job data> %s\n\n", jclappend->data);
}
-int exec_kid4(FILE *in, FILE *out, void *user_arg)
+
+int
+exec_kid4(FILE *in,
+ FILE *out,
+ void *user_arg)
{
- FILE *fileh = open_postpipe();
- int driverjcl = 0;
- size_t readbinarybytes;
+ FILE *fileh = open_postpipe();
+ int driverjcl = 0;
+ size_t readbinarybytes;
+
+ log_jcl();
+
+ // wrap the JCL around the job data, if there are any options specified...
+ // Should the driver already have inserted JCL commands we merge our JCL
+ // header with the one from the driver
+ if (argv_count(jclprepend) > 0)
+ {
+ if (!isspace(jclprepend[0][0]))
+ {
+ char *jclstr, **jclheader;
+ size_t pos;
- log_jcl();
+ pos = strcspn(jclprepend[0], " \t\n\r");
+ jclstr = malloc(pos +1);
+ strncpy(jclstr, jclprepend[0], pos);
+ jclstr[pos] = '\0';
- /* wrap the JCL around the job data, if there are any options specified...
- * Should the driver already have inserted JCL commands we merge our JCL
- * header with the one from the driver */
- if (argv_count(jclprepend) > 0)
- {
- if (!isspace(jclprepend[0][0]))
- {
- char *jclstr, **jclheader;
- size_t pos;
-
- pos = strcspn(jclprepend[0], " \t\n\r");
- jclstr = malloc(pos +1);
- strncpy(jclstr, jclprepend[0], pos);
- jclstr[pos] = '\0';
-
- jclheader = read_jcl_lines(in, jclstr, &readbinarybytes);
-
- driverjcl = write_merged_jcl_options(fileh,
- jclheader,
- jclprepend,
- readbinarybytes,
- jclstr);
-
- free(jclstr);
- argv_free(jclheader);
- }
- else
- /* No merging of JCL header possible, simply prepend it */
- argv_write(fileh, jclprepend, "\n");
+ jclheader = read_jcl_lines(in, jclstr, &readbinarybytes);
+
+ driverjcl = write_merged_jcl_options(fileh,
+ jclheader,
+ jclprepend,
+ readbinarybytes,
+ jclstr);
+
+ free(jclstr);
+ argv_free(jclheader);
}
+ else
+ // No merging of JCL header possible, simply prepend it
+ argv_write(fileh, jclprepend, "\n");
+ }
- /* The job data */
- copy_file(fileh, in, NULL, 0);
+ // The job data
+ copy_file(fileh, in, NULL, 0);
- /* A JCL trailer */
- if (argv_count(jclprepend) > 0 && !driverjcl)
- fwrite_or_die(jclappend->data, jclappend->len, 1, fileh);
+ // A JCL trailer
+ if (argv_count(jclprepend) > 0 && !driverjcl)
+ fwrite_or_die(jclappend->data, jclappend->len, 1, fileh);
- fclose(in);
- if (fclose(fileh) != 0)
- {
- _log("error closing postpipe\n");
- return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
- }
+ fclose(in);
+ if (fclose(fileh) != 0)
+ {
+ _log("error closing postpipe\n");
+ return (EXIT_PRNERR_NORETRY_BAD_SETTINGS);
+ }
- return EXIT_PRINTED;
+ return (EXIT_PRINTED);
}
-int exec_kid3(FILE *in, FILE *out, void *user_arg)
+
+int
+exec_kid3(FILE *in,
+ FILE *out,
+ void *user_arg)
{
- dstr_t *commandline;
- int kid4;
- FILE *kid4in;
- int status;
-
- commandline = create_dstr();
- dstrcpy(commandline, (const char *)user_arg);
-
- kid4 = start_process("kid4", exec_kid4, NULL, &kid4in, NULL);
- if (kid4 < 0) {
- free_dstr(commandline);
- return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
- }
+ dstr_t *commandline;
+ int kid4;
+ FILE *kid4in;
+ int status;
- if (in && dup2(fileno(in), fileno(stdin)) < 0) {
- _log("kid3: Could not dup stdin\n");
- fclose(kid4in);
- free_dstr(commandline);
- return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
- }
- if (dup2(fileno(kid4in), fileno(stdout)) < 0) {
- _log("kid3: Could not dup stdout to kid4\n");
- fclose(kid4in);
- free_dstr(commandline);
- return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
- }
- if (debug)
- {
- if (!redirect_log_to_stderr()) {
- fclose(kid4in);
- free_dstr(commandline);
- return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
- }
-
- /* Save the data supposed to be fed into the renderer also into a file*/
- dstrprepend(commandline, "tee $(mktemp " LOG_FILE "-XXXXXX.ps) | ( ");
- dstrcat(commandline, ")");
- }
+ commandline = create_dstr();
+ dstrcpy(commandline, (const char *)user_arg);
- /* Actually run the thing */
- status = run_system_process("renderer", commandline->data);
+ kid4 = start_process("kid4", exec_kid4, NULL, &kid4in, NULL);
+ if (kid4 < 0)
+ {
+ free_dstr(commandline);
+ return (EXIT_PRNERR_NORETRY_BAD_SETTINGS);
+ }
- if (in)
- fclose(in);
+ if (in && dup2(fileno(in), fileno(stdin)) < 0)
+ {
+ _log("kid3: Could not dup stdin\n");
+ fclose(kid4in);
+ free_dstr(commandline);
+ return (EXIT_PRNERR_NORETRY_BAD_SETTINGS);
+ }
+ if (dup2(fileno(kid4in), fileno(stdout)) < 0)
+ {
+ _log("kid3: Could not dup stdout to kid4\n");
fclose(kid4in);
- fclose(stdin);
- fclose(stdout);
free_dstr(commandline);
+ return (EXIT_PRNERR_NORETRY_BAD_SETTINGS);
+ }
+ if (debug)
+ {
+ if (!redirect_log_to_stderr())
+ {
+ fclose(kid4in);
+ free_dstr(commandline);
+ return (EXIT_PRNERR_NORETRY_BAD_SETTINGS);
+ }
+
+ // Save the data supposed to be fed into the renderer also into a file
+ dstrprepend(commandline, "tee $(mktemp " LOG_FILE "-XXXXXX.ps) | ( ");
+ dstrcat(commandline, ")");
+ }
+
+ // Actually run the thing
+ status = run_system_process("renderer", commandline->data);
- if (WIFEXITED(status)) {
- switch (WEXITSTATUS(status)) {
- case 0: /* Success! */
- /* wait for postpipe/output child */
- wait_for_process(kid4);
- _log("kid3 finished\n");
- return EXIT_PRINTED;
- case 1:
- _log("Possible error on renderer command line or PostScript error. Check options.");
- return EXIT_JOBERR;
- case 139:
- _log("The renderer may have dumped core.");
- return EXIT_JOBERR;
- case 141:
- _log("A filter used in addition to the renderer itself may have failed.");
- return EXIT_PRNERR;
- case 243:
- case 255: /* PostScript error? */
- return EXIT_JOBERR;
- }
+ if (in)
+ fclose(in);
+ fclose(kid4in);
+ fclose(stdin);
+ fclose(stdout);
+ free_dstr(commandline);
+
+ if (WIFEXITED(status))
+ {
+ switch (WEXITSTATUS(status))
+ {
+ case 0: // Success!
+ // wait for postpipe/output child
+ wait_for_process(kid4);
+ _log("kid3 finished\n");
+ return (EXIT_PRINTED);
+ case 1:
+ _log("Possible error on renderer command line or PostScript error. Check options.");
+ return (EXIT_JOBERR);
+ case 139:
+ _log("The renderer may have dumped core.");
+ return (EXIT_JOBERR);
+ case 141:
+ _log("A filter used in addition to the renderer itself may have failed.");
+ return (EXIT_PRNERR);
+ case 243:
+ case 255: // PostScript error?
+ return (EXIT_JOBERR);
}
- else if (WIFSIGNALED(status)) {
- switch (WTERMSIG(status)) {
- case SIGUSR1:
- return EXIT_PRNERR;
- case SIGUSR2:
- return EXIT_PRNERR_NORETRY;
- case SIGTTIN:
- return EXIT_ENGAGED;
- }
+ }
+ else if (WIFSIGNALED(status))
+ {
+ switch (WTERMSIG(status))
+ {
+ case SIGUSR1:
+ return (EXIT_PRNERR);
+ case SIGUSR2:
+ return (EXIT_PRNERR_NORETRY);
+ case SIGTTIN:
+ return (EXIT_ENGAGED);
}
- return EXIT_PRNERR;
+ }
+ return (EXIT_PRNERR);
}
-
-/* renderer.h
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// renderer.h
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#ifndef renderer_h
#define renderer_h
void massage_gs_commandline(dstr_t *cmd);
int exec_kid3(FILE *in, FILE *out, void *user_arg);
-#endif
-
+#endif // !renderer_h
-/* spooler.c
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// spooler.c
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#include "spooler.h"
#include "foomaticrip.h"
#include <unistd.h>
#include <limits.h>
-const char *spooler_name(int spooler)
+
+const char *
+spooler_name(int spooler)
{
- switch (spooler) {
- case SPOOLER_CUPS: return "cups";
- case SPOOLER_DIRECT: return "direct";
- };
- return "<unknown>";
+ switch (spooler)
+ {
+ case SPOOLER_CUPS:
+ return ("cups");
+ case SPOOLER_DIRECT:
+ return ("direct");
+ };
+ return ("<unknown>");
}
-void init_cups(list_t *arglist, dstr_t *filelist, jobparams_t *job)
+
+void
+init_cups(list_t *arglist,
+ dstr_t *filelist,
+ jobparams_t *job)
{
- char path [PATH_MAX] = "";
- char cups_jobid [128];
- char cups_user [128];
- char cups_jobtitle [2048];
- char cups_copies [128];
- int cups_options_len;
- char *cups_options;
- const char *pname;
- char cups_filename [256];
-
- if (getenv("CUPS_FONTPATH"))
- strncpy(path, getenv("CUPS_FONTPATH"), PATH_MAX - 1);
- else if (getenv("CUPS_DATADIR")) {
- strncpy(path, getenv("CUPS_DATADIR"), PATH_MAX - 1);
- strncat(path, "/fonts", PATH_MAX - strlen(path) - 1);
- }
- if (getenv("GS_LIB")) {
- strncat(path, ":", PATH_MAX - strlen(path) - 1);
- strncat(path, getenv("GS_LIB"), PATH_MAX - strlen(path) - 1);
- }
- setenv("GS_LIB", path, 1);
+ char path [PATH_MAX] = "";
+ char cups_jobid [128];
+ char cups_user [128];
+ char cups_jobtitle [2048];
+ char cups_copies [128];
+ int cups_options_len;
+ char *cups_options;
+ const char *pname;
+ char cups_filename [256];
- /* Get all command line parameters */
- strncpy_omit(cups_jobid, arglist_get(arglist, 0), 128, omit_shellescapes);
- strncpy_omit(cups_user, arglist_get(arglist, 1), 128, omit_shellescapes);
- strncpy_omit(cups_jobtitle, arglist_get(arglist, 2), 2048,
- omit_shellescapes);
- strncpy_omit(cups_copies, arglist_get(arglist, 3), 128, omit_shellescapes);
+ if (getenv("CUPS_FONTPATH"))
+ strncpy(path, getenv("CUPS_FONTPATH"), PATH_MAX - 1);
+ else if (getenv("CUPS_DATADIR"))
+ {
+ strncpy(path, getenv("CUPS_DATADIR"), PATH_MAX - 1);
+ strncat(path, "/fonts", PATH_MAX - strlen(path) - 1);
+ }
+ if (getenv("GS_LIB"))
+ {
+ strncat(path, ":", PATH_MAX - strlen(path) - 1);
+ strncat(path, getenv("GS_LIB"), PATH_MAX - strlen(path) - 1);
+ }
+ setenv("GS_LIB", path, 1);
- cups_options_len = strlen(arglist_get(arglist, 4));
- cups_options = malloc(cups_options_len + 1);
- strncpy_omit(cups_options, arglist_get(arglist, 4), cups_options_len + 1,
- omit_shellescapes);
+ // Get all command line parameters
+ strncpy_omit(cups_jobid, arglist_get(arglist, 0), 128, omit_shellescapes);
+ strncpy_omit(cups_user, arglist_get(arglist, 1), 128, omit_shellescapes);
+ strncpy_omit(cups_jobtitle, arglist_get(arglist, 2), 2048,
+ omit_shellescapes);
+ strncpy_omit(cups_copies, arglist_get(arglist, 3), 128, omit_shellescapes);
+
+ cups_options_len = strlen(arglist_get(arglist, 4));
+ cups_options = malloc(cups_options_len + 1);
+ strncpy_omit(cups_options, arglist_get(arglist, 4), cups_options_len + 1,
+ omit_shellescapes);
- /* Common job parameters */
- strcpy(job->id, cups_jobid);
- strcpy(job->title, cups_jobtitle);
- strcpy(job->user, cups_user);
- strcpy(job->copies, cups_copies);
- dstrcatf(job->optstr, " %s", cups_options);
-
- /* Check for and handle inputfile vs stdin */
- if (list_item_count(arglist) > 4) {
- strncpy_omit(cups_filename, arglist_get(arglist, 5), 256, omit_shellescapes);
- if (cups_filename[0] != '-') {
- /* We get input from a file */
- dstrcatf(filelist, "%s ", cups_filename);
- _log("Getting input from file %s\n", cups_filename);
- }
+ // Common job parameters
+ strcpy(job->id, cups_jobid);
+ strcpy(job->title, cups_jobtitle);
+ strcpy(job->user, cups_user);
+ strcpy(job->copies, cups_copies);
+ dstrcatf(job->optstr, " %s", cups_options);
+
+ // Check for and handle inputfile vs stdin
+ if (list_item_count(arglist) > 4)
+ {
+ strncpy_omit(cups_filename, arglist_get(arglist, 5), 256,
+ omit_shellescapes);
+ if (cups_filename[0] != '-')
+ {
+ // We get input from a file
+ dstrcatf(filelist, "%s ", cups_filename);
+ _log("Getting input from file %s\n", cups_filename);
}
+ }
- /* On which queue are we printing?
- CUPS puts the print queue name into the PRINTER environment variable
- when calling filters. */
- pname = getenv("PRINTER");
- if (pname == NULL)
- pname = "unknown";
- strncpy(job->printer, pname, 256);
- job->printer[255] = '\0';
+ // On which queue are we printing?
+ // CUPS puts the print queue name into the PRINTER environment variable
+ // when calling filters.
+ pname = getenv("PRINTER");
+ if (pname == NULL)
+ pname = "unknown";
+ strncpy(job->printer, pname, 256);
+ job->printer[255] = '\0';
- free(cups_options);
+ free(cups_options);
}
-/* used by init_direct to find a ppd file */
-int find_ppdfile(const char *user_default_path, jobparams_t *job)
+
+// used by init_direct to find a ppd file
+int
+find_ppdfile(const char *user_default_path,
+ jobparams_t *job)
{
- /* Search also common spooler-specific locations, this way a printer
- configured under a certain spooler can also be used without spooler */
-
- strcpy(job->ppdfile, job->printer);
- if (access(job->ppdfile, R_OK) == 0)
- return 1;
-
- snprintf(job->ppdfile, 2048, "%s.ppd", job->printer); /* current dir */
- if (access(job->ppdfile, R_OK) == 0)
- return 1;
- snprintf(job->ppdfile, 2048, "%s/%s.ppd", user_default_path, job->printer); /* user dir */
- if (access(job->ppdfile, R_OK) == 0)
- return 1;
- snprintf(job->ppdfile, 2048, "%s/direct/%s.ppd", CONFIG_PATH, job->printer); /* system dir */
- if (access(job->ppdfile, R_OK) == 0)
- return 1;
- snprintf(job->ppdfile, 2048, "%s/%s.ppd", CONFIG_PATH, job->printer); /* system dir */
- if (access(job->ppdfile, R_OK) == 0)
- return 1;
- snprintf(job->ppdfile, 2048, "/etc/cups/ppd/%s.ppd", job->printer); /* CUPS config dir */
- if (access(job->ppdfile, R_OK) == 0)
- return 1;
- snprintf(job->ppdfile, 2048, "/usr/local/etc/cups/ppd/%s.ppd", job->printer); /* CUPS config dir */
- if (access(job->ppdfile, R_OK) == 0)
- return 1;
-
- /* nothing found */
- job->ppdfile[0] = '\0';
- return 0;
+ // Search also common spooler-specific locations, this way a printer
+ // configured under a certain spooler can also be used without spooler
+
+ strcpy(job->ppdfile, job->printer);
+ if (access(job->ppdfile, R_OK) == 0)
+ return (1);
+
+ snprintf(job->ppdfile, 2048, "%s.ppd", job->printer); // current dir
+ if (access(job->ppdfile, R_OK) == 0)
+ return (1);
+ snprintf(job->ppdfile, 2048, "%s/%s.ppd", user_default_path, job->printer);
+ // user dir
+ if (access(job->ppdfile, R_OK) == 0)
+ return (1);
+ snprintf(job->ppdfile, 2048, "%s/direct/%s.ppd", CONFIG_PATH, job->printer);
+ // system dir
+ if (access(job->ppdfile, R_OK) == 0)
+ return (1);
+ snprintf(job->ppdfile, 2048, "%s/%s.ppd", CONFIG_PATH, job->printer);
+ // system dir
+ if (access(job->ppdfile, R_OK) == 0)
+ return (1);
+ snprintf(job->ppdfile, 2048, "/etc/cups/ppd/%s.ppd", job->printer);
+ // CUPS config dir
+ if (access(job->ppdfile, R_OK) == 0)
+ return (1);
+ snprintf(job->ppdfile, 2048, "/usr/local/etc/cups/ppd/%s.ppd", job->printer);
+ // CUPS config dir
+ if (access(job->ppdfile, R_OK) == 0)
+ return (1);
+
+ // nothing found
+ job->ppdfile[0] = '\0';
+ return (0);
}
-/* search 'configfile' for 'key', copy value into dest, return success */
-int configfile_find_option(const char *configfile, const char *key, char *dest, size_t destsize)
+
+// search 'configfile' for 'key', copy value into dest, return success
+int
+configfile_find_option(const char *configfile,
+ const char *key,
+ char *dest,
+ size_t destsize)
{
- FILE *fh;
- char line [1024];
- char *p;
-
- dest[0] = '\0';
-
- if (!(fh = fopen(configfile, "r")))
- return 0;
-
- while (fgets(line, 1024, fh)) {
- if (!prefixcmp(line, "default")) {
- p = strchr(line, ':');
- if (p) {
- strncpy_omit(dest, p + 1, destsize, omit_whitespace_newline);
- if (dest[0])
- break;
- }
- }
+ FILE *fh;
+ char line [1024];
+ char *p;
+
+ dest[0] = '\0';
+
+ if (!(fh = fopen(configfile, "r")))
+ return (0);
+
+ while (fgets(line, 1024, fh))
+ {
+ if (!prefixcmp(line, "default"))
+ {
+ p = strchr(line, ':');
+ if (p)
+ {
+ strncpy_omit(dest, p + 1, destsize, omit_whitespace_newline);
+ if (dest[0])
+ break;
+ }
}
- fclose(fh);
- return dest[0] != '\0';
+ }
+ fclose(fh);
+ return (dest[0] != '\0');
}
-/* tries to find a default printer name in various config files and copies the
- * result into the global var 'printer'. Returns success */
-int find_default_printer(const char *user_default_path, jobparams_t *job)
+
+// tries to find a default printer name in various config files and copies the
+// result into the global var 'printer'. Returns success
+int
+find_default_printer(const char *user_default_path,
+ jobparams_t *job)
{
- char configfile [1024];
- char *key = "default";
-
- if (configfile_find_option("./.directconfig", key, job->printer, 256))
- return 1;
- if (configfile_find_option("./directconfig", key, job->printer, 256))
- return 1;
- if (configfile_find_option("./.config", key, job->printer, 256))
- return 1;
- strlcpy(configfile, user_default_path, 1024);
- strlcat(configfile, "/direct/.config", 1024);
- if (configfile_find_option(configfile, key, job->printer, 256))
- return 1;
- strlcpy(configfile, user_default_path, 1024);
- strlcat(configfile, "/direct.conf", 1024);
- if (configfile_find_option(configfile, key, job->printer, 256))
- return 1;
- if (configfile_find_option(CONFIG_PATH "/direct/.config", key, job->printer, 256))
- return 1;
- if (configfile_find_option(CONFIG_PATH "/direct.conf", key, job->printer, 256))
- return 1;
-
- return 0;
+ char configfile [1024];
+ char *key = "default";
+
+ if (configfile_find_option("./.directconfig", key, job->printer, 256))
+ return (1);
+ if (configfile_find_option("./directconfig", key, job->printer, 256))
+ return (1);
+ if (configfile_find_option("./.config", key, job->printer, 256))
+ return (1);
+ strlcpy(configfile, user_default_path, 1024);
+ strlcat(configfile, "/direct/.config", 1024);
+ if (configfile_find_option(configfile, key, job->printer, 256))
+ return (1);
+ strlcpy(configfile, user_default_path, 1024);
+ strlcat(configfile, "/direct.conf", 1024);
+ if (configfile_find_option(configfile, key, job->printer, 256))
+ return (1);
+ if (configfile_find_option(CONFIG_PATH "/direct/.config", key, job->printer,
+ 256))
+ return (1);
+ if (configfile_find_option(CONFIG_PATH "/direct.conf", key, job->printer,
+ 256))
+ return (1);
+
+ return (0);
}
-void init_direct(list_t *arglist, dstr_t *filelist, jobparams_t *job)
+
+void
+init_direct(list_t *arglist,
+ dstr_t *filelist,
+ jobparams_t *job)
{
- char tmp [1024];
- listitem_t *i;
- char user_default_path [PATH_MAX];
+ char tmp [1024];
+ listitem_t *i;
+ char user_default_path [PATH_MAX];
+
+ strlcpy(user_default_path, getenv("HOME"), 256);
+ strlcat(user_default_path, "/.foomatic/", 256);
- strlcpy(user_default_path, getenv("HOME"), 256);
- strlcat(user_default_path, "/.foomatic/", 256);
+ // Which files do we want to print?
+ for (i = arglist->first; i; i = i->next)
+ {
+ strncpy_omit(tmp, (char*)i->data, 1024, omit_shellescapes);
+ dstrcatf(filelist, "%s ", tmp);
+ }
- /* Which files do we want to print? */
- for (i = arglist->first; i; i = i->next) {
- strncpy_omit(tmp, (char*)i->data, 1024, omit_shellescapes);
- dstrcatf(filelist, "%s ", tmp);
+ if (job->ppdfile[0] == '\0')
+ {
+ if (job->printer[0] == '\0')
+ {
+ // No printer definition file selected, check whether we have a
+ // default printer defined
+ find_default_printer(user_default_path, job);
}
- if (job->ppdfile[0] == '\0') {
- if (job->printer[0] == '\0') {
- /* No printer definition file selected, check whether we have a
- default printer defined */
- find_default_printer(user_default_path, job);
- }
-
- /* Neither in a config file nor on the command line a printer was selected */
- if (!job->printer[0]) {
- _log("No printer definition (option \"-P <name>\") specified!\n");
- exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
- }
-
- /* Search for the PPD file */
- if (!find_ppdfile(user_default_path, job)) {
- _log("There is no readable PPD file for the printer %s, is it configured?\n", job->printer);
- exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
- }
+ // Neither in a config file nor on the command line a printer was selected
+ if (!job->printer[0])
+ {
+ _log("No printer definition (option \"-P <name>\") specified!\n");
+ exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
}
-}
+ // Search for the PPD file
+ if (!find_ppdfile(user_default_path, job))
+ {
+ _log("There is no readable PPD file for the printer %s, is it configured?\n",
+ job->printer);
+ exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
+ }
+ }
+}
-/* spooler.h
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// spooler.h
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#ifndef SPOOLER_H
#define SPOOLER_H
void init_cups(list_t *arglist, dstr_t *filelist, jobparams_t *job);
void init_direct(list_t *arglist, dstr_t *filelist, jobparams_t *job);
-#endif
+#endif // !SPOOLER_H
-/* util.c
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// util.c
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#include "util.h"
#include "foomaticrip.h"
#include <errno.h>
-const char* shellescapes = "|;<>&!$\'\"`#*?()[]{}";
+const char *shellescapes = "|;<>&!$\'\"`#*?()[]{}";
-const char * temp_dir()
+
+const char *
+temp_dir()
{
- static const char *tmpdir = NULL;
+ static const char *tmpdir = NULL;
+
+ if (!tmpdir)
+ {
+ const char *dirs[] = { getenv("TMPDIR"), P_tmpdir, "/tmp" };
+ int i;
- if (!tmpdir)
+ for (i = 0; i < (sizeof(dirs) / sizeof(dirs[0])); i++)
{
- const char *dirs[] = { getenv("TMPDIR"), P_tmpdir, "/tmp" };
- int i;
-
- for (i = 0; i < (sizeof(dirs) / sizeof(dirs[0])); i++) {
- if (access(dirs[i], W_OK) == 0) {
- tmpdir = dirs[i];
- break;
- }
- }
- if (tmpdir)
- {
- _log("Storing temporary files in %s\n", tmpdir);
- setenv("TMPDIR", tmpdir, 1); /* for child processes */
- }
- else
- rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
- "Cannot find a writable temp dir.");
+ if (access(dirs[i], W_OK) == 0)
+ {
+ tmpdir = dirs[i];
+ break;
+ }
}
+ if (tmpdir)
+ {
+ _log("Storing temporary files in %s\n", tmpdir);
+ setenv("TMPDIR", tmpdir, 1); // for child processes
+ }
+ else
+ rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
+ "Cannot find a writable temp dir.");
+ }
- return tmpdir;
+ return (tmpdir);
}
-int prefixcmp(const char *str, const char *prefix)
+
+int
+prefixcmp(const char *str,
+ const char *prefix)
{
- return strncmp(str, prefix, strlen(prefix));
+ return (strncmp(str, prefix, strlen(prefix)));
}
-int prefixcasecmp(const char *str, const char *prefix)
+
+int
+prefixcasecmp(const char *str,
+ const char *prefix)
{
- return strncasecmp(str, prefix, strlen(prefix));
+ return (strncasecmp(str, prefix, strlen(prefix)));
}
-int startswith(const char *str, const char *prefix)
+
+int
+startswith(const char *str,
+ const char *prefix)
{
- return str ? (strncmp(str, prefix, strlen(prefix)) == 0) : 0;
+ return (str ? (strncmp(str, prefix, strlen(prefix)) == 0) : 0);
}
-int endswith(const char *str, const char *postfix)
+
+int
+endswith(const char *str,
+ const char *postfix)
{
- int slen = strlen(str);
- int plen = strlen(postfix);
- const char *pstr;
+ int slen = strlen(str);
+ int plen = strlen(postfix);
+ const char *pstr;
- if (slen < plen)
- return 0;
+ if (slen < plen)
+ return (0);
- pstr = &str[slen - plen];
- return strcmp(pstr, postfix) == 0;
+ pstr = &str[slen - plen];
+ return (strcmp(pstr, postfix) == 0);
}
-const char * skip_whitespace(const char *str)
+
+const char *
+skip_whitespace(const char *str)
{
- while (*str && isspace(*str))
- str++;
- return str;
+ while (*str && isspace(*str))
+ str ++;
+ return (str);
}
-void strlower(char *dest, size_t destlen, const char *src)
+
+void
+strlower(char *dest,
+ size_t destlen,
+ const char *src)
{
- char *pdest = dest;
- const char *psrc = src;
- while (*psrc && --destlen > 0)
- {
- *pdest = tolower(*psrc);
- pdest++;
- psrc++;
- }
- *pdest = '\0';
+ char *pdest = dest;
+ const char *psrc = src;
+ while (*psrc && --destlen > 0)
+ {
+ *pdest = tolower(*psrc);
+ pdest++;
+ psrc++;
+ }
+ *pdest = '\0';
}
+
int isempty(const char *string)
{
- return !string || string[0] == '\0';
-}
-
-const char * strncpy_omit(char* dest, const char* src, size_t n, int (*omit_func)(int))
-{
- const char* psrc = src;
- char* pdest = dest;
- int cnt = n -1;
- if (!pdest)
- return NULL;
- if (psrc) {
- while (*psrc != 0 && cnt > 0) {
- if (!omit_func(*psrc)) {
- *pdest = *psrc;
- pdest++;
- cnt--;
- }
- psrc++;
- }
+ return (!string || string[0] == '\0');
+}
+
+
+const char *
+strncpy_omit(char* dest,
+ const char* src,
+ size_t n,
+ int (*omit_func)(int))
+{
+ const char* psrc = src;
+ char* pdest = dest;
+ int cnt = n - 1;
+
+ if (!pdest)
+ return (NULL);
+
+ if (psrc)
+ {
+ while (*psrc != 0 && cnt > 0)
+ {
+ if (!omit_func(*psrc))
+ {
+ *pdest = *psrc;
+ pdest++;
+ cnt--;
+ }
+ psrc++;
}
- *pdest = '\0';
- return psrc;
+ }
+ *pdest = '\0';
+ return (psrc);
}
-int omit_unprintables(int c) { return c>= '\x00' && c <= '\x1f'; }
-int omit_shellescapes(int c) { return strchr(shellescapes, c) != NULL; }
-int omit_specialchars(int c) { return omit_unprintables(c) || omit_shellescapes(c); }
-int omit_whitespace(int c) { return c == ' ' || c == '\t'; }
-int omit_whitespace_newline(int c) { return omit_whitespace(c) || c == '\n'; }
+
+
+int omit_unprintables(int c) { return (c >= '\x00' && c <= '\x1f'); }
+int omit_shellescapes(int c) { return (strchr(shellescapes, c) != NULL); }
+int omit_specialchars(int c) { return (omit_unprintables(c) ||
+ omit_shellescapes(c)); }
+int omit_whitespace(int c) { return (c == ' ' || c == '\t'); }
+int omit_whitespace_newline(int c) { return (omit_whitespace(c) || c == '\n'); }
+
#ifndef HAVE_STRCASESTR
char *
-strcasestr (const char *haystack, const char *needle)
-{
- char *p, *startn = 0, *np = 0;
-
- for (p = haystack; *p; p++) {
- if (np) {
- if (toupper(*p) == toupper(*np)) {
- if (!*++np)
- return startn;
- } else
- np = 0;
- } else if (toupper(*p) == toupper(*needle)) {
- np = needle + 1;
- startn = p;
- }
+strcasestr (const char *haystack,
+ const char *needle)
+{
+ char *p, *startn = 0, *np = 0;
+
+ for (p = haystack; *p; p++)
+ {
+ if (np)
+ {
+ if (toupper(*p) == toupper(*np))
+ {
+ if (!*++np)
+ return (startn);
+ }
+ else
+ np = 0;
}
+ else if (toupper(*p) == toupper(*needle))
+ {
+ np = needle + 1;
+ startn = p;
+ }
+ }
- return 0;
+ return (0);
}
#endif
+
#ifndef __OpenBSD__
#ifndef HAVE_STRLCPY
-size_t strlcpy(char *dest, const char *src, size_t size)
-{
- char *pdest = dest;
- const char *psrc = src;
-
- if (!src) {
- dest[0] = '\0';
- return 0;
- }
+size_t
+strlcpy(char *dest,
+ const char *src,
+ size_t size)
+{
+ char *pdest = dest;
+ const char *psrc = src;
+
+ if (!src)
+ {
+ dest[0] = '\0';
+ return (0);
+ }
+
+ if (size)
+ {
+ while (--size && (*pdest++ = *psrc++) != '\0');
+ *pdest = '\0';
+ }
+
+ if (!size)
+ while (*psrc++);
- if (size) {
- while (--size && (*pdest++ = *psrc++) != '\0');
- *pdest = '\0';
- }
- if (!size)
- while (*psrc++);
- return (psrc - src -1);
+ return (psrc - src - 1);
}
-#endif /* ! HAVE_STRLCPY */
+#endif // ! HAVE_STRLCPY
+
#ifndef HAVE_STRLCAT
-size_t strlcat(char *dest, const char *src, size_t size)
+size_t
+strlcat(char *dest,
+ const char *src,
+ size_t size)
{
- char *pdest = dest;
- const char *psrc = src;
- size_t i = size;
- size_t len;
+ char *pdest = dest;
+ const char *psrc = src;
+ size_t i = size;
+ size_t len;
- while (--i && *pdest)
- pdest++;
- len = pdest - dest;
+ while (--i && *pdest)
+ pdest++;
+ len = pdest - dest;
- if (!i)
- return strlen(src) + len;
+ if (!i)
+ return (strlen(src) + len);
- while (i-- && *psrc)
- *pdest++ = *psrc++;
- *pdest = '\0';
+ while (i-- && *psrc)
+ *pdest++ = *psrc++;
+ *pdest = '\0';
- return len + (psrc - src);
+ return (len + (psrc - src));
}
-#endif /* ! HAVE_STRLCAT */
-#endif /* ! __OpenBSD__ */
+#endif // ! HAVE_STRLCAT
+#endif // ! __OpenBSD__
-void strrepl(char *str, const char *chars, char repl)
+
+void
+strrepl(char *str,
+ const char *chars,
+ char repl)
{
- char *p = str;
+ char *p = str;
- while (*p) {
- if (strchr(chars, *p))
- *p = repl;
- p++;
- }
+ while (*p)
+ {
+ if (strchr(chars, *p))
+ *p = repl;
+ p++;
+ }
}
-void strrepl_nodups(char *str, const char *chars, char repl)
-{
- char *pstr = str;
- char *p = str;
- int prev = 0;
-
- while (*pstr) {
- if (strchr(chars, *pstr) || *pstr == repl) {
- if (!prev) {
- *p = repl;
- p++;
- prev = 1;
- }
- }
- else {
- *p = *pstr;
- p++;
- prev = 0;
- }
- pstr++;
+
+void
+strrepl_nodups(char *str,
+ const char *chars,
+ char repl)
+{
+ char *pstr = str;
+ char *p = str;
+ int prev = 0;
+
+ while (*pstr)
+ {
+ if (strchr(chars, *pstr) || *pstr == repl)
+ {
+ if (!prev)
+ {
+ *p = repl;
+ p++;
+ prev = 1;
+ }
}
- *p = '\0';
+ else
+ {
+ *p = *pstr;
+ p++;
+ prev = 0;
+ }
+ pstr++;
+ }
+ *p = '\0';
}
-void strclr(char *str)
+
+void
+strclr(char *str)
{
- while (*str) {
- *str = '\0';
- str++;
- }
+ while (*str)
+ {
+ *str = '\0';
+ str++;
+ }
}
-char * strnchr(const char *str, int c, size_t n)
+
+char *
+strnchr(const char *str,
+ int c,
+ size_t n)
{
- char *p = (char*)str;
+ char *p = (char*)str;
- while (*p && --n > 0) {
- if (*p == (char)c)
- return p;
- p++;
- }
- return p;
+ while (*p && --n > 0)
+ {
+ if (*p == (char)c)
+ return (p);
+ p++;
+ }
+ return (p);
}
-void escapechars(char *dest, size_t size, const char *src, const char *esc_chars)
+
+void
+escapechars(char *dest,
+ size_t size,
+ const char *src,
+ const char *esc_chars)
{
- const char *psrc = src;
+ const char *psrc = src;
- while (*psrc && --size > 0) {
- if (strchr(esc_chars, *psrc))
- *dest++ = '\\';
- *dest++ = *psrc++;
- }
+ while (*psrc && --size > 0)
+ {
+ if (strchr(esc_chars, *psrc))
+ *dest++ = '\\';
+ *dest++ = *psrc++;
+ }
}
-const char * strncpy_tochar(char *dest, const char *src, size_t max, const char *stopchars)
+
+const char *
+strncpy_tochar(char *dest,
+ const char *src,
+ size_t max,
+ const char *stopchars)
{
- const char *psrc = src;
- char *pdest = dest;
- if (isempty(psrc)) {
- return NULL;
- }
- while (*psrc && --max > 0 && !strchr(stopchars, *psrc)) {
- *pdest = *psrc;
- pdest++;
- psrc++;
- }
- *pdest = '\0';
- return psrc +1;
+ const char *psrc = src;
+ char *pdest = dest;
+
+ if (isempty(psrc))
+ return (NULL);
+ while (*psrc && --max > 0 && !strchr(stopchars, *psrc))
+ {
+ *pdest = *psrc;
+ pdest++;
+ psrc++;
+ }
+ *pdest = '\0';
+ return (psrc + 1);
}
-size_t fwrite_or_die(const void* ptr, size_t size, size_t count, FILE* stream) {
+
+size_t
+fwrite_or_die(const void* ptr,
+ size_t size,
+ size_t count,
+ FILE* stream)
+{
size_t res = fwrite(ptr, size, count, stream);
if (ferror(stream))
rip_die(EXIT_PRNERR, "Encountered error %s during fwrite", strerror(errno));
- return res;
+ return (res);
}
-size_t fread_or_die(void* ptr, size_t size, size_t count, FILE* stream) {
+
+size_t
+fread_or_die(void* ptr,
+ size_t size,
+ size_t count,
+ FILE* stream)
+{
size_t res = fread(ptr, size, count, stream);
if (ferror(stream))
rip_die(EXIT_PRNERR, "Encountered error %s during fread", strerror(errno));
- return res;
+ return (res);
}
-int find_in_path(const char *progname, const char *paths, char *found_in)
+
+int
+find_in_path(const char *progname,
+ const char *paths,
+ char *found_in)
{
- char *pathscopy;
- char *path;
- char filepath[PATH_MAX];
+ char *pathscopy;
+ char *path;
+ char filepath[PATH_MAX];
- if (access(progname, X_OK) == 0)
- return 1;
+ if (access(progname, X_OK) == 0)
+ return (1);
- pathscopy = strdup(paths);
- for (path = strtok(pathscopy, ":"); path; path = strtok(NULL, ":")) {
- strlcpy(filepath, path, PATH_MAX);
- strlcat(filepath, "/", PATH_MAX);
- strlcat(filepath, progname, PATH_MAX);
+ pathscopy = strdup(paths);
+ for (path = strtok(pathscopy, ":"); path; path = strtok(NULL, ":"))
+ {
+ strlcpy(filepath, path, PATH_MAX);
+ strlcat(filepath, "/", PATH_MAX);
+ strlcat(filepath, progname, PATH_MAX);
- if (access(filepath, X_OK) == 0) {
- if (found_in)
- strlcpy(found_in, path, PATH_MAX);
- free(pathscopy);
- return 1;
- }
+ if (access(filepath, X_OK) == 0)
+ {
+ if (found_in)
+ strlcpy(found_in, path, PATH_MAX);
+ free(pathscopy);
+ return (1);
}
+ }
- if (found_in)
- found_in[0] = '\0';
- free(pathscopy);
- return 0;
+ if (found_in)
+ found_in[0] = '\0';
+ free(pathscopy);
+ return (0);
}
-void file_basename(char *dest, const char *path, size_t dest_size)
+
+void
+file_basename(char *dest,
+ const char *path,
+ size_t dest_size)
{
- const char *p = strrchr(path, '/');
- char *pdest = dest;
- if (!pdest)
- return;
- if (p)
- p += 1;
- else
- p = path;
- while (*p != 0 && *p != '.' && --dest_size > 0) {
- *pdest++ = *p++;
- }
- *pdest = '\0';
+ const char *p = strrchr(path, '/');
+ char *pdest = dest;
+
+ if (!pdest)
+ return;
+ if (p)
+ p += 1;
+ else
+ p = path;
+ while (*p != 0 && *p != '.' && --dest_size > 0)
+ *pdest++ = *p++;
+ *pdest = '\0';
}
-void make_absolute_path(char *path, int len)
+
+void
+make_absolute_path(char *path,
+ int len)
{
- char *tmp, *cwd;
+ char *tmp, *cwd;
- if (path[0] != '/') {
- tmp = malloc(len +1);
- strlcpy(tmp, path, len);
+ if (path[0] != '/')
+ {
+ tmp = malloc(len +1);
+ strlcpy(tmp, path, len);
- cwd = malloc(len);
- if (getcwd(cwd, len) != NULL) {
- strlcpy(path, cwd, len);
- strlcat(path, "/", len);
- strlcat(path, tmp, len);
- }
-
- free(tmp);
- free(cwd);
+ cwd = malloc(len);
+ if (getcwd(cwd, len) != NULL)
+ {
+ strlcpy(path, cwd, len);
+ strlcat(path, "/", len);
+ strlcat(path, tmp, len);
}
+
+ free(tmp);
+ free(cwd);
+ }
}
-int is_true_string(const char *str)
+
+int
+is_true_string(const char *str)
{
- return str && (!strcmp(str, "1") || !strcasecmp(str, "Yes") ||
- !strcasecmp(str, "On") || !strcasecmp(str, "True"));
+ return (str && (!strcmp(str, "1") || !strcasecmp(str, "Yes") ||
+ !strcasecmp(str, "On") || !strcasecmp(str, "True")));
}
-int is_false_string(const char *str)
+int
+is_false_string(const char *str)
{
- return str && (!strcmp(str, "0") || !strcasecmp(str, "No") ||
- !strcasecmp(str, "Off") || !strcasecmp(str, "False") ||
- !strcasecmp(str, "None"));
+ return (str && (!strcmp(str, "0") || !strcasecmp(str, "No") ||
+ !strcasecmp(str, "Off") || !strcasecmp(str, "False") ||
+ !strcasecmp(str, "None")));
}
-int digit(char c)
+int
+digit(char c)
{
- if (c >= '0' && c <= '9')
- return (int)c - (int)'0';
- return -1;
+ if (c >= '0' && c <= '9')
+ return ((int)c - (int)'0');
+ return (-1);
}
-static const char * next_token(const char *string, const char *separators)
+
+static const char *
+next_token(const char *string,
+ const char *separators)
{
- if (!string)
- return NULL;
+ if (!string)
+ return (NULL);
- while (*string && !strchr(separators, *string))
- string++;
+ while (*string && !strchr(separators, *string))
+ string++;
- while (*string && strchr(separators, *string))
- string++;
+ while (*string && strchr(separators, *string))
+ string++;
- return string;
+ return (string);
}
-static unsigned count_separators(const char *string, const char *separators)
+
+static unsigned
+count_separators(const char *string,
+ const char *separators)
{
- const char *p;
- unsigned cnt = 0;
+ const char *p;
+ unsigned cnt = 0;
- if (!string)
- return 0;
+ if (!string)
+ return (0);
- for (p = string; *p; p = next_token(p, separators))
- cnt++;
+ for (p = string; *p; p = next_token(p, separators))
+ cnt++;
- return cnt;
+ return (cnt);
}
-/*
- * Returns a zero terminated array of strings
- */
-char ** argv_split(const char *string, const char *separators, int *cntp)
+
+//
+// Returns a zero terminated array of strings
+//
+char **
+argv_split(const char *string,
+ const char *separators,
+ int *cntp)
{
- unsigned cnt;
- int i;
- char **argv;
+ unsigned cnt;
+ int i;
+ char **argv;
- if (!string)
- return NULL;
+ if (!string)
+ return (NULL);
- if ((cnt = count_separators(string, separators)) == 0)
- return NULL;
+ if ((cnt = count_separators(string, separators)) == 0)
+ return (NULL);
- argv = malloc((cnt +1) * sizeof(char *));
- argv[cnt] = NULL;
+ argv = malloc((cnt + 1) * sizeof(char *));
+ argv[cnt] = NULL;
- for (i = 0; i < cnt; i++)
- {
- size_t len = strcspn(string, separators);
- char *s;
- s = malloc(len + 1);
- strncpy(s, string, len);
- s[len] = '\0';
- argv[i] = s;
- string = next_token(string, separators);
- }
+ for (i = 0; i < cnt; i++)
+ {
+ size_t len = strcspn(string, separators);
+ char *s;
+ s = malloc(len + 1);
+ strncpy(s, string, len);
+ s[len] = '\0';
+ argv[i] = s;
+ string = next_token(string, separators);
+ }
- if (cntp)
- *cntp = cnt;
- return argv;
+ if (cntp)
+ *cntp = cnt;
+ return (argv);
}
-size_t argv_count(char **argv)
+
+size_t
+argv_count(char **argv)
{
- size_t cnt = 0;
+ size_t cnt = 0;
- if (!argv)
- return 0;
+ if (!argv)
+ return (0);
- while (*argv++)
- cnt++;
+ while (*argv++)
+ cnt++;
- return cnt;
+ return (cnt);
}
-void argv_free(char **argv)
+
+void
+argv_free(char **argv)
{
- char **p;
+ char **p;
- if (!argv)
- return;
+ if (!argv)
+ return;
- for (p = argv; *p; p++)
- free(*p);
+ for (p = argv; *p; p++)
+ free(*p);
- free(argv);
+ free(argv);
}
-int line_count(const char *str)
+
+int
+line_count(const char *str)
{
- int cnt = 0;
- while (*str) {
- if (*str == '\n')
- cnt++;
- str++;
- }
- return cnt;
+ int cnt = 0;
+ while (*str)
+ {
+ if (*str == '\n')
+ cnt++;
+ str++;
+ }
+ return (cnt);
}
-int line_start(const char *str, int line_number)
+
+int
+line_start(const char *str,
+ int line_number)
{
- const char *p = str;
- while (*p && line_number > 0) {
- if (*p == '\n')
- line_number--;
- p++;
- }
- return p - str;
-}
-
-void unhexify(char *dest, size_t size, const char *src)
-{
- char *pdest = dest;
- const char *psrc = src;
- char cstr[3];
-
- cstr[2] = '\0';
-
- while (*psrc && pdest - dest < size -1) {
- if (*psrc == '<') {
- psrc++;
- do {
- cstr[0] = *psrc++;
- cstr[1] = *psrc++;
- if (!isxdigit(cstr[0]) || !isxdigit(cstr[1])) {
- printf("Error replacing hex notation in %s!\n", src);
- break;
- }
- *pdest++ = (char)strtol(cstr, NULL, 16);
- } while (*psrc != '>');
- psrc++;
- }
- else
- *pdest++ = *psrc++;
+ const char *p = str;
+ while (*p && line_number > 0)
+ {
+ if (*p == '\n')
+ line_number--;
+ p++;
+ }
+ return (p - str);
+}
+
+
+void
+unhexify(char *dest,
+ size_t size,
+ const char *src)
+{
+ char *pdest = dest;
+ const char *psrc = src;
+ char cstr[3];
+
+ cstr[2] = '\0';
+
+ while (*psrc && pdest - dest < size -1)
+ {
+ if (*psrc == '<')
+ {
+ psrc++;
+ do
+ {
+ cstr[0] = *psrc++;
+ cstr[1] = *psrc++;
+ if (!isxdigit(cstr[0]) || !isxdigit(cstr[1]))
+ {
+ printf("Error replacing hex notation in %s!\n", src);
+ break;
+ }
+ *pdest++ = (char)strtol(cstr, NULL, 16);
+ }
+ while (*psrc != '>');
+ psrc++;
}
- *pdest = '\0';
+ else
+ *pdest++ = *psrc++;
+ }
+ *pdest = '\0';
}
-void extract_command(size_t *start, size_t *end, const char *cmdline, const char *cmd)
+
+void
+extract_command(size_t *start,
+ size_t *end,
+ const char *cmdline,
+ const char *cmd)
{
- char *copy = strdup(cmdline);
- char *tok = NULL;
- const char *delim = "|;";
+ char *copy = strdup(cmdline);
+ char *tok = NULL;
+ const char *delim = "|;";
- *start = *end = 0;
- for (tok = strtok(copy, delim); tok; tok = strtok(NULL, delim)) {
- while (*tok && isspace(*tok))
- tok++;
- if (startswith(tok, cmd)) {
- *start = tok - copy;
- *end = tok + strlen(tok) - copy;
- break;
- }
+ *start = *end = 0;
+ for (tok = strtok(copy, delim); tok; tok = strtok(NULL, delim))
+ {
+ while (*tok && isspace(*tok))
+ tok++;
+ if (startswith(tok, cmd))
+ {
+ *start = tok - copy;
+ *end = tok + strlen(tok) - copy;
+ break;
}
+ }
- free(copy);
+ free(copy);
}
-int contains_command(const char *cmdline, const char *cmd)
+
+int
+contains_command(const char *cmdline,
+ const char *cmd)
{
- size_t start = 0, end = 0;
+ size_t start = 0, end = 0;
- extract_command(&start, &end, cmdline, cmd);
- if (start == 0 && end == 0)
- return 0;
+ extract_command(&start, &end, cmdline, cmd);
+ if (start == 0 && end == 0)
+ return (0);
- return 1;
+ return (1);
}
-/*
- * Dynamic strings
- */
-dstr_t * create_dstr()
+
+//
+// Dynamic strings
+//
+
+dstr_t *
+create_dstr()
{
- dstr_t *ds = malloc(sizeof(dstr_t));
- ds->len = 0;
- ds->alloc = 32;
- ds->data = malloc(ds->alloc);
- ds->data[0] = '\0';
- return ds;
+ dstr_t *ds = malloc(sizeof(dstr_t));
+ ds->len = 0;
+ ds->alloc = 32;
+ ds->data = malloc(ds->alloc);
+ ds->data[0] = '\0';
+ return (ds);
}
-void free_dstr(dstr_t *ds)
+
+void
+free_dstr(dstr_t *ds)
{
- free(ds->data);
- free(ds);
+ free(ds->data);
+ free(ds);
}
-void dstrclear(dstr_t *ds)
+
+void
+dstrclear(dstr_t *ds)
{
- ds->len = 0;
- ds->data[0] = '\0';
+ ds->len = 0;
+ ds->data[0] = '\0';
}
-void dstrassure(dstr_t *ds, size_t alloc)
+
+void
+dstrassure(dstr_t *ds,
+ size_t alloc)
{
- if (ds->alloc < alloc) {
- ds->alloc = alloc;
- ds->data = realloc(ds->data, ds->alloc);
- }
+ if (ds->alloc < alloc)
+ {
+ ds->alloc = alloc;
+ ds->data = realloc(ds->data, ds->alloc);
+ }
}
-void dstrcpy(dstr_t *ds, const char *src)
+
+void
+dstrcpy(dstr_t *ds,
+ const char *src)
{
- size_t srclen;
+ size_t srclen;
- if (!src) {
- ds->len = 0;
- ds->data[0] = '\0';
- return;
- }
+ if (!src)
+ {
+ ds->len = 0;
+ ds->data[0] = '\0';
+ return;
+ }
- srclen = strlen(src);
+ srclen = strlen(src);
- if (srclen >= ds->alloc) {
- do {
- ds->alloc *= 2;
- } while (srclen >= ds->alloc);
- ds->data = realloc(ds->data, ds->alloc);
+ if (srclen >= ds->alloc)
+ {
+ do
+ {
+ ds->alloc *= 2;
}
+ while (srclen >= ds->alloc);
+ ds->data = realloc(ds->data, ds->alloc);
+ }
- strcpy(ds->data, src);
- ds->len = srclen;
+ strcpy(ds->data, src);
+ ds->len = srclen;
}
-void dstrncpy(dstr_t *ds, const char *src, size_t n)
+
+void
+dstrncpy(dstr_t *ds,
+ const char *src,
+ size_t n)
{
- if (n >= ds->alloc) {
- do {
- ds->alloc *= 2;
- } while (n >= ds->alloc);
- ds->data = realloc(ds->data, ds->alloc);
+ if (n >= ds->alloc)
+ {
+ do
+ {
+ ds->alloc *= 2;
}
+ while (n >= ds->alloc);
+ ds->data = realloc(ds->data, ds->alloc);
+ }
- strncpy(ds->data, src, n);
- ds->len = n;
- ds->data[ds->len] = '\0';
+ strncpy(ds->data, src, n);
+ ds->len = n;
+ ds->data[ds->len] = '\0';
}
-void dstrncat(dstr_t *ds, const char *src, size_t n)
+
+void
+dstrncat(dstr_t *ds,
+ const char *src,
+ size_t n)
{
- size_t needed = ds->len + n;
+ size_t needed = ds->len + n;
- if (needed >= ds->alloc) {
- do {
- ds->alloc *= 2;
- } while (needed >= ds->alloc);
- ds->data = realloc(ds->data, ds->alloc);
+ if (needed >= ds->alloc)
+ {
+ do
+ {
+ ds->alloc *= 2;
}
+ while (needed >= ds->alloc);
+ ds->data = realloc(ds->data, ds->alloc);
+ }
- strncpy(&ds->data[ds->len], src, n);
- ds->len = needed;
- ds->data[ds->len] = '\0';
+ strncpy(&ds->data[ds->len], src, n);
+ ds->len = needed;
+ ds->data[ds->len] = '\0';
}
-void dstrcpyf(dstr_t *ds, const char *src, ...)
-{
- va_list ap;
- size_t srclen;
- va_start(ap, src);
- srclen = vsnprintf(ds->data, ds->alloc, src, ap);
- va_end(ap);
+void
+dstrcpyf(dstr_t *ds,
+ const char *src,
+ ...)
+{
+ va_list ap;
+ size_t srclen;
- if (srclen >= ds->alloc) {
- do {
- ds->alloc *= 2;
- } while (srclen >= ds->alloc);
- ds->data = realloc(ds->data, ds->alloc);
+ va_start(ap, src);
+ srclen = vsnprintf(ds->data, ds->alloc, src, ap);
+ va_end(ap);
- va_start(ap, src);
- vsnprintf(ds->data, ds->alloc, src, ap);
- va_end(ap);
+ if (srclen >= ds->alloc)
+ {
+ do
+ {
+ ds->alloc *= 2;
}
+ while (srclen >= ds->alloc);
+ ds->data = realloc(ds->data, ds->alloc);
+
+ va_start(ap, src);
+ vsnprintf(ds->data, ds->alloc, src, ap);
+ va_end(ap);
+ }
- ds->len = srclen;
+ ds->len = srclen;
}
-void dstrputc(dstr_t *ds, int c)
+
+void
+dstrputc(dstr_t *ds,
+ int c)
{
- if (ds->len +1 >= ds->alloc) {
- ds->alloc *= 2;
- ds->data = realloc(ds->data, ds->alloc);
- }
- ds->data[ds->len++] = c;
- ds->data[ds->len] = '\0';
+ if (ds->len +1 >= ds->alloc)
+ {
+ ds->alloc *= 2;
+ ds->data = realloc(ds->data, ds->alloc);
+ }
+ ds->data[ds->len++] = c;
+ ds->data[ds->len] = '\0';
}
-void dstrcat(dstr_t *ds, const char *src)
+
+void
+dstrcat(dstr_t *ds,
+ const char *src)
{
- size_t srclen = strlen(src);
- size_t newlen = ds->len + srclen;
+ size_t srclen = strlen(src);
+ size_t newlen = ds->len + srclen;
- if (newlen >= ds->alloc) {
- do {
- ds->alloc *= 2;
- } while (newlen >= ds->alloc);
- ds->data = realloc(ds->data, ds->alloc);
+ if (newlen >= ds->alloc)
+ {
+ do
+ {
+ ds->alloc *= 2;
}
+ while (newlen >= ds->alloc);
+ ds->data = realloc(ds->data, ds->alloc);
+ }
- memcpy(&ds->data[ds->len], src, srclen +1);
- ds->len = newlen;
+ memcpy(&ds->data[ds->len], src, srclen +1);
+ ds->len = newlen;
}
-void dstrcatf(dstr_t *ds, const char *src, ...)
+
+void
+dstrcatf(dstr_t *ds,
+ const char *src,
+ ...)
{
- va_list ap;
- size_t restlen = ds->alloc - ds->len;
- size_t srclen;
+ va_list ap;
+ size_t restlen = ds->alloc - ds->len;
+ size_t srclen;
+
+ va_start(ap, src);
+ srclen = vsnprintf(&ds->data[ds->len], restlen, src, ap);
+ va_end(ap);
+
+ if (srclen >= restlen)
+ {
+ do
+ {
+ ds->alloc *= 2;
+ restlen = ds->alloc - ds->len;
+ }
+ while (srclen >= restlen);
+ ds->data = realloc(ds->data, ds->alloc);
va_start(ap, src);
srclen = vsnprintf(&ds->data[ds->len], restlen, src, ap);
va_end(ap);
+ }
- if (srclen >= restlen) {
- do {
- ds->alloc *= 2;
- restlen = ds->alloc - ds->len;
- } while (srclen >= restlen);
- ds->data = realloc(ds->data, ds->alloc);
-
- va_start(ap, src);
- srclen = vsnprintf(&ds->data[ds->len], restlen, src, ap);
- va_end(ap);
- }
-
- ds->len += srclen;
+ ds->len += srclen;
}
-size_t fgetdstr(dstr_t *ds, FILE *stream)
+
+size_t
+fgetdstr(dstr_t *ds,
+ FILE *stream)
{
- int c;
- size_t cnt = 0;
+ int c;
+ size_t cnt = 0;
- ds->len = 0;
- if (ds->alloc == 0) {
- ds->alloc = 256;
- ds->data = malloc(ds->alloc);
- }
+ ds->len = 0;
+ if (ds->alloc == 0)
+ {
+ ds->alloc = 256;
+ ds->data = malloc(ds->alloc);
+ }
- while ((c = fgetc(stream)) != EOF) {
- if (ds->len +1 == ds->alloc) {
- ds->alloc *= 2;
- ds->data = realloc(ds->data, ds->alloc);
- }
- ds->data[ds->len++] = (char)c;
- cnt ++;
- if (c == '\n')
- break;
+ while ((c = fgetc(stream)) != EOF)
+ {
+ if (ds->len +1 == ds->alloc)
+ {
+ ds->alloc *= 2;
+ ds->data = realloc(ds->data, ds->alloc);
}
- ds->data[ds->len] = '\0';
- return cnt;
+ ds->data[ds->len++] = (char)c;
+ cnt ++;
+ if (c == '\n')
+ break;
+ }
+ ds->data[ds->len] = '\0';
+ return (cnt);
}
-/*
- * Replace the first occurrence of 'find' after the index 'start' with 'repl'
- * Returns the position right after the replaced string
- */
-int dstrreplace(dstr_t *ds, const char *find, const char *repl, int start)
+
+//
+// Replace the first occurrence of 'find' after the index 'start' with 'repl'
+// Returns the position right after the replaced string
+//
+
+int
+dstrreplace(dstr_t *ds,
+ const char *find,
+ const char *repl,
+ int start)
{
- char *p;
- dstr_t *copy = create_dstr();
- int end = -1;
+ char *p;
+ dstr_t *copy = create_dstr();
+ int end = -1;
- dstrcpy(copy, ds->data);
+ dstrcpy(copy, ds->data);
- if ((p = strstr(©->data[start], find)))
- {
- dstrncpy(ds, copy->data, p - copy->data);
- dstrcatf(ds, "%s", repl);
- end = ds->len;
- dstrcatf(ds, "%s", p + strlen(find));
- }
+ if ((p = strstr(©->data[start], find)))
+ {
+ dstrncpy(ds, copy->data, p - copy->data);
+ dstrcatf(ds, "%s", repl);
+ end = ds->len;
+ dstrcatf(ds, "%s", p + strlen(find));
+ }
- free_dstr(copy);
- return end;
+ free_dstr(copy);
+ return (end);
}
-void dstrprepend(dstr_t *ds, const char *str)
+
+void
+dstrprepend(dstr_t *ds,
+ const char *str)
{
- dstr_t *copy = create_dstr();
- dstrcpy(copy, ds->data);
- dstrcpy(ds, str);
- dstrcatf(ds, "%s", copy->data);
- free_dstr(copy);
+ dstr_t *copy = create_dstr();
+ dstrcpy(copy, ds->data);
+ dstrcpy(ds, str);
+ dstrcatf(ds, "%s", copy->data);
+ free_dstr(copy);
}
-void dstrinsert(dstr_t *ds, int idx, const char *str)
+
+void
+dstrinsert(dstr_t *ds,
+ int idx,
+ const char *str)
{
- char * copy = strdup(ds->data);
- size_t len = strlen(str);
+ char * copy = strdup(ds->data);
+ size_t len = strlen(str);
- if (idx >= ds->len)
- idx = ds->len;
- else if (idx < 0)
- idx = 0;
+ if (idx >= ds->len)
+ idx = ds->len;
+ else if (idx < 0)
+ idx = 0;
- if (ds->len + len >= ds->alloc) {
- do {
- ds->alloc *= 2;
- } while (ds->len + len >= ds->alloc);
- free(ds->data);
- ds->data = malloc(ds->alloc);
+ if (ds->len + len >= ds->alloc)
+ {
+ do
+ {
+ ds->alloc *= 2;
}
+ while (ds->len + len >= ds->alloc);
+ free(ds->data);
+ ds->data = malloc(ds->alloc);
+ }
- strncpy(ds->data, copy, idx);
- ds->data[idx] = '\0';
- strcat(ds->data, str);
- strcat(ds->data, ©[idx]);
- ds->len += len;
- free(copy);
+ strncpy(ds->data, copy, idx);
+ ds->data[idx] = '\0';
+ strcat(ds->data, str);
+ strcat(ds->data, ©[idx]);
+ ds->len += len;
+ free(copy);
}
-void dstrinsertf(dstr_t *ds, int idx, const char *str, ...)
+
+void
+dstrinsertf(dstr_t *ds,
+ int idx,
+ const char *str,
+ ...)
{
- va_list ap;
- char *strf;
- size_t len;
+ va_list ap;
+ char *strf;
+ size_t len;
- va_start(ap, str);
- len = vsnprintf(NULL, 0, str, ap);
- va_end(ap);
+ va_start(ap, str);
+ len = vsnprintf(NULL, 0, str, ap);
+ va_end(ap);
- strf = malloc(len +1);
- va_start(ap, str);
- vsnprintf(strf, len +1, str, ap);
- va_end(ap);
+ strf = malloc(len +1);
+ va_start(ap, str);
+ vsnprintf(strf, len +1, str, ap);
+ va_end(ap);
- dstrinsert(ds, idx, strf);
+ dstrinsert(ds, idx, strf);
- free(strf);
+ free(strf);
}
-void dstrremove(dstr_t *ds, int idx, size_t count)
+
+void
+dstrremove(dstr_t *ds,
+ int idx,
+ size_t count)
{
- char *p1, *p2;
+ char *p1, *p2;
- if (idx + count >= ds->len)
- return;
+ if (idx + count >= ds->len)
+ return;
- p1 = &ds->data[idx];
- p2 = &ds->data[idx + count];
+ p1 = &ds->data[idx];
+ p2 = &ds->data[idx + count];
- while (*p2) {
- *p1 = *p2;
- p1++;
- p2++;
- }
- *p1 = '\0';
+ while (*p2)
+ {
+ *p1 = *p2;
+ p1++;
+ p2++;
+ }
+ *p1 = '\0';
}
-static inline int isnewline(int c)
+
+static inline int
+isnewline(int c)
{
- return c == '\n' || c == '\r';
+ return (c == '\n' || c == '\r');
}
-void dstrcatline(dstr_t *ds, const char *str)
+
+void
+dstrcatline(dstr_t *ds,
+ const char *str)
{
- size_t eol = strcspn(str, "\n\r");
- if (isnewline(str[eol]))
- eol++;
- dstrncat(ds, str, eol);
+ size_t eol = strcspn(str, "\n\r");
+ if (isnewline(str[eol]))
+ eol++;
+ dstrncat(ds, str, eol);
}
-int dstrendswith(dstr_t *ds, const char *str)
-{
- int len = strlen(str);
- char *pstr;
- if (ds->len < len)
- return 0;
- pstr = &ds->data[ds->len - len];
- return strcmp(pstr, str) == 0;
+int
+dstrendswith(dstr_t *ds,
+ const char *str)
+{
+ int len = strlen(str);
+ char *pstr;
+ if (ds->len < len)
+ return (0);
+ pstr = &ds->data[ds->len - len];
+ return (strcmp(pstr, str) == 0);
}
-void dstrfixnewlines(dstr_t *ds)
+
+void
+dstrfixnewlines(dstr_t *ds)
{
- if (ds->data[ds->len -1] == '\r') {
- ds->data[ds->len -1] = '\n';
- }
- else if (ds->data[ds->len -2] == '\r') {
- ds->data[ds->len -1] = '\n';
- ds->data[ds->len -2] = '\0';
- ds->len -= 1;
- }
+ if (ds->data[ds->len -1] == '\r')
+ ds->data[ds->len -1] = '\n';
+ else if (ds->data[ds->len -2] == '\r')
+ {
+ ds->data[ds->len -1] = '\n';
+ ds->data[ds->len -2] = '\0';
+ ds->len -= 1;
+ }
}
-void dstrremovenewline(dstr_t *ds)
+
+void
+dstrremovenewline(dstr_t *ds)
{
- if (!ds->len)
- return;
+ if (!ds->len)
+ return;
- if (ds->data[ds->len -1] == '\r' || ds->data[ds->len -1] == '\n') {
- ds->data[ds->len -1] = '\0';
- ds->len -= 1;
- }
+ if (ds->data[ds->len -1] == '\r' || ds->data[ds->len -1] == '\n')
+ {
+ ds->data[ds->len -1] = '\0';
+ ds->len -= 1;
+ }
- if (ds->len < 2)
- return;
+ if (ds->len < 2)
+ return;
- if (ds->data[ds->len -2] == '\r') {
- ds->data[ds->len -2] = '\0';
- ds->len -= 2;
- }
+ if (ds->data[ds->len -2] == '\r')
+ {
+ ds->data[ds->len -2] = '\0';
+ ds->len -= 2;
+ }
}
-void dstrtrim(dstr_t *ds)
+
+void
+dstrtrim(dstr_t *ds)
{
- int pos = 0;
+ int pos = 0;
- while (pos < ds->len && isspace(ds->data[pos]))
- pos++;
+ while (pos < ds->len && isspace(ds->data[pos]))
+ pos++;
- if (pos > 0) {
- ds->len -= pos;
- memmove(ds->data, &ds->data[pos], ds->len +1);
- }
+ if (pos > 0)
+ {
+ ds->len -= pos;
+ memmove(ds->data, &ds->data[pos], ds->len +1);
+ }
}
-void dstrtrim_right(dstr_t *ds)
+
+void
+dstrtrim_right(dstr_t *ds)
{
- if (!ds->len)
- return;
+ if (!ds->len)
+ return;
- while (isspace(ds->data[ds->len -1]))
- ds->len -= 1;
- ds->data[ds->len] = '\0';
+ while (isspace(ds->data[ds->len - 1]))
+ ds->len -= 1;
+ ds->data[ds->len] = '\0';
}
+//
+// LIST
+//
-/*
- * LIST
- */
-
-list_t * list_create()
+list_t *
+list_create()
{
- list_t *l = malloc(sizeof(list_t));
- l->first = NULL;
- l->last = NULL;
- return l;
+ list_t *l = malloc(sizeof(list_t));
+ l->first = NULL;
+ l->last = NULL;
+ return (l);
}
-list_t * list_create_from_array(int count, void ** data)
+
+list_t *
+list_create_from_array(int count,
+ void ** data)
{
- int i;
- list_t *l = list_create();
+ int i;
+ list_t *l = list_create();
- for (i = 0; i < count; i++)
- list_append(l, data[i]);
+ for (i = 0; i < count; i++)
+ list_append(l, data[i]);
- return l;
+ return (l);
}
-void list_free(list_t *list)
+
+void
+list_free(list_t *list)
{
- listitem_t *i = list->first, *tmp;
- while (i) {
- tmp = i->next;
- free(i);
- i = tmp;
- }
+ listitem_t *i = list->first, *tmp;
+ while (i)
+ {
+ tmp = i->next;
+ free(i);
+ i = tmp;
+ }
}
-size_t list_item_count(list_t *list)
+
+size_t
+list_item_count(list_t *list)
{
- size_t cnt = 0;
- listitem_t *i;
- for (i = list->first; i; i = i->next)
- cnt++;
- return cnt;
+ size_t cnt = 0;
+ listitem_t *i;
+ for (i = list->first; i; i = i->next)
+ cnt++;
+ return (cnt);
}
-list_t * list_copy(list_t *list)
+
+list_t *
+list_copy(list_t *list)
{
- list_t *l = list_create();
- listitem_t *i;
+ list_t *l = list_create();
+ listitem_t *i;
- for (i = list->first; i; i = i->next)
- list_append(l, i->data);
- return l;
+ for (i = list->first; i; i = i->next)
+ list_append(l, i->data);
+ return (l);
}
-void list_prepend(list_t *list, void *data)
+
+void
+list_prepend(list_t *list,
+ void *data)
{
- listitem_t *item;
+ listitem_t *item;
- if (!list)
- return;
+ if (!list)
+ return;
- item = malloc(sizeof(listitem_t));
- item->data = data;
- item->prev = NULL;
+ item = malloc(sizeof(listitem_t));
+ item->data = data;
+ item->prev = NULL;
- if (list->first) {
- item->next = list->first;
- list->first->next = item;
- list->first = item;
- }
- else {
- item->next = NULL;
- list->first = item;
- list->last = item;
- }
+ if (list->first)
+ {
+ item->next = list->first;
+ list->first->next = item;
+ list->first = item;
+ }
+ else
+ {
+ item->next = NULL;
+ list->first = item;
+ list->last = item;
+ }
}
+
void list_append(list_t *list, void *data)
{
- listitem_t *item;
+ listitem_t *item;
- if (!list)
- return;
+ if (!list)
+ return;
- item = malloc(sizeof(listitem_t));
- item->data = data;
- item->next = NULL;
+ item = malloc(sizeof(listitem_t));
+ item->data = data;
+ item->next = NULL;
- if (list->last) {
- item->prev = list->last;
- list->last->next = item;
- list->last = item;
- }
- else {
- item->prev = NULL;
- list->first = item;
- list->last = item;
- }
+ if (list->last)
+ {
+ item->prev = list->last;
+ list->last->next = item;
+ list->last = item;
+ }
+ else
+ {
+ item->prev = NULL;
+ list->first = item;
+ list->last = item;
+ }
}
-void list_remove(list_t *list, listitem_t *item)
+
+void
+list_remove(list_t *list,
+ listitem_t *item)
{
- if (!list || !item)
- return;
+ if (!list || !item)
+ return;
- if (item->prev)
- item->prev->next = item->next;
- if (item->next)
- item->next->prev = item->prev;
- if (item == list->first)
- list->first = item->next;
- if (item == list->last)
- list->last = item->prev;
+ if (item->prev)
+ item->prev->next = item->next;
+ if (item->next)
+ item->next->prev = item->prev;
+ if (item == list->first)
+ list->first = item->next;
+ if (item == list->last)
+ list->last = item->prev;
- free(item);
+ free(item);
}
-listitem_t * list_get(list_t *list, int idx)
+
+listitem_t *
+list_get(list_t *list,
+ int idx)
{
- listitem_t *i;
- for (i = list->first; i && idx; i = i->next)
- idx--;
- return i;
+ listitem_t *i;
+ for (i = list->first; i && idx; i = i->next)
+ idx--;
+ return (i);
}
-listitem_t * arglist_find(list_t *list, const char *name)
+
+listitem_t *
+arglist_find(list_t *list,
+ const char *name)
{
- listitem_t *i;
- for (i = list->first; i; i = i->next) {
- if (!strcmp((const char*)i->data, name))
- return i;
- }
- return NULL;
+ listitem_t *i;
+ for (i = list->first; i; i = i->next)
+ {
+ if (!strcmp((const char*)i->data, name))
+ return (i);
+ }
+ return (NULL);
}
-listitem_t * arglist_find_prefix(list_t *list, const char *name)
+
+listitem_t *
+arglist_find_prefix(list_t *list,
+ const char *name)
{
- listitem_t *i;
- for (i = list->first; i; i= i->next) {
- if (!prefixcmp((const char*)i->data, name))
- return i;
- }
- return NULL;
+ listitem_t *i;
+ for (i = list->first; i; i= i->next)
+ {
+ if (!prefixcmp((const char*)i->data, name))
+ return (i);
+ }
+ return (NULL);
}
-char * arglist_get_value(list_t *list, const char *name)
+char *
+arglist_get_value(list_t *list,
+ const char *name)
{
- listitem_t *i;
- char *p;
+ listitem_t *i;
+ char *p;
- for (i = list->first; i; i = i->next) {
- if (i->next && !strcmp(name, (char*)i->data))
- return (char*)i->next->data;
- else if (!prefixcmp((char*)i->data, name)) {
- p = &((char*)i->data)[strlen(name)];
- return *p == '=' ? p +1 : p;
- }
+ for (i = list->first; i; i = i->next)
+ {
+ if (i->next && !strcmp(name, (char*)i->data))
+ return ((char*)i->next->data);
+ else if (!prefixcmp((char*)i->data, name))
+ {
+ p = &((char*)i->data)[strlen(name)];
+ return (*p == '=' ? p +1 : p);
}
- return NULL;
+ }
+ return (NULL);
}
-char * arglist_get(list_t *list, int idx)
+
+char *
+arglist_get(list_t *list,
+ int idx)
{
- listitem_t *i = list_get(list, idx);
- return i ? (char*)i->data : NULL;
+ listitem_t *i = list_get(list, idx);
+ return (i ? (char*)i->data : NULL);
}
-int arglist_remove(list_t *list, const char *name)
+
+int
+arglist_remove(list_t *list,
+ const char *name)
{
- listitem_t *i;
- char *i_name;
+ listitem_t *i;
+ char *i_name;
- for (i = list->first; i; i = i->next) {
- i_name = (char*)i->data;
- if (i->next && !strcmp(name, i_name)) {
- list_remove(list, i->next);
- list_remove(list, i);
- return 1;
- }
- else if (!prefixcmp(i_name, name)) {
- list_remove(list, i);
- return 1;
- }
+ for (i = list->first; i; i = i->next)
+ {
+ i_name = (char*)i->data;
+ if (i->next && !strcmp(name, i_name))
+ {
+ list_remove(list, i->next);
+ list_remove(list, i);
+ return (1);
}
- return 0;
+ else if (!prefixcmp(i_name, name))
+ {
+ list_remove(list, i);
+ return (1);
+ }
+ }
+ return (0);
}
-int arglist_remove_flag(list_t *list, const char *name)
+
+int
+arglist_remove_flag(list_t *list,
+ const char *name)
{
- listitem_t *i = arglist_find(list, name);
- if (i) {
- list_remove(list, i);
- return 1;
- }
- return 0;
+ listitem_t *i = arglist_find(list, name);
+
+ if (i)
+ {
+ list_remove(list, i);
+ return (1);
+ }
+ return (0);
}
-int copy_file(FILE *dest,
- FILE *src,
- const char *alreadyread,
- size_t alreadyread_len)
+
+int
+copy_file(FILE *dest,
+ FILE *src,
+ const char *alreadyread,
+ size_t alreadyread_len)
{
- char buf[8192];
- size_t bytes;
+ char buf[8192];
+ size_t bytes;
- if (alreadyread && alreadyread_len)
+ if (alreadyread && alreadyread_len)
+ {
+ if (fwrite_or_die(alreadyread, 1, alreadyread_len, dest) < alreadyread_len)
{
- if (fwrite_or_die(alreadyread, 1, alreadyread_len, dest) < alreadyread_len)
- {
- _log("Could not write to temp file\n");
- return 0;
- }
+ _log("Could not write to temp file\n");
+ return 0;
}
+ }
- while ((bytes = fread_or_die(buf, 1, 8192, src)))
- fwrite_or_die(buf, 1, bytes, dest);
+ while ((bytes = fread_or_die(buf, 1, 8192, src)))
+ fwrite_or_die(buf, 1, bytes, dest);
- return !ferror(src) && !ferror(dest);
+ return (!ferror(src) && !ferror(dest));
}
-
-/* util.h
- *
- * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
- * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
- *
- * This file is part of foomatic-rip.
- *
- * Foomatic-rip 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.
- *
- * Foomatic-rip 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
+//
+// util.h
+//
+// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
+//
+// This file is part of foomatic-rip.
+//
+// Foomatic-rip 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.
+//
+// Foomatic-rip 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 Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
#ifndef util_h
#define util_h
void strlower(char *dest, size_t destlen, const char *src);
-/*
- * Like strncpy, but omits characters for which omit_func returns true
- * It also assures that dest is zero terminated.
- * Returns a pointer to the position in 'src' right after the last byte that has been copied.
- */
+// Like strncpy, but omits characters for which omit_func returns true
+// It also assures that dest is zero terminated.
+// Returns a pointer to the position in 'src' right after the last byte that
+// has been copied.
const char * strncpy_omit(char* dest, const char* src, size_t n, int (*omit_func)(int));
int omit_unprintables(int c);
int omit_whitespace_newline(int c);
#ifndef HAVE_STRCASESTR
-/* strcasestr() is not available under Solaris */
+// strcasestr() is not available under Solaris
char * strcasestr (const char *haystack, const char *needle);
#endif
-/* TODO check for platforms which already have strlcpy and strlcat */
+// TODO check for platforms which already have strlcpy and strlcat
-/* Copy at most size-1 characters from src to dest
- dest will always be \0 terminated (unless size == 0)
- returns strlen(src) */
+// Copy at most size - 1 characters from src to dest
+// dest will always be \0 terminated (unless size == 0)
+// returns strlen(src)
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dest, const char *src, size_t size);
-#endif /* ! HAVE_STRLCPY */
+#endif // ! HAVE_STRLCPY
#ifndef HAVE_STRLCAT
size_t strlcat(char *dest, const char *src, size_t size);
-#endif /* ! HAVE_STRLCAT */
+#endif // ! HAVE_STRLCAT
-/* Replace all occurences of each of the characters in 'chars' by 'repl' */
+// Replace all occurences of each of the characters in 'chars' by 'repl'
void strrepl(char *str, const char *chars, char repl);
-/* Replace all occurences of each of the characters in 'chars' by 'repl',
- but do not allow consecutive 'repl' chars */
+// Replace all occurences of each of the characters in 'chars' by 'repl',
+// but do not allow consecutive 'repl' chars
void strrepl_nodups(char *str, const char *chars, char repl);
-/* clears 'str' with \0s */
+// clears 'str' with \0s
void strclr(char *str);
-char * strnchr(const char *str, int c, size_t n);
+char *strnchr(const char *str, int c, size_t n);
-void escapechars(char *dest, size_t size, const char *src, const char *esc_chars);
+void escapechars(char *dest, size_t size, const char *src,
+ const char *esc_chars);
-/* copies characters from 'src' to 'dest', until 'src' contains a character from 'stopchars'
- will not copy more than 'max' chars
- dest will be zero terminated in either case
- returns a pointer to the position right after the last byte that has been copied
-*/
-const char * strncpy_tochar(char *dest, const char *src, size_t max, const char *stopchars);
+// copies characters from 'src' to 'dest', until 'src' contains a character
+//from 'stopchars'
+// - will not copy more than 'max' chars
+// - dest will be zero terminated in either case
+// - returns a pointer to the position right after the last byte that has been
+// copied
+const char *strncpy_tochar(char *dest, const char *src, size_t max,
+ const char *stopchars);
-/* "safe" versions of standard <cstdio> fwrite and fread that will cause the
- * program to exit gracefully when a write/read fails */
+// "safe" versions of standard <cstdio> fwrite and fread that will cause the
+// program to exit gracefully when a write/read fails
size_t fwrite_or_die(const void* ptr, size_t size, size_t count, FILE* stream);
size_t fread_or_die(void* ptr, size_t size, size_t count, FILE* stream);
-/* 'paths' is a colon seperated list of paths (like $PATH)
- * 'found_in' may be NULL if it is not needed */
+// 'paths' is a colon seperated list of paths (like $PATH)
+// 'found_in' may be NULL if it is not needed
int find_in_path(const char *progname, const char *paths, char *found_in);
-/* extracts the base name of 'path', i.e. only the filename, without path or extension */
+// extracts the base name of 'path', i.e. only the filename, without path or
+// extension
void file_basename(char *dest, const char *path, size_t dest_size);
-/* if 'path' is relative, prepend cwd */
+// if 'path' is relative, prepend cwd
void make_absolute_path(char *path, int len);
-int is_true_string(const char *str); /* "1", "Yes", "On", "True" */
-int is_false_string(const char *str); /* "0", "No", "Off", "False", "None" */
+int is_true_string(const char *str); // "1", "Yes", "On", "True"
+int is_false_string(const char *str); // "0", "No", "Off", "False", "None"
-int digit(char c); /* returns 0-9 if c is a digit, otherwise -1 */
+int digit(char c); // returns 0-9 if c is a digit, otherwise -1
int line_count(const char *str);
-/* returns the index of the beginning of the line_number'th line in str */
+// returns the index of the beginning of the line_number'th line in str
int line_start(const char *str, int line_number);
-/* Replace hex notation for unprintable characters in PPD files
- by the actual characters ex: "<0A>" --> chr(hex("0A")) */
+// Replace hex notation for unprintable characters in PPD files
+// by the actual characters ex: "<0A>" --> chr(hex("0A"))
void unhexify(char *dest, size_t size, const char *src);
-void extract_command(size_t *start, size_t *end, const char *cmdline, const char *cmd);
+void extract_command(size_t *start, size_t *end, const char *cmdline,
+ const char *cmd);
-char ** argv_split(const char *string, const char *separators, int *cntp);
+char **argv_split(const char *string, const char *separators, int *cntp);
size_t argv_count(char **argv);
void argv_free(char **argv);
-/*
- * Returns non-zero if 'cmdline' calls 'cmd' in some way
- */
+// Returns non-zero if 'cmdline' calls 'cmd' in some way
int contains_command(const char *cmdline, const char *cmd);
-int copy_file(FILE *dest, FILE *src, const char *alreadyread, size_t alreadyread_len);
+int copy_file(FILE *dest, FILE *src, const char *alreadyread,
+ size_t alreadyread_len);
-/* Dynamic string */
-typedef struct dstr {
- char *data;
- size_t len;
- size_t alloc;
+// Dynamic string
+typedef struct dstr
+{
+ char *data;
+ size_t len;
+ size_t alloc;
} dstr_t;
dstr_t * create_dstr();
void dstrcat(dstr_t *ds, const char *src);
void dstrcatf(dstr_t *ds, const char *src, ...);
void dstrputc(dstr_t *ds, int c);
-size_t fgetdstr(dstr_t *ds, FILE *stream); /* returns number of characters read */
+size_t fgetdstr(dstr_t *ds, FILE *stream); // returns number of characters read
int dstrreplace(dstr_t *ds, const char *find, const char *repl, int start);
void dstrprepend(dstr_t *ds, const char *str);
void dstrinsert(dstr_t *ds, int idx, const char *str);
void dstrinsertf(dstr_t *ds, int idx, const char *str, ...);
void dstrremove(dstr_t *ds, int idx, size_t count);
-void dstrcatline(dstr_t *ds, const char *str); /* appends the first line from str to ds (incl. \n) */
+void dstrcatline(dstr_t *ds, const char *str);
+ // appends the first line from str to ds (incl. \n)
int dstrendswith(dstr_t *ds, const char *str);
void dstrfixnewlines(dstr_t *ds);
void dstrtrim(dstr_t *ds);
void dstrtrim_right(dstr_t *ds);
-
-/* Doubly linked list of void pointers */
-typedef struct listitem_s {
- void *data;
- struct listitem_s *prev, *next;
+// Doubly linked list of void pointers
+typedef struct listitem_s
+{
+ void *data;
+ struct listitem_s *prev, *next;
} listitem_t;
-typedef struct {
- listitem_t *first, *last;
+typedef struct
+{
+ listitem_t *first, *last;
} list_t;
list_t * list_create();
-list_t * list_create_from_array(int count, void ** data); /* array values are NOT copied */
+list_t * list_create_from_array(int count, void ** data);
+ // array values are NOT copied
void list_free(list_t *list);
size_t list_item_count(list_t *list);
listitem_t * list_get(list_t *list, int idx);
+// Argument values may be seperated from their keys in the following ways:
+// - with whitespace (i.e. it is in the next list entry)
+// - with a '='
+// - not at all
-/* Argument values may be seperated from their keys in the following ways:
- - with whitespace (i.e. it is in the next list entry)
- - with a '='
- - not at all
-*/
listitem_t * arglist_find(list_t *list, const char *name);
listitem_t * arglist_find_prefix(list_t *list, const char *name);
int arglist_remove(list_t *list, const char *name);
int arglist_remove_flag(list_t *list, const char *name);
-#endif
-
+#endif // !util_h