|
|
a996cb |
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
|
|
|
a996cb |
index e393931..e1f2d18 100644
|
|
|
a996cb |
--- a/converter/other/pnmtops.c
|
|
|
a996cb |
+++ b/converter/other/pnmtops.c
|
|
|
a996cb |
@@ -42,6 +42,8 @@
|
|
|
a996cb |
#include <unistd.h>
|
|
|
a996cb |
#include <assert.h>
|
|
|
a996cb |
#include <string.h>
|
|
|
a996cb |
+#include <errno.h>
|
|
|
a996cb |
+#include <signal.h>
|
|
|
a996cb |
#ifndef NOFLATE
|
|
|
a996cb |
#include <zlib.h>
|
|
|
a996cb |
#endif
|
|
|
a996cb |
@@ -52,6 +54,37 @@
|
|
|
a996cb |
#include "shhopt.h"
|
|
|
a996cb |
#include "nstring.h"
|
|
|
a996cb |
|
|
|
a996cb |
+
|
|
|
a996cb |
+
|
|
|
a996cb |
+static void
|
|
|
a996cb |
+setSignals() {
|
|
|
a996cb |
+/*----------------------------------------------------------------------------
|
|
|
a996cb |
+ Set up the process-global signal-related state.
|
|
|
a996cb |
+
|
|
|
a996cb |
+ Note that we can't rely on defaults, because much of this is inherited
|
|
|
a996cb |
+ from the process that forked and exec'ed this program.
|
|
|
a996cb |
+-----------------------------------------------------------------------------*/
|
|
|
a996cb |
+ /* See waitForChildren() for why we do this to SIGCHLD */
|
|
|
a996cb |
+
|
|
|
a996cb |
+ struct sigaction sigchldAction;
|
|
|
a996cb |
+ int rc;
|
|
|
a996cb |
+ sigset_t emptySet;
|
|
|
a996cb |
+
|
|
|
a996cb |
+ sigemptyset(&emptySet);
|
|
|
a996cb |
+
|
|
|
a996cb |
+ sigchldAction.sa_handler = SIG_DFL;
|
|
|
a996cb |
+ sigchldAction.sa_mask = emptySet;
|
|
|
a996cb |
+ sigchldAction.sa_flags = SA_NOCLDSTOP;
|
|
|
a996cb |
+
|
|
|
a996cb |
+ rc = sigaction(SIGCHLD, &sigchldAction, NULL);
|
|
|
a996cb |
+
|
|
|
a996cb |
+ if (rc != 0)
|
|
|
a996cb |
+ pm_error("sigaction() to set up signal environment failed, "
|
|
|
a996cb |
+ "errno = %d (%s)", errno, strerror(errno));
|
|
|
a996cb |
+}
|
|
|
a996cb |
+
|
|
|
a996cb |
+
|
|
|
a996cb |
+
|
|
|
a996cb |
struct cmdlineInfo {
|
|
|
a996cb |
/* All the information the user supplied in the command line,
|
|
|
a996cb |
in a form easy for the program to use.
|
|
|
a996cb |
@@ -256,21 +289,17 @@ parseCommandLine(int argc, const char ** argv,
|
|
|
a996cb |
validateCompDimension(width, 72, "-width value");
|
|
|
a996cb |
validateCompDimension(height, 72, "-height value");
|
|
|
a996cb |
|
|
|
a996cb |
- overflow2(width, 72);
|
|
|
a996cb |
cmdlineP->width = width * 72;
|
|
|
a996cb |
- overflow2(height, 72);
|
|
|
a996cb |
cmdlineP->height = height * 72;
|
|
|
a996cb |
|
|
|
a996cb |
if (imagewidthSpec) {
|
|
|
a996cb |
validateCompDimension(imagewidth, 72, "-imagewidth value");
|
|
|
a996cb |
- overflow2(imagewidth, 72);
|
|
|
a996cb |
cmdlineP->imagewidth = imagewidth * 72;
|
|
|
a996cb |
}
|
|
|
a996cb |
else
|
|
|
a996cb |
cmdlineP->imagewidth = 0;
|
|
|
a996cb |
if (imageheightSpec) {
|
|
|
a996cb |
- validateCompDimension(imageheight, 72, "-imageheight value");
|
|
|
a996cb |
- overflow2(imageheight, 72);
|
|
|
a996cb |
+ validateCompDimension(imagewidth, 72, "-imageheight value");
|
|
|
a996cb |
cmdlineP->imageheight = imageheight * 72;
|
|
|
a996cb |
}
|
|
|
a996cb |
else
|
|
|
a996cb |
@@ -339,6 +368,33 @@ basebasename(const char * const filespec) {
|
|
|
a996cb |
|
|
|
a996cb |
|
|
|
a996cb |
|
|
|
a996cb |
+static void
|
|
|
a996cb |
+writeFile(const unsigned char * const buffer,
|
|
|
a996cb |
+ size_t const writeCt,
|
|
|
a996cb |
+ const char * const name,
|
|
|
a996cb |
+ FILE * const ofP) {
|
|
|
a996cb |
+
|
|
|
a996cb |
+ size_t writtenCt;
|
|
|
a996cb |
+
|
|
|
a996cb |
+ writtenCt = fwrite(buffer, 1, writeCt, ofP);
|
|
|
a996cb |
+
|
|
|
a996cb |
+ if (writtenCt != writeCt)
|
|
|
a996cb |
+ pm_error("Error writing to %s output file", name);
|
|
|
a996cb |
+}
|
|
|
a996cb |
+
|
|
|
a996cb |
+
|
|
|
a996cb |
+
|
|
|
a996cb |
+static void
|
|
|
a996cb |
+writeFileChar(const char * const buffer,
|
|
|
a996cb |
+ size_t const writeCt,
|
|
|
a996cb |
+ const char * const name,
|
|
|
a996cb |
+ FILE * const ofP) {
|
|
|
a996cb |
+
|
|
|
a996cb |
+ writeFile((const unsigned char *)buffer, writeCt, name, ofP);
|
|
|
a996cb |
+}
|
|
|
a996cb |
+
|
|
|
a996cb |
+
|
|
|
a996cb |
+
|
|
|
a996cb |
#define MAX_FILTER_CT 10
|
|
|
a996cb |
/* The maximum number of filters this code is capable of applying */
|
|
|
a996cb |
|
|
|
a996cb |
@@ -498,18 +554,12 @@ flateFilter(FILE * const ifP,
|
|
|
a996cb |
*/
|
|
|
a996cb |
do {
|
|
|
a996cb |
unsigned int have;
|
|
|
a996cb |
- size_t bytesWritten;
|
|
|
a996cb |
|
|
|
a996cb |
strm.avail_out = chunkSz;
|
|
|
a996cb |
strm.next_out = out;
|
|
|
a996cb |
deflate(&strm, flush);
|
|
|
a996cb |
have = chunkSz - strm.avail_out;
|
|
|
a996cb |
- bytesWritten = fwrite(out, 1, have, ofP);
|
|
|
a996cb |
- if (ferror(ofP) || bytesWritten != have) {
|
|
|
a996cb |
- deflateEnd(&strm;;
|
|
|
a996cb |
- pm_error("Error writing to internal pipe during "
|
|
|
a996cb |
- "flate compression.");
|
|
|
a996cb |
- }
|
|
|
a996cb |
+ writeFile(out, have, "flate filter", ofP);
|
|
|
a996cb |
} while (strm.avail_out == 0);
|
|
|
a996cb |
assert(strm.avail_in == 0); /* all input is used */
|
|
|
a996cb |
|
|
|
a996cb |
@@ -554,7 +604,7 @@ rlePutBuffer (unsigned int const repeat,
|
|
|
a996cb |
fputc(repeatitem, fP);
|
|
|
a996cb |
} else {
|
|
|
a996cb |
fputc(count - 1, fP);
|
|
|
a996cb |
- fwrite(itembuf, 1, count, fP);
|
|
|
a996cb |
+ writeFile(itembuf, count, "rlePutBuffer", fP);
|
|
|
a996cb |
}
|
|
|
a996cb |
}
|
|
|
a996cb |
|
|
|
a996cb |
@@ -677,23 +727,24 @@ asciiHexFilter(FILE * const ifP,
|
|
|
a996cb |
unsigned char inbuff[40], outbuff[81];
|
|
|
a996cb |
|
|
|
a996cb |
for (eof = false; !eof; ) {
|
|
|
a996cb |
- size_t bytesRead;
|
|
|
a996cb |
+ size_t readCt;
|
|
|
a996cb |
|
|
|
a996cb |
- bytesRead = fread(inbuff, 1, 40, ifP);
|
|
|
a996cb |
+ readCt = fread(inbuff, 1, 40, ifP);
|
|
|
a996cb |
|
|
|
a996cb |
- if (bytesRead == 0)
|
|
|
a996cb |
+ if (readCt == 0)
|
|
|
a996cb |
eof = true;
|
|
|
a996cb |
else {
|
|
|
a996cb |
unsigned int i;
|
|
|
a996cb |
|
|
|
a996cb |
- for (i = 0; i < bytesRead; ++i) {
|
|
|
a996cb |
+ for (i = 0; i < readCt; ++i) {
|
|
|
a996cb |
int const item = inbuff[i];
|
|
|
a996cb |
outbuff[i*2] = hexits[item >> 4];
|
|
|
a996cb |
outbuff[i*2+1] = hexits[item & 15];
|
|
|
a996cb |
}
|
|
|
a996cb |
}
|
|
|
a996cb |
- outbuff[bytesRead * 2] = '\n';
|
|
|
a996cb |
- fwrite(outbuff, 1, bytesRead*2 + 1, ofP);
|
|
|
a996cb |
+ outbuff[readCt * 2] = '\n';
|
|
|
a996cb |
+
|
|
|
a996cb |
+ writeFile(outbuff, readCt * 2 + 1, "asciiHex filter", ofP);
|
|
|
a996cb |
}
|
|
|
a996cb |
|
|
|
a996cb |
fclose(ifP);
|
|
|
a996cb |
@@ -731,7 +782,8 @@ ascii85Filter(FILE * const ifP,
|
|
|
a996cb |
++count;
|
|
|
a996cb |
|
|
|
a996cb |
if (value == 0 && count == 4) {
|
|
|
a996cb |
- putchar('z'); /* Ascii85 encoding z exception */
|
|
|
a996cb |
+ writeFileChar("z", 1, "ASCII 85 filter", ofP);
|
|
|
a996cb |
+ /* Ascii85 encoding z exception */
|
|
|
a996cb |
++outcount;
|
|
|
a996cb |
count = 0;
|
|
|
a996cb |
} else if (count == 4) {
|
|
|
a996cb |
@@ -741,13 +793,14 @@ ascii85Filter(FILE * const ifP,
|
|
|
a996cb |
outbuff[1] = value % 85 + 33;
|
|
|
a996cb |
outbuff[0] = value / 85 + 33;
|
|
|
a996cb |
|
|
|
a996cb |
- fwrite(outbuff, 1, count + 1, ofP);
|
|
|
a996cb |
+ writeFileChar(outbuff, count + 1, "ASCII 85 filter", ofP);
|
|
|
a996cb |
+
|
|
|
a996cb |
count = value = 0;
|
|
|
a996cb |
outcount += 5;
|
|
|
a996cb |
}
|
|
|
a996cb |
|
|
|
a996cb |
if (outcount > 75) {
|
|
|
a996cb |
- putchar('\n');
|
|
|
a996cb |
+ writeFileChar("\n", 1, "ASCII 85 filter", ofP);
|
|
|
a996cb |
outcount = 0;
|
|
|
a996cb |
}
|
|
|
a996cb |
}
|
|
|
a996cb |
@@ -763,7 +816,7 @@ ascii85Filter(FILE * const ifP,
|
|
|
a996cb |
outbuff[0] = value / 85 + 33;
|
|
|
a996cb |
outbuff[count + 1] = '\n';
|
|
|
a996cb |
|
|
|
a996cb |
- fwrite(outbuff, 1, count + 2, ofP);
|
|
|
a996cb |
+ writeFileChar(outbuff, count + 2, "ASCII 85 filter", ofP);
|
|
|
a996cb |
}
|
|
|
a996cb |
|
|
|
a996cb |
fclose(ifP);
|
|
|
a996cb |
@@ -873,13 +926,22 @@ addFilter(const char * const description,
|
|
|
a996cb |
OutputEncoder * const oeP,
|
|
|
a996cb |
FILE ** const feedFilePP,
|
|
|
a996cb |
pid_t * const pidList) {
|
|
|
a996cb |
+/*----------------------------------------------------------------------------
|
|
|
a996cb |
+ Add a filter to the front of the chain.
|
|
|
a996cb |
|
|
|
a996cb |
- pid_t pid;
|
|
|
a996cb |
+ Spawn a process to do the filtering, by running function 'filter'.
|
|
|
a996cb |
+
|
|
|
a996cb |
+ *feedFilePP is the present head of the chain. We make the new filter
|
|
|
a996cb |
+ process write its output to that and get its input from a new pipe.
|
|
|
a996cb |
+ We update *feedFilePP to the sending end of the new pipe.
|
|
|
a996cb |
|
|
|
a996cb |
+ Add to the list pidList[] the PID of the process we spawn.
|
|
|
a996cb |
+-----------------------------------------------------------------------------*/
|
|
|
a996cb |
FILE * const oldFeedFileP = *feedFilePP;
|
|
|
a996cb |
|
|
|
a996cb |
FILE * newFeedFileP;
|
|
|
a996cb |
-
|
|
|
a996cb |
+ pid_t pid;
|
|
|
a996cb |
+
|
|
|
a996cb |
spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid;;
|
|
|
a996cb |
|
|
|
a996cb |
if (verbose)
|
|
|
a996cb |
@@ -887,7 +949,7 @@ addFilter(const char * const description,
|
|
|
a996cb |
description, (unsigned)pid);
|
|
|
a996cb |
|
|
|
a996cb |
fclose(oldFeedFileP); /* Child keeps this open now */
|
|
|
a996cb |
-
|
|
|
a996cb |
+
|
|
|
a996cb |
addToPidList(pidList, pid);
|
|
|
a996cb |
|
|
|
a996cb |
*feedFilePP = newFeedFileP;
|
|
|
a996cb |
@@ -949,6 +1011,15 @@ waitForChildren(const pid_t * const pidList) {
|
|
|
a996cb |
Wait for all child processes with PIDs in pidList[] to exit.
|
|
|
a996cb |
In pidList[], end-of-list is marked with a special zero value.
|
|
|
a996cb |
-----------------------------------------------------------------------------*/
|
|
|
a996cb |
+ /* There's an odd behavior in Unix such that if you have set the
|
|
|
a996cb |
+ action for SIGCHLD to ignore the signal (even though ignoring the
|
|
|
a996cb |
+ signal is the default), the process' children do not become
|
|
|
a996cb |
+ zombies. Consequently, waitpid() always fails with ECHILD - but
|
|
|
a996cb |
+ nonetheless waits for the child to exit.
|
|
|
a996cb |
+
|
|
|
a996cb |
+ We expect the process not to have the action for SIGCHLD set that
|
|
|
a996cb |
+ way.
|
|
|
a996cb |
+ */
|
|
|
a996cb |
unsigned int i;
|
|
|
a996cb |
|
|
|
a996cb |
for (i = 0; pidList[i]; ++i) {
|
|
|
a996cb |
@@ -960,7 +1031,8 @@ waitForChildren(const pid_t * const pidList) {
|
|
|
a996cb |
|
|
|
a996cb |
rc = waitpid(pidList[i], &status, 0);
|
|
|
a996cb |
if (rc == -1)
|
|
|
a996cb |
- pm_error ("waitpid() for child %u failed", i);
|
|
|
a996cb |
+ pm_error ("waitpid() for child %u failed, errno=%d (%s)",
|
|
|
a996cb |
+ i, errno, strerror(errno));
|
|
|
a996cb |
else if (status != EXIT_SUCCESS)
|
|
|
a996cb |
pm_error ("Child process %u terminated abnormally", i);
|
|
|
a996cb |
}
|
|
|
a996cb |
@@ -1724,7 +1796,7 @@ convertRowPbm(struct pam * const pamP,
|
|
|
a996cb |
bitrow[colChars-1] <<= padRight; /* right edge */
|
|
|
a996cb |
}
|
|
|
a996cb |
|
|
|
a996cb |
- fwrite(bitrow, 1, colChars, fP);
|
|
|
a996cb |
+ writeFile(bitrow, colChars, "PBM reader", fP);
|
|
|
a996cb |
}
|
|
|
a996cb |
|
|
|
a996cb |
|
|
|
a996cb |
@@ -1867,6 +1939,21 @@ convertRaster(struct pam * const inpamP,
|
|
|
a996cb |
|
|
|
a996cb |
|
|
|
a996cb |
|
|
|
a996cb |
+/* FILE MANAGEMENT: File management is pretty hairy here. A filter, which
|
|
|
a996cb |
+ runs in its own process, needs to be able to cause its output file to
|
|
|
a996cb |
+ close because it might be an internal pipe and the next stage needs to
|
|
|
a996cb |
+ know output is done. So the forking process must close its copy of the
|
|
|
a996cb |
+ file descriptor. BUT: if the output of the filter is not an internal
|
|
|
a996cb |
+ pipe but this program's output, then we don't want it closed when the
|
|
|
a996cb |
+ filter terminates because we'll need it to be open for the next image
|
|
|
a996cb |
+ the program converts (with a whole new chain of filters).
|
|
|
a996cb |
+
|
|
|
a996cb |
+ To prevent the progam output file from getting closed, we pass a
|
|
|
a996cb |
+ duplicate of it to spawnFilters() and keep the original open.
|
|
|
a996cb |
+*/
|
|
|
a996cb |
+
|
|
|
a996cb |
+
|
|
|
a996cb |
+
|
|
|
a996cb |
static void
|
|
|
a996cb |
convertPage(FILE * const ifP,
|
|
|
a996cb |
int const turnflag,
|
|
|
a996cb |
@@ -1954,7 +2041,7 @@ convertPage(FILE * const ifP,
|
|
|
a996cb |
|
|
|
a996cb |
fflush(stdout);
|
|
|
a996cb |
filterChainOfP = fdopen(dup(fileno(stdout)), "w");
|
|
|
a996cb |
- /* spawnFilters() closes this. See FILE MANAGEMENT above */
|
|
|
a996cb |
+ /* spawnFilters() closes this. See FILE MANAGEMENT above */
|
|
|
a996cb |
|
|
|
a996cb |
spawnFilters(filterChainOfP, &oe, &feedFileP, filterPidList);
|
|
|
a996cb |
|
|
|
a996cb |
@@ -1979,6 +2066,8 @@ main(int argc, const char * argv[]) {
|
|
|
a996cb |
|
|
|
a996cb |
pm_proginit(&argc, argv);
|
|
|
a996cb |
|
|
|
a996cb |
+ setSignals();
|
|
|
a996cb |
+
|
|
|
a996cb |
parseCommandLine(argc, argv, &cmdline);
|
|
|
a996cb |
|
|
|
a996cb |
verbose = cmdline.verbose;
|
|
|
a996cb |
@@ -1994,6 +2083,13 @@ main(int argc, const char * argv[]) {
|
|
|
a996cb |
name = strdup("noname");
|
|
|
a996cb |
else
|
|
|
a996cb |
name = basebasename(cmdline.inputFileName);
|
|
|
a996cb |
+
|
|
|
a996cb |
+ /* This program manages file descriptors in a way that assumes
|
|
|
a996cb |
+ that new files will get file descriptor numbers less than 10,
|
|
|
a996cb |
+ so we close superfluous files now to make sure that's true.
|
|
|
a996cb |
+ */
|
|
|
a996cb |
+ closeAllBut(fileno(ifP), fileno(stdout), fileno(stderr));
|
|
|
a996cb |
+
|
|
|
a996cb |
{
|
|
|
a996cb |
int eof; /* There are no more images in the input file */
|
|
|
a996cb |
unsigned int imageSeq;
|