From 07d41c90bca1e7a8500b3bcda82985236896702c Mon Sep 17 00:00:00 2001
From: Jindrich Novy <jnovy@fedoraproject.org>
Date: Wed, 17 Mar 2010 09:43:11 +0000
Subject: [PATCH] - pgmtopbm should generate PBM, not PAM file - forwardport
 pnmmontage from 10.35 to make it work - fix pamstretch-gen

---
 netpbm-pnmmontagefix.patch    | 832 ++++++++++++++++++++++++++++++++++
 netpbm-security-scripts.patch |  44 +-
 netpbm.spec                   |  15 +-
 3 files changed, 868 insertions(+), 23 deletions(-)
 create mode 100644 netpbm-pnmmontagefix.patch

diff --git a/netpbm-pnmmontagefix.patch b/netpbm-pnmmontagefix.patch
new file mode 100644
index 0000000..fb715b8
--- /dev/null
+++ b/netpbm-pnmmontagefix.patch
@@ -0,0 +1,832 @@
+diff -up netpbm-10.47.05/editor/pnmmontage.c.pnmmontagefix netpbm-10.47.05/editor/pnmmontage.c
+--- netpbm-10.47.05/editor/pnmmontage.c.pnmmontagefix	2009-12-10 08:34:32.000000000 +0100
++++ netpbm-10.47.05/editor/pnmmontage.c	2010-03-16 20:47:38.000000000 +0100
+@@ -10,136 +10,19 @@
+  * implied warranty.
+  */
+ 
+-#define _BSD_SOURCE  /* Make sure strdup() is in <string.h> */
+-#include <assert.h>
+ #include <limits.h>
+ #include <string.h>
+ 
+-#include "pm_c_util.h"
+-#include "mallocvar.h"
+-#include "nstring.h"
+-#include "shhopt.h"
+ #include "pam.h"
++#include "shhopt.h"
++#include "nstring.h"
++#include "mallocvar.h"
+ 
++typedef struct { int f[sizeof(int) * 8 + 1]; } factorset;
++typedef struct { int x; int y; } coord;
+ 
+-
+-struct cmdlineInfo {
+-    const char * header;
+-    const char * data;
+-    const char * prefix;
+-    unsigned int quality;
+-    unsigned int quality2;
+-    unsigned int nFiles;
+-    const char ** inFileName;
+-};
+-
+-
+-
+-static void
+-parseCommandLine(int argc, const char ** argv,
+-                 struct cmdlineInfo * const cmdlineP) {
+-/*----------------------------------------------------------------------------
+-   parse program command line described in Unix standard form by argc
+-   and argv.  Return the information in the options as *cmdlineP.  
+-
+-   If command line is internally inconsistent (invalid options, etc.),
+-   issue error message to stderr and abort program.
+-
+-   Note that the strings we return are stored in the storage that
+-   was passed to us as the argv array.  We also trash *argv.
+------------------------------------------------------------------------------*/
+-    optEntry * option_def;
+-        /* Instructions to OptParseOptions3 on how to parse our options. */
+-    optStruct3 opt;
+-    unsigned int dataSpec, headerSpec, prefixSpec, qualitySpec;
+-    unsigned int option_def_index;
+-    unsigned int i;
+-    unsigned int q[10];
+-
+-    MALLOCARRAY_NOFAIL(option_def, 100);
+-  
+-    option_def_index = 0;   /* incremented by OPTENTRY */
+-    OPTENT3( 0,  "data",    OPT_STRING, &cmdlineP->data, &dataSpec, 0);
+-    OPTENT3( 0,  "header",  OPT_STRING, &cmdlineP->header, &headerSpec, 0);
+-    OPTENT3('q', "quality", OPT_UINT,   &cmdlineP->quality,   &qualitySpec, 0);
+-    OPTENT3('p', "prefix",  OPT_STRING, &cmdlineP->prefix,    &prefixSpec, 0);
+-    OPTENT3('0', "0",       OPT_FLAG,   NULL, &q[0],      0);
+-    OPTENT3('1', "1",       OPT_FLAG,   NULL, &q[1],      0);
+-    OPTENT3('2', "2",       OPT_FLAG,   NULL, &q[2],      0);
+-    OPTENT3('3', "3",       OPT_FLAG,   NULL, &q[3],      0);
+-    OPTENT3('4', "4",       OPT_FLAG,   NULL, &q[4],      0);
+-    OPTENT3('5', "5",       OPT_FLAG,   NULL, &q[5],      0);
+-    OPTENT3('6', "6",       OPT_FLAG,   NULL, &q[6],      0);
+-    OPTENT3('7', "7",       OPT_FLAG,   NULL, &q[7],      0);
+-    OPTENT3('8', "8",       OPT_FLAG,   NULL, &q[8],      0);
+-    OPTENT3('9', "9",       OPT_FLAG,   NULL, &q[9],      0);
+-
+-    opt.opt_table = option_def;
+-    opt.short_allowed = FALSE;
+-    opt.allowNegNum = FALSE;
+-
+-    optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0);
+-
+-    if (!dataSpec)
+-        cmdlineP->data = NULL;
+-    if (!headerSpec)
+-        cmdlineP->header = NULL;
+-    if (!prefixSpec)
+-        cmdlineP->prefix = "";
+-    if (!qualitySpec)
+-        cmdlineP->quality = 200;
+-
+-    
+-    /* cmdlineP->quality2 is the greatest number from the --1, --2, etc.
+-       options, or 5 if none of those are specified.
+-    */
+-    cmdlineP->quality2 = 5;  /* initial value */
+-    for (i = 0; i < 10; ++i) {
+-        if (q[i])
+-            cmdlineP->quality2 = i;
+-    }
+-
+-    cmdlineP->nFiles = argc-1;
+-
+-    MALLOCARRAY_NOFAIL(cmdlineP->inFileName, argc-1);
+-
+-    for (i = 0; i < argc-1; ++i) {
+-        if (cmdlineP->data && strchr(argv[i+1], ':'))
+-            pm_error("Filename '%s' contains a \":\", which is forbidden "
+-                     "with -data", argv[i+1]);
+-        else
+-            cmdlineP->inFileName[i] = strdup(argv[1+1]);
+-    }
+-}
+-
+-
+-
+-typedef struct {
+-    int f[sizeof(int) * 8 + 1];
+-} factorset;
+-
+-typedef struct {
+-    int x; int y;
+-} coord;
+-
+-typedef struct {
+-    coord ul;
+-    coord size;
+-} rectangle;
+-
+-static coord
+-lr(rectangle const r) {
+-/*----------------------------------------------------------------------------
+-   Return the coordinates of the lower right corner of 'r'
+-   (i.e. the pixel just beyond the lowest rightmost one).
+------------------------------------------------------------------------------*/
+-    coord retval;
+-
+-    retval.x = r.ul.x + r.size.x;
+-    retval.y = r.ul.y + r.size.y;
+-
+-    return retval;
+-}
++static int qfactor = 200;
++static int quality = 5;
+ 
+ static factorset 
+ factor(int n)
+@@ -180,151 +63,109 @@ gcd(int n, int m)
+   return (g);
+ }
+ 
++static __inline__ int imax(int n, int m) { return (n > m ? n : m); }
+ 
+-
+-static bool
+-overlaps(rectangle const a,
+-         rectangle const b) {
+-
+-    return
+-        (a.ul.x < lr(b).x && a.ul.y < lr(b).y) &&
+-        (lr(a).x > b.ul.x && lr(a).y > b.ul.y);
+-}
+-
+-
+-
+-static bool
+-collides(rectangle         const test,
+-         const rectangle * const fieldList,
+-         unsigned int      const n) {
+-/*----------------------------------------------------------------------------
+-   Return true iff the rectangle 'test' overlaps any of the 'n' rectangles
+-   fieldList[].
+------------------------------------------------------------------------------*/
+-    unsigned int i;
+-
+-    for (i = 0; i < n; ++i)
+-        if (overlaps(fieldList[i], test))
+-            return true;
+-
+-    return false;
++static int 
++checkcollision(coord *locs, coord *szs, coord *cloc, coord *csz, int n)
++{
++  int i;
++  for (i = 0; i < n; ++i)
++  {
++    if ((locs[i].x < cloc->x + csz->x) &&
++        (locs[i].y < cloc->y + csz->y) &&
++        (locs[i].x + szs[i].x > cloc->x) &&
++        (locs[i].y + szs[i].y > cloc->y))
++      return (1);
++  }
++  return (0);
+ }
+ 
+-
+-
+ static void 
+-recursefindpack(rectangle *    const current,
+-                coord          const currentsz,
+-                coord *        const best,
+-                unsigned int   const minarea,
+-                unsigned int * const maxareaP, 
+-                unsigned int   const depth,
+-                unsigned int   const n,
+-                unsigned int   const xinc,
+-                unsigned int   const yinc,
+-                unsigned int   const quality,
+-                unsigned int   const qfactor) {
+-
+-    if (depth == n) {
+-        if (currentsz.x * currentsz.y < *maxareaP) {
+-            unsigned int i;
+-            for (i = 0; i < n; ++i)
+-                best[i] = current[i].ul;
+-            *maxareaP = currentsz.x * currentsz.y;
+-        }
+-    } else {
+-        unsigned int i;
+-
+-        rectangle * const newP = &current[depth];
++recursefindpack(coord *current, coord currentsz, coord *set, 
++                coord *best, int minarea, int *maxarea, 
++                int depth, int n, int xinc, int yinc)
++{
++  coord c;
++  if (depth == n)
++  {
++    if (currentsz.x * currentsz.y < *maxarea)
++    {
++      memcpy(best, current, sizeof(coord) * n);
++      *maxarea = currentsz.x * currentsz.y;
++    }
++    return;
++  }
+ 
+-        for (i = 0; ; ++i) {
+-            for (newP->ul.x = 0, newP->ul.y = i * yinc;
+-                 newP->ul.y <= i * yinc;) {
+-
+-                coord c;
+-
+-                c.x = MAX(lr(*newP).x, currentsz.x);
+-                c.y = MAX(lr(*newP).y, currentsz.y);
+-                pm_message("current = (%u.%u, %u.%u) new = (%u.%u, %u.%u)",
+-                           current[0].ul.x, current[0].size.x,
+-                           current[0].ul.y, current[0].size.y,
+-                           newP->ul.x,   newP->size.x,
+-                           newP->ul.y,   newP->size.y);
+-                if (!collides(*newP, current, depth)) {
+-                    pm_message("Depth %u: Doesn't collide at i=%u", depth,i);
+-                    recursefindpack(current, c, best, minarea, maxareaP,
+-                                    depth + 1, n, xinc, yinc,
+-                                    quality, qfactor);
+-                    if (*maxareaP <= minarea)
+-                        return;
+-                }
+-                if (newP->ul.x == (i - 1) * xinc)
+-                    newP->ul.y = 0;
+-                if (newP->ul.x < i * xinc)
+-                    newP->ul.x += xinc;
+-                else
+-                    newP->ul.y += yinc;
+-            }
+-        }
++  for (current[depth].x = 0; 
++       imax(current[depth].x + set[depth].x, currentsz.x) * 
++           imax(currentsz.y, set[depth].y) < *maxarea; 
++       current[depth].x += xinc)
++  {
++    for (current[depth].y = 0; 
++         imax(current[depth].x + set[depth].x, currentsz.x) * 
++             imax(currentsz.y, current[depth].y + set[depth].y) < *maxarea; 
++         current[depth].y += yinc)
++    {
++      c.x = imax(current[depth].x + set[depth].x, currentsz.x);
++      c.y = imax(current[depth].y + set[depth].y, currentsz.y);
++      if (!checkcollision(current, set, &current[depth], &set[depth], depth))
++      {
++        recursefindpack(current, c, set, best, minarea, maxarea, 
++                        depth + 1, n, xinc, yinc);
++        if (*maxarea <= minarea)
++          return;
++      }
+     }
++  }
+ }
+ 
+-
+-
+ static void 
+-findpack(struct pam * const imgs,
+-         unsigned int const n,
+-         coord *      const coords,
+-         unsigned int const quality,
+-         unsigned int const qfactor) {
++findpack(struct pam *imgs, int n, coord *coords)
++{
++  int minarea;
++  int i;
++  int rdiv;
++  int cdiv;
++  int minx = -1;
++  int miny = -1;
++  coord *current;
++  coord *set;
++  int z = INT_MAX;
++  coord c = { 0, 0 };
+ 
+-    int minarea;
+-    int i;
+-    int rdiv;
+-    int cdiv;
+-    int minx;
+-    int miny;
+-    rectangle * current;
+-    unsigned int z;
+-    coord c;
+-
+-    minx = -1; miny = -1;  /* initial value */
+-    z = UINT_MAX;  /* initial value */
+-    c.x = 0; c.y = 0;  /* initial value */
+-
+-    if (quality > 1) {
+-        unsigned int realMinarea;
+-        for (realMinarea = i = 0; i < n; ++i)
+-            realMinarea += imgs[i].height * imgs[i].width,
+-                minx = MAX(minx, imgs[i].width),
+-                miny = MAX(miny, imgs[i].height);
+-
+-        minarea = realMinarea * qfactor / 100;
+-    } else {
+-        minarea = INT_MAX - 1;
+-    }
++  if (quality > 1)
++  {
++    for (minarea = i = 0; i < n; ++i)
++      minarea += imgs[i].height * imgs[i].width,
++      minx = imax(minx, imgs[i].width),
++      miny = imax(miny, imgs[i].height);
+ 
+-    /* It's relatively easy to show that, if all the images
+-     * are multiples of a particular size, then a best
+-     * packing will always align the images on a grid of
+-     * that size.
+-     *
+-     * This speeds computation immensely.
+-     */
+-    for (rdiv = imgs[0].height, i = 1; i < n; ++i)
+-        rdiv = gcd(imgs[i].height, rdiv);
+-
+-    for (cdiv = imgs[0].width, i = 1; i < n; ++i)
+-        cdiv = gcd(imgs[i].width, cdiv);
+-
+-    MALLOCARRAY(current, n);
+-
+-    for (i = 0; i < n; ++i) {
+-        current[i].size.x = imgs[i].width;
+-        current[i].size.y = imgs[i].height;
+-    }
+-    recursefindpack(current, c, coords, minarea, &z, 0, n, cdiv, rdiv,
+-                    quality, qfactor);
++    minarea = minarea * qfactor / 100;
++  }
++  else
++  {
++    minarea = INT_MAX - 1;
++  }
++
++  /* It's relatively easy to show that, if all the images
++   * are multiples of a particular size, then a best
++   * packing will always align the images on a grid of
++   * that size.
++   *
++   * This speeds computation immensely.
++   */
++  for (rdiv = imgs[0].height, i = 1; i < n; ++i)
++    rdiv = gcd(imgs[i].height, rdiv);
++
++  for (cdiv = imgs[0].width, i = 1; i < n; ++i)
++    cdiv = gcd(imgs[i].width, cdiv);
++
++  MALLOCARRAY(current, n);
++  MALLOCARRAY(set, n);
++  for (i = 0; i < n; ++i)
++    set[i].x = imgs[i].width,
++    set[i].y = imgs[i].height;
++  recursefindpack(current, c, set, coords, minarea, &z, 0, n, cdiv, rdiv);
+ }
+ 
+ 
+@@ -396,264 +237,204 @@ writePam(struct pam *       const outpam
+ 
+ 
+ 
+-static void
+-writeData(FILE *             const dataFileP,
+-          unsigned int       const width,
+-          unsigned int       const height,
+-          unsigned int       const nfiles,
+-          const char **      const names,
+-          const coord *      const coords,
+-          const struct pam * const imgs) {
+-
+-    unsigned int i;
+-
+-    fprintf(dataFileP, ":0:0:%u:%u\n", width, height);
+-
+-    for (i = 0; i < nfiles; ++i) {
+-        fprintf(dataFileP, "%s:%u:%u:%u:%u\n", names[i], coords[i].x,
+-                coords[i].y, imgs[i].width, imgs[i].height);
+-    }
+-}
+-
+-
+-
+-static void
+-writeHeader(FILE * const headerFileP,
+-            const char * const prefix,
+-            unsigned int const width,
+-            unsigned int const height,
+-            unsigned int const nfiles,
+-            const char ** const names,
+-            const coord * const coords,
+-            const struct pam * imgs) {
+-
+-    unsigned int i;
+-
+-    fprintf(headerFileP, "#define %sOVERALLX %u\n", prefix, width);
+-
+-    fprintf(headerFileP, "#define %sOVERALLY %u\n", prefix, height);
+-
+-    fprintf(headerFileP, "\n");
+-
+-    for (i = 0; i < nfiles; ++i) {
+-        char * const buffer = strdup(names[i]);
+-        coord const coord = coords[i];
+-        struct pam const img = imgs[i];
+-
+-        unsigned int j;
+-        
+-        *strchr(buffer, '.') = 0;
+-        for (j = 0; buffer[j]; ++j) {
+-            if (ISLOWER(buffer[j]))
+-                buffer[j] = TOUPPER(buffer[j]);
+-        }
+-        fprintf(headerFileP, "#define %s%sX %u\n", 
+-                prefix, buffer, coord.x);
+-
+-        fprintf(headerFileP, "#define %s%sY %u\n",
+-                prefix, buffer, coord.y);
+-
+-        fprintf(headerFileP, "#define %s%sSZX %u\n",
+-                prefix, buffer, img.width);
+-
+-        fprintf(headerFileP, "#define %s%sSZY %u\n",
+-                prefix, buffer, img.height);
+-
+-        fprintf(headerFileP, "\n");
+-    }
+-}
++int 
++main(int argc, char **argv)
++{
++  struct pam *imgs;
++  struct pam outimg;
++  struct pam p;
++  int nfiles;
++  int i, j;
++  unsigned int q[10];
++  coord *coords;
++  const char *headfname = NULL;
++  const char *datafname = NULL;
++  const char *prefix = "";
++  FILE *header;
++  FILE *data;
++  char **names;
++  char *c;
++
++  optEntry *option_def = malloc(100*sizeof(optEntry));
++      /* Instructions to OptParseOptions3 on how to parse our options.
++       */
++  optStruct3 opt;
++
++  unsigned int option_def_index;
++
++  option_def_index = 0;   /* incremented by OPTENTRY */
++  OPTENT3( 0,  "data",    OPT_STRING, &datafname, NULL, 0);
++  OPTENT3( 0,  "header",  OPT_STRING, &headfname, NULL, 0);
++  OPTENT3('q', "quality", OPT_UINT,   &qfactor,   NULL, 0);
++  OPTENT3('p', "prefix",  OPT_STRING, &prefix,    NULL, 0);
++  OPTENT3('0', "0",       OPT_FLAG,   NULL, &q[0],      0);
++  OPTENT3('1', "1",       OPT_FLAG,   NULL, &q[1],      0);
++  OPTENT3('2', "2",       OPT_FLAG,   NULL, &q[2],      0);
++  OPTENT3('3', "3",       OPT_FLAG,   NULL, &q[3],      0);
++  OPTENT3('4', "4",       OPT_FLAG,   NULL, &q[4],      0);
++  OPTENT3('5', "5",       OPT_FLAG,   NULL, &q[5],      0);
++  OPTENT3('6', "6",       OPT_FLAG,   NULL, &q[6],      0);
++  OPTENT3('7', "7",       OPT_FLAG,   NULL, &q[7],      0);
++  OPTENT3('8', "8",       OPT_FLAG,   NULL, &q[8],      0);
++  OPTENT3('9', "9",       OPT_FLAG,   NULL, &q[9],      0);
++
++  opt.opt_table = option_def;
++  opt.short_allowed = FALSE;
++  opt.allowNegNum = FALSE;
++
++  pnm_init(&argc, argv);
++
++  /* Check for flags. */
++  optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+ 
++  if (headfname)
++    header = pm_openw(headfname);
+ 
++  if (datafname)
++    data = pm_openw(datafname);
+ 
+-static void
+-sortImagesByArea(unsigned int  const nfiles,
+-                 struct pam *  const imgs,
+-                 const char ** const names) {
+-/*----------------------------------------------------------------------------
+-   Sort the images described by 'imgs' and 'names' in place, from largest
+-   area to smallest.
+------------------------------------------------------------------------------*/
+-    /* Bubble sort */
+-
+-    unsigned int i;
+-
+-    for (i = 0; i < nfiles - 1; ++i) {
+-        unsigned int j;
+-        for (j = i + 1; j < nfiles; ++j) {
+-            if (imgs[j].width * imgs[j].height >
+-                imgs[i].width * imgs[i].height) {
+-
+-                struct pam p;
+-                const char * c;
+-                
+-                p = imgs[i]; imgs[i] = imgs[j]; imgs[j] = p;
+-                c = names[i]; names[i] = names[j]; names[j] = c;
+-            }
+-        }
++  for (i = 0; i < 10; ++i)
++  {
++    if (q[i])
++    {
++      quality = i;
++      switch (quality)
++      {
++        case 0: case 1: break;
++        case 2: case 3: case 4: case 5: case 6: 
++            qfactor = 100 * (8 - quality); 
++            break;
++        case 7: qfactor = 150; break;
++        case 8: qfactor = 125; break;
++        case 9: qfactor = 100; break;
++      }
+     }
+-}
+-
++  }
+ 
++  if (1 < argc)
++    nfiles = argc - 1;
++  else
++    nfiles = 1;
++
++  MALLOCARRAY(imgs, nfiles);
++  MALLOCARRAY(coords, nfiles);
++  MALLOCARRAY(names, nfiles);
++  
++  if (!imgs || !coords || !names)
++    pm_error("out of memory");
+ 
+-static void
+-computeOutputType(sample *           const maxvalP,
+-                  int *              const formatP,
+-                  char *             const tupleTypeP,
+-                  unsigned int *     const depthP,
+-                  unsigned int       const nfiles,
+-                  const struct pam * const imgs) {
+-
+-    unsigned int i;
+-
+-    sample maxval;
+-    int format;
+-    const char * tupleType;
+-    unsigned int depth;
+-
+-    assert(nfiles > 0);
+-
+-    /* initial guesses */
+-    maxval    = imgs[0].maxval;
+-    format    = imgs[0].format;
+-    depth     = imgs[0].depth;
+-    tupleType = imgs[0].tuple_type;
+-
+-    for (i = 1; i < nfiles; ++i) {
+-        if (PAM_FORMAT_TYPE(imgs[i].format) > PAM_FORMAT_TYPE(format)) {
+-            format    = imgs[i].format;
+-            tupleType = imgs[i].tuple_type;
+-        }
+-        maxval = MAX(maxval, imgs[i].maxval);
+-        depth  = MAX(depth,  imgs[i].depth);
++  if (1 < argc)
++  {
++    for (i = 0; i < nfiles; ++i)
++    {
++      if (strchr(argv[i+1], ':'))
++      {
++        imgs[i].file = pm_openr(strchr(argv[i+1], ':') + 1);
++        *strchr(argv[i+1], ':') = 0;
++        names[i] = argv[i+1];
++      }
++      else
++      {
++        imgs[i].file = pm_openr(argv[i+1]);
++        names[i] = argv[i+1];
++      }
+     }
++  }
++  else
++  {
++    imgs[0].file = stdin;
++  }
+ 
+-    *maxvalP = maxval;
+-    *formatP = format;
+-    *depthP  = depth;
+-    memcpy(tupleTypeP, tupleType, sizeof(imgs[0].tuple_type));
+-}
++  pnm_readpaminit(imgs[0].file, &imgs[0], PAM_STRUCT_SIZE(tuple_type));
++  memset(&outimg, 0, sizeof(outimg));
++  outimg.maxval = imgs[0].maxval;
++  outimg.format = imgs[0].format;
++  memcpy(outimg.tuple_type, imgs[0].tuple_type, sizeof(imgs[0].tuple_type));
++  outimg.depth = imgs[0].depth;
+ 
++  for (i = 1; i < nfiles; ++i)
++  {
++    pnm_readpaminit(imgs[i].file, &imgs[i], PAM_STRUCT_SIZE(tuple_type));
++    if (PAM_FORMAT_TYPE(imgs[i].format) > PAM_FORMAT_TYPE(outimg.format))
++      outimg.format = imgs[i].format,
++      memcpy(outimg.tuple_type, imgs[i].tuple_type, 
++             sizeof(imgs[i].tuple_type));
++    outimg.maxval = imax(imgs[i].maxval, outimg.maxval);
++    outimg.depth = imax(imgs[i].depth, outimg.depth);
++  }
+ 
++  for (i = 0; i < nfiles - 1; ++i)
++    for (j = i + 1; j < nfiles; ++j)
++      if (imgs[j].width * imgs[j].height > imgs[i].width * imgs[i].height)
++        p = imgs[i], imgs[i] = imgs[j], imgs[j] = p,
++        c = names[i], names[i] = names[j], names[j] = c;
+ 
+-static void
+-computeOutputDimensions(int * const widthP,
+-                        int * const heightP,
+-                        unsigned int const nfiles,
+-                        const struct pam * const imgs,
+-                        const coord * const coords) {
+-
+-    unsigned int widthGuess, heightGuess;
+-    unsigned int i;
+-
+-    widthGuess  = 0;  /* initial value */
+-    heightGuess = 0;  /* initial value */
+-    
+-    for (i = 0; i < nfiles; ++i) {
+-        widthGuess  = MAX(widthGuess,  imgs[i].width  + coords[i].x);
+-        heightGuess = MAX(heightGuess, imgs[i].height + coords[i].y);
+-    }
++  findpack(imgs, nfiles, coords);
+ 
+-    *widthP  = widthGuess;
+-    *heightP = heightGuess;
+-}
++  outimg.height = outimg.width = 0;
++  for (i = 0; i < nfiles; ++i)
++  {
++    outimg.width = imax(outimg.width, imgs[i].width + coords[i].x);
++    outimg.height = imax(outimg.height, imgs[i].height + coords[i].y);
++  }
+ 
++  outimg.size = sizeof(outimg);
++  outimg.len = sizeof(outimg);
++  outimg.file = stdout;
++  outimg.bytes_per_sample = 0;
++  for (i = outimg.maxval; i; i >>= 8)
++    ++outimg.bytes_per_sample;
+ 
++  writePam(&outimg, nfiles, coords, imgs);
+ 
+-int 
+-main(int argc, const char **argv) {
++  if (datafname)
++  {
++    fprintf(data, ":0:0:%u:%u\n", outimg.width, outimg.height);
+ 
+-    struct cmdlineInfo cmdline;
+-    struct pam * imgs;
+-    struct pam outimg;
+-    unsigned int nfiles;
+-    coord * coords;
+-    FILE * header;
+-    FILE * data;
+-    const char ** names;
+-    unsigned int i;
+-    unsigned int qfactor;  /* In per cent */
+-
+-    pm_proginit(&argc, argv);
+-
+-    parseCommandLine(argc, argv, &cmdline);
+-
+-    header = cmdline.header ? pm_openw(cmdline.header) : NULL;
+-    data = cmdline.data ? pm_openw(cmdline.data) : NULL;
+-
+-    switch (cmdline.quality2) {
+-    case 0: case 1:
+-        qfactor = cmdline.quality;
+-        break;
+-    case 2: case 3: case 4: case 5: case 6: 
+-        qfactor = 100 * (8 - cmdline.quality2); 
+-        break;
+-    case 7: qfactor = 150; break;
+-    case 8: qfactor = 125; break;
+-    case 9: qfactor = 100; break;
+-    default: pm_error("Internal error - impossible value of 'quality2': %u",
+-                      cmdline.quality2);
++    for (i = 0; i < nfiles; ++i)
++    {
++      fprintf(data, "%s:%u:%u:%u:%u\n", names[i], coords[i].x,
++          coords[i].y, imgs[i].width, imgs[i].height);
+     }
++  }
+ 
+-    nfiles = cmdline.nFiles > 0 ? cmdline.nFiles : 1;
+-
+-    MALLOCARRAY(imgs, nfiles);
+-    MALLOCARRAY(coords, nfiles);
+-    MALLOCARRAY(names, nfiles);
+-  
+-    if (!imgs || !coords || !names)
+-        pm_error("out of memory");
+-
+-    if (cmdline.nFiles > 0) {
+-        unsigned int i;
+-
+-        for (i = 0; i < cmdline.nFiles; ++i) {
+-            imgs[i].file = pm_openr(cmdline.inFileName[i]);
+-            names[i] = strdup(cmdline.inFileName[i]);
+-        }
+-    } else {
+-        imgs[0].file = stdin;
+-        names[0] = strdup("stdin");
+-    }
++  if (headfname)
++  {
++    fprintf(header, "#define %sOVERALLX %u\n"
++                    "#define %sOVERALLY %u\n"
++                    "\n",
++                    prefix, outimg.width,
++                    prefix, outimg.height);
+ 
+     for (i = 0; i < nfiles; ++i)
+-        pnm_readpaminit(imgs[i].file, &imgs[i], PAM_STRUCT_SIZE(tuple_type));
+-
+-    sortImagesByArea(nfiles, imgs, names);
+-
+-    findpack(imgs, nfiles, coords, cmdline.quality2, qfactor);
+-
+-    computeOutputType(&outimg.maxval, &outimg.format, outimg.tuple_type,
+-                      &outimg.depth, nfiles, imgs);
+-
+-    computeOutputDimensions(&outimg.width, &outimg.height, nfiles,
+-                            imgs, coords);
+-
+-    pnm_setminallocationdepth(&outimg, outimg.depth);
+-
+-    outimg.size = sizeof(outimg);
+-    outimg.len = sizeof(outimg);
+-    outimg.file = stdout;
+-    outimg.bytes_per_sample = 0;
+-    for (i = outimg.maxval; i; i >>= 8)
+-        ++outimg.bytes_per_sample;
+- 
+-    writePam(&outimg, nfiles, coords, imgs);
++    {
++      *strchr(names[i], '.') = 0;
++      for (j = 0; names[i][j]; ++j)
++      {
++        if (ISLOWER(names[i][j]))
++          names[i][j] = TOUPPER(names[i][j]);
++      }
++      fprintf(header, "#define %s%sX %u\n"
++                      "#define %s%sY %u\n"
++                      "#define %s%sSZX %u\n"
++                      "#define %s%sSZY %u\n"
++                      "\n",
++                      prefix, names[i], coords[i].x,
++                      prefix, names[i], coords[i].y,
++                      prefix, names[i], imgs[i].width,
++                      prefix, names[i], imgs[i].height);
++    }
++  }
+ 
+-    if (data)
+-        writeData(data, outimg.width, outimg.height,
+-                  nfiles, names, coords, imgs);
++  for (i = 0; i < nfiles; ++i)
++    pm_close(imgs[i].file);
++  pm_close(stdout);
+ 
+-    if (header)
+-        writeHeader(header, cmdline.prefix, outimg.width, outimg.height,
+-                    nfiles, names, coords, imgs);
++  if (headfname)
++    pm_close(header);
+ 
+-    for (i = 0; i < nfiles; ++i)
+-        pm_close(imgs[i].file);
+-    pm_close(stdout);
+-    if (header)
+-        pm_close(header);
+-    if (data)
+-        pm_close(data);
++  if (datafname)
++    pm_close(data);
+ 
+-    return 0;
++  return 0;
+ }
diff --git a/netpbm-security-scripts.patch b/netpbm-security-scripts.patch
index 63005d1..557914b 100644
--- a/netpbm-security-scripts.patch
+++ b/netpbm-security-scripts.patch
@@ -1,6 +1,6 @@
-diff -up netpbm-10.47.06/converter/other/anytopnm.security-scripts netpbm-10.47.06/converter/other/anytopnm
---- netpbm-10.47.06/converter/other/anytopnm.security-scripts	2009-12-13 20:27:05.000000000 +0100
-+++ netpbm-10.47.06/converter/other/anytopnm	2009-12-16 18:59:17.000000000 +0100
+diff -up netpbm-10.47.05/converter/other/anytopnm.security-scripts netpbm-10.47.05/converter/other/anytopnm
+--- netpbm-10.47.05/converter/other/anytopnm.security-scripts	2009-12-10 08:34:36.000000000 +0100
++++ netpbm-10.47.05/converter/other/anytopnm	2010-03-16 21:28:09.000000000 +0100
 @@ -510,10 +510,7 @@ else
      inputFile="-"
  fi
@@ -31,10 +31,10 @@ diff -up netpbm-10.47.06/converter/other/anytopnm.security-scripts netpbm-10.47.
 +fi
 +
  exit 0
-diff -up netpbm-10.47.06/editor/pamstretch-gen.security-scripts netpbm-10.47.06/editor/pamstretch-gen
---- netpbm-10.47.06/editor/pamstretch-gen.security-scripts	2009-12-13 20:26:58.000000000 +0100
-+++ netpbm-10.47.06/editor/pamstretch-gen	2009-12-16 18:59:17.000000000 +0100
-@@ -31,9 +31,7 @@ if [ "$1" = "" ]; then
+diff -up netpbm-10.47.05/editor/pamstretch-gen.security-scripts netpbm-10.47.05/editor/pamstretch-gen
+--- netpbm-10.47.05/editor/pamstretch-gen.security-scripts	2009-12-10 08:34:32.000000000 +0100
++++ netpbm-10.47.05/editor/pamstretch-gen	2010-03-16 21:28:47.000000000 +0100
+@@ -31,13 +31,9 @@ if [ "$1" = "" ]; then
    exit 1
  fi
  
@@ -44,10 +44,14 @@ diff -up netpbm-10.47.06/editor/pamstretch-gen.security-scripts netpbm-10.47.06/
 +tempfile=$(mktemp /tmp/pnmig.XXXXXXXXXX) || exit 1
  trap 'rm -rf $tempdir' 0 1 3 15
  
- tempfile=$tempdir/pnmig
-diff -up netpbm-10.47.06/editor/pnmmargin.security-scripts netpbm-10.47.06/editor/pnmmargin
---- netpbm-10.47.06/editor/pnmmargin.security-scripts	2009-12-13 20:26:58.000000000 +0100
-+++ netpbm-10.47.06/editor/pnmmargin	2009-12-16 19:04:05.000000000 +0100
+-tempfile=$tempdir/pnmig
+-
+ if ! cat $2 >$tempfile 2>/dev/null; then
+   echo 'pamstretch-gen: error reading file' 1>&2
+   exit 1
+diff -up netpbm-10.47.05/editor/pnmmargin.security-scripts netpbm-10.47.05/editor/pnmmargin
+--- netpbm-10.47.05/editor/pnmmargin.security-scripts	2009-12-10 08:34:32.000000000 +0100
++++ netpbm-10.47.05/editor/pnmmargin	2010-03-16 21:28:09.000000000 +0100
 @@ -11,15 +11,11 @@
  # documentation.  This software is provided "as is" without express or
  # implied warranty.
@@ -86,9 +90,9 @@ diff -up netpbm-10.47.06/editor/pnmmargin.security-scripts netpbm-10.47.06/edito
 -
 -
 +rm -rf "$tmpdir"
-diff -up netpbm-10.47.06/editor/ppmfade.security-scripts netpbm-10.47.06/editor/ppmfade
---- netpbm-10.47.06/editor/ppmfade.security-scripts	2009-12-13 20:26:58.000000000 +0100
-+++ netpbm-10.47.06/editor/ppmfade	2009-12-16 18:59:17.000000000 +0100
+diff -up netpbm-10.47.05/editor/ppmfade.security-scripts netpbm-10.47.05/editor/ppmfade
+--- netpbm-10.47.05/editor/ppmfade.security-scripts	2009-12-10 08:34:32.000000000 +0100
++++ netpbm-10.47.05/editor/ppmfade	2010-03-16 21:28:09.000000000 +0100
 @@ -14,6 +14,7 @@
  #
  #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -352,9 +356,9 @@ diff -up netpbm-10.47.06/editor/ppmfade.security-scripts netpbm-10.47.06/editor/
 +system("rm $tmpdir/junk*$$.ppm");
  
  exit(0);
-diff -up netpbm-10.47.06/editor/ppmquantall.security-scripts netpbm-10.47.06/editor/ppmquantall
---- netpbm-10.47.06/editor/ppmquantall.security-scripts	2009-12-13 20:26:58.000000000 +0100
-+++ netpbm-10.47.06/editor/ppmquantall	2009-12-16 18:59:17.000000000 +0100
+diff -up netpbm-10.47.05/editor/ppmquantall.security-scripts netpbm-10.47.05/editor/ppmquantall
+--- netpbm-10.47.05/editor/ppmquantall.security-scripts	2009-12-10 08:34:32.000000000 +0100
++++ netpbm-10.47.05/editor/ppmquantall	2010-03-16 21:28:09.000000000 +0100
 @@ -70,12 +70,8 @@ for i in ${files[@]}; do
      heights=(${heights[*]} `grep -v '^#' $i | sed '1d; s/.* //; 2q'`)
  done
@@ -370,9 +374,9 @@ diff -up netpbm-10.47.06/editor/ppmquantall.security-scripts netpbm-10.47.06/edi
  
  pnmcat -topbottom -jleft -white ${files[@]} | pnmquant $newcolors > $all
  if [ $? != 0 ]; then
-diff -up netpbm-10.47.06/editor/ppmshadow.security-scripts netpbm-10.47.06/editor/ppmshadow
---- netpbm-10.47.06/editor/ppmshadow.security-scripts	2009-12-13 20:26:58.000000000 +0100
-+++ netpbm-10.47.06/editor/ppmshadow	2009-12-16 18:59:17.000000000 +0100
+diff -up netpbm-10.47.05/editor/ppmshadow.security-scripts netpbm-10.47.05/editor/ppmshadow
+--- netpbm-10.47.05/editor/ppmshadow.security-scripts	2009-12-10 08:34:32.000000000 +0100
++++ netpbm-10.47.05/editor/ppmshadow	2010-03-16 21:28:09.000000000 +0100
 @@ -72,9 +72,10 @@ sub makeConvolutionKernel($$) {
  
  
diff --git a/netpbm.spec b/netpbm.spec
index 723c3db..94560ba 100644
--- a/netpbm.spec
+++ b/netpbm.spec
@@ -1,7 +1,7 @@
 Summary: A library for handling different graphics file formats
 Name: netpbm
 Version: 10.47.10
-Release: 1%{?dist}
+Release: 2%{?dist}
 # See copyright_summary for details
 License: BSD and GPLv2 and IJG and MIT and Public Domain
 Group: System Environment/Libraries
@@ -29,6 +29,7 @@ Patch15: netpbm-docfix.patch
 Patch16: netpbm-ppmfadeusage.patch
 Patch17: netpbm-fiasco-overflow.patch
 Patch18: netpbm-lz.patch
+Patch19: netpbm-pnmmontagefix.patch
 Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires: libjpeg-devel, libpng-devel, libtiff-devel, flex
 BuildRequires: libX11-devel, python, jasper-devel
@@ -88,6 +89,7 @@ netpbm-progs.  You'll also need to install the netpbm package.
 %patch16 -p1 -b .ppmfadeusage
 %patch17 -p1 -b .fiasco-overflow
 %patch18 -p1 -b .lz
+%patch19 -p1 -b .pnmmmontagefix
 
 sed -i 's/STRIPFLAG = -s/STRIPFLAG =/g' config.mk.in
 
@@ -188,13 +190,15 @@ rm -rf $RPM_BUILD_ROOT/usr/config_template
 # Don't ship the static library
 rm -f $RPM_BUILD_ROOT/%{_libdir}/lib*.a
 
-# remove/symlink obsolete utilities
+# remove/symlink/substitute obsolete utilities
 pushd $RPM_BUILD_ROOT%{_bindir}
 rm -f pgmtopbm pnmcomp
-ln -s pamditherbw pgmtopbm
 ln -s pamcomp pnmcomp
+echo -e '#!/bin/sh\npamditherbw $@ | pamtopnm\n' > pgmtopbm
+chmod 0755 pgmtopbm
 popd
 
+
 %clean
 rm -rf $RPM_BUILD_ROOT
 
@@ -222,6 +226,11 @@ rm -rf $RPM_BUILD_ROOT
 %{_datadir}/netpbm/
 
 %changelog
+* Wed Mar 17 2010 Jindrich Novy <jnovy@redhat.com> 10.47.10-2
+- pgmtopbm should generate PBM, not PAM file
+- forwardport pnmmontage from 10.35 to make it work
+- fix pamstretch-gen
+
 * Wed Feb 24 2010 Jindrich Novy <jnovy@redhat.com> 10.47.10-1
 - update to 10.47.10
 - fixes crash in pnmhistmap