about summary refs log tree commit diff
path: root/other
diff options
context:
space:
mode:
Diffstat (limited to 'other')
-rw-r--r--other/Makefile2
-rw-r--r--other/pamfixtrunc.c175
2 files changed, 176 insertions, 1 deletions
diff --git a/other/Makefile b/other/Makefile
index 139527e3..a38766fc 100644
--- a/other/Makefile
+++ b/other/Makefile
@@ -24,7 +24,7 @@ endif
 # build.
 
 PORTBINARIES = pamarith pambayer pamchannel pamdepth \
-	pamendian pamlookup pampick pamsplit \
+	pamendian pamfixtrunc pamlookup pampick pamsplit \
 	pamstack pamsummcol pnmcolormap \
 	ppmdcfont ppmddumpfont ppmdmkfont 
 
diff --git a/other/pamfixtrunc.c b/other/pamfixtrunc.c
new file mode 100644
index 00000000..7bf2435e
--- /dev/null
+++ b/other/pamfixtrunc.c
@@ -0,0 +1,175 @@
+/*============================================================================
+                             pamfixtrunc
+==============================================================================
+  Fix a Netpbm image that has been truncated, e.g. by I/O error.
+
+  By Bryan Henderson, January 2007.
+
+  Contributed to the public domain by its author.
+
+============================================================================*/
+
+#include <setjmp.h>
+
+#include "pam.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFilespec;  /* Filespec of input file */
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, char ** const argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+
+    OPTENT3(0, "verbose",   OPT_FLAG,    NULL, &cmdlineP->verbose,       0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We don't parms that are negative numbers */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 == 0) 
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
+    else
+        cmdlineP->inputFilespec = argv[1];
+}
+
+
+
+static unsigned int readErrRow;
+static bool readErrVerbose;
+
+static pm_usererrormsgfn discardMsg;
+
+static void
+discardMsg(const char * const msg) {
+    if (readErrVerbose)
+        pm_message("Error reading row %u: %s", readErrRow, msg);
+}
+
+
+
+static void
+countRows(const struct pam * const inpamP,
+          bool               const verbose,
+          unsigned int *     const goodRowCountP) {
+
+    tuple * tuplerow;
+    unsigned int row;
+    jmp_buf jmpbuf;
+    int rc;
+    unsigned int goodRowCount;
+    
+    tuplerow = pnm_allocpamrow(inpamP);
+
+    pm_setusererrormsgfn(discardMsg);
+
+    rc = setjmp(jmpbuf);
+    if (rc == 0) {
+        pm_setjmpbuf(&jmpbuf);
+
+        readErrVerbose = verbose;
+        goodRowCount = 0;  /* initial value */
+        for (row = 0; row < inpamP->height; ++row) {
+            readErrRow = row;
+            pnm_readpamrow(inpamP, tuplerow);
+            /* The above does not return if it can't read the next row from
+               the file.  Instead, it longjmps out of this loop.
+            */
+            ++goodRowCount;
+        }
+    }
+    *goodRowCountP = goodRowCount;
+
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+static void
+copyGoodRows(const struct pam * const inpamP,
+             FILE *             const ofP,
+             unsigned int       const goodRowCount) {
+
+    struct pam outpam;
+    tuple * tuplerow;
+    unsigned int row;
+
+    outpam = *inpamP;  /* initial value */
+
+    outpam.file = ofP;
+    outpam.height = goodRowCount;
+
+    tuplerow = pnm_allocpamrow(inpamP);
+
+    pnm_writepaminit(&outpam);
+
+    for (row = 0; row < outpam.height; ++row) {
+        pnm_readpamrow(inpamP, tuplerow);
+        pnm_writepamrow(&outpam, tuplerow);
+    }
+    
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+int
+main(int argc, char * argv[]) {
+    struct cmdlineInfo cmdline;
+    struct pam inpam;
+    FILE * ifP;
+    pm_filepos rasterPos;
+    unsigned int goodRowCount;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr_seekable(cmdline.inputFilespec);
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
+
+    countRows(&inpam, cmdline.verbose, &goodRowCount);
+
+    pm_message("Copying %u good rows; %u bottom rows missing",
+               goodRowCount, inpam.height - goodRowCount);
+    
+    pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+
+    copyGoodRows(&inpam, stdout, goodRowCount);
+
+    pm_close(inpam.file);
+    
+    return 0;
+}
+
+