about summary refs log tree commit diff
path: root/lib/util
diff options
context:
space:
mode:
Diffstat (limited to 'lib/util')
-rw-r--r--lib/util/Makefile14
-rw-r--r--lib/util/bitarith.h42
-rw-r--r--lib/util/floatcode.h185
-rw-r--r--lib/util/intcode.h228
-rw-r--r--lib/util/mallocvar.h19
-rw-r--r--lib/util/nsleep.c27
-rw-r--r--lib/util/nsleep.h7
-rw-r--r--lib/util/nstring.c79
-rw-r--r--lib/util/nstring.h82
-rw-r--r--lib/util/pm_c_util.h10
-rw-r--r--lib/util/shhopt.c124
-rw-r--r--lib/util/shhopt.h19
-rw-r--r--lib/util/vasprintf.c58
-rw-r--r--lib/util/wordaccess.h31
-rw-r--r--lib/util/wordaccess_64_le.h46
-rw-r--r--lib/util/wordaccess_gcc3_be.h17
-rw-r--r--lib/util/wordaccess_gcc3_le.h54
-rw-r--r--lib/util/wordaccess_generic.h74
-rw-r--r--lib/util/wordintclz.h93
19 files changed, 933 insertions, 276 deletions
diff --git a/lib/util/Makefile b/lib/util/Makefile
index 8f461f28..8b3fa1c1 100644
--- a/lib/util/Makefile
+++ b/lib/util/Makefile
@@ -5,25 +5,23 @@ endif
 SUBDIR = lib/util
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
-
-INCLUDES = -I $(BUILDDIR) -I $(SRCDIR)/$(SUBDIR)/..
+include $(BUILDDIR)/config.mk
 
 # nstring is required for asprintf(), etc.  Also some systems don't have
 # snprintf(), e.g. Solaris 2.5.1.  2002.03.29.
-UTILOBJECTS = shhopt.o nstring.o filename.o
+UTILOBJECTS = shhopt.o nstring.o vasprintf.o filename.o nsleep.o
 
 MERGE_OBJECTS =
 
 all: $(UTILOBJECTS)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
+
+INCLUDES = -I$(SRCDIR)/$(SUBDIR) -I. -Iimportinc
 
 $(UTILOBJECTS):%.o:%.c importinc
-	$(CC) -c $(INCLUDES) -DNDEBUG $(CFLAGS) $(CFLAGS_SHLIB) \
+	$(CC) -c $(INCLUDES) -DNDEBUG $(CPPFLAGS) $(CFLAGS) $(CFLAGS_SHLIB) \
 	  $(CFLAGS_PERSONAL) $(CADD) -o $@ $<
 
 testnstring: test.c nstring.h nstring.o
 	$(CC) $(CFLAGS) $(CADD) -o $@ nstring.o $<
-
-include Makefile.depend
diff --git a/lib/util/bitarith.h b/lib/util/bitarith.h
new file mode 100644
index 00000000..4ed6c4c3
--- /dev/null
+++ b/lib/util/bitarith.h
@@ -0,0 +1,42 @@
+#ifndef BITARITH_H_INCLUDED
+#define BITARITH_H_INCLUDED
+
+#include "pm_config.h"
+
+static __inline__ unsigned char
+pm_byteLeftBits(unsigned char const x,
+                unsigned int  const n) {
+/*----------------------------------------------------------------------------
+  Clear rightmost (8-n) bits, retain leftmost (=high) n bits.
+
+  Return arbitrary value if n > 8.
+-----------------------------------------------------------------------------*/
+    unsigned char retval;
+
+    retval = x;
+    retval >>= (8-n);
+    retval <<= (8-n);
+
+    return retval;
+}
+
+
+
+static __inline__ unsigned char
+pm_byteRightBits(unsigned char const x,
+                 unsigned int  const n){
+/*----------------------------------------------------------------------------
+  Return rightmost (=low) n bits of x.
+
+  Return arbitrary value if n > 8.
+-----------------------------------------------------------------------------*/
+    unsigned char retval;
+
+    retval = x;
+    retval <<= (8-n);
+    retval >>= (8-n);
+
+    return retval;
+}
+
+#endif
diff --git a/lib/util/floatcode.h b/lib/util/floatcode.h
new file mode 100644
index 00000000..23c57e9b
--- /dev/null
+++ b/lib/util/floatcode.h
@@ -0,0 +1,185 @@
+#ifndef FLOATCODE_H_INCLUDED
+#define FLOATCODE_H_INCLUDED
+
+#include "pm_config.h"  /* BYTE_ORDER */
+
+unsigned int const pm_byteOrder = BYTE_ORDER;
+
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   This is a big-endian representation of a 32 bit floating point number.
+   I.e. bytes[0] contains the sign bit, etc.
+
+   On a big-endian machines, this is bit for bit identical to 'float'.
+   On a little-endian machine, it isn't.
+
+   This is an important data type because decent file formats use
+   big-endian -- they don't care if some CPU happens to use some other
+   code for its own work.
+-----------------------------------------------------------------------------*/
+    unsigned char bytes[4];
+} pm_bigendFloat;
+
+
+static __inline__ float
+pm_floatFromBigendFloat(pm_bigendFloat const arg) {
+
+    float retval;
+
+    switch (pm_byteOrder) {
+    case BIG_ENDIAN: {
+        union {
+            pm_bigendFloat bigend;
+            float native;
+        } converter;
+        
+        converter.bigend = arg;
+        
+        retval = converter.native;
+    }; break;
+    case LITTLE_ENDIAN: {
+        union {
+            unsigned char bytes[4];
+            float native;
+        } converter;
+
+        converter.bytes[0] = arg.bytes[3];
+        converter.bytes[1] = arg.bytes[2];
+        converter.bytes[2] = arg.bytes[1];
+        converter.bytes[3] = arg.bytes[0];
+
+        retval = converter.native;
+    } break;
+    }
+    return retval;
+}
+
+
+
+static __inline__ pm_bigendFloat
+pm_bigendFloatFromFloat(float const arg) {
+
+    pm_bigendFloat retval;
+
+    switch (pm_byteOrder) {
+    case BIG_ENDIAN: {
+        union {
+            pm_bigendFloat bigend;
+            float native;
+        } converter;
+        
+        converter.native = arg;
+
+        retval = converter.bigend;
+    } break;
+    case LITTLE_ENDIAN: {
+        union {
+            unsigned char bytes[4];
+            float native;
+        } converter;
+
+        converter.native = arg;
+
+        retval.bytes[0] = converter.bytes[3];
+        retval.bytes[1] = converter.bytes[2];
+        retval.bytes[2] = converter.bytes[1];
+        retval.bytes[3] = converter.bytes[0];
+    } break;
+    }
+    return retval;
+}
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   This is a big-endian representation of a 64 bit floating point number.
+   I.e. bytes[0] contains the sign bit, etc.
+
+   On a big-endian machines, this is bit for bit identical to 'float'.
+   On a little-endian machine, it isn't.
+
+   This is an important data type because decent file formats use
+   big-endian -- they don't care if some CPU happens to use some other
+   code for its own work.
+-----------------------------------------------------------------------------*/
+    unsigned char bytes[8];
+} pm_bigendDouble;
+
+
+static __inline__ double
+pm_doubleFromBigendDouble(pm_bigendDouble const arg) {
+
+    double retval;
+
+    switch (pm_byteOrder) {
+    case BIG_ENDIAN: {
+        union {
+            pm_bigendDouble bigend;
+            double native;
+        } converter;
+        
+        converter.bigend = arg;
+        
+        retval = converter.native;
+    }; break;
+    case LITTLE_ENDIAN: {
+        union {
+            unsigned char bytes[4];
+            double native;
+        } converter;
+
+        converter.bytes[0] = arg.bytes[7];
+        converter.bytes[1] = arg.bytes[6];
+        converter.bytes[2] = arg.bytes[5];
+        converter.bytes[3] = arg.bytes[4];
+        converter.bytes[4] = arg.bytes[3];
+        converter.bytes[5] = arg.bytes[2];
+        converter.bytes[6] = arg.bytes[1];
+        converter.bytes[7] = arg.bytes[0];
+
+        retval = converter.native;
+    } break;
+    }
+    return retval;
+}
+
+
+
+static __inline__ pm_bigendDouble
+pm_bigendDoubleFromDouble(double const arg) {
+
+    pm_bigendDouble retval;
+
+    switch (pm_byteOrder) {
+    case BIG_ENDIAN: {
+        union {
+            pm_bigendDouble bigend;
+            double native;
+        } converter;
+        
+        converter.native = arg;
+
+        retval = converter.bigend;
+    } break;
+    case LITTLE_ENDIAN: {
+        union {
+            unsigned char bytes[4];
+            double native;
+        } converter;
+
+        converter.native = arg;
+
+        retval.bytes[0] = converter.bytes[7];
+        retval.bytes[1] = converter.bytes[6];
+        retval.bytes[2] = converter.bytes[5];
+        retval.bytes[3] = converter.bytes[4];
+        retval.bytes[4] = converter.bytes[3];
+        retval.bytes[5] = converter.bytes[2];
+        retval.bytes[6] = converter.bytes[1];
+        retval.bytes[7] = converter.bytes[0];
+    } break;
+    }
+    return retval;
+}
+
+#endif
diff --git a/lib/util/intcode.h b/lib/util/intcode.h
index 4d9c83aa..dd42f669 100644
--- a/lib/util/intcode.h
+++ b/lib/util/intcode.h
@@ -1,7 +1,78 @@
 #ifndef INTCODE_H_INCLUDED
 #define INTCODE_H_INCLUDED
 
-#include "pm_config.h"  /* For uint32_t, BYTE_ORDER */
+#include "pm_config.h"  /* For uint32_t, BYTE_ORDER, HAVE_INT64 */
+
+static unsigned int const pm_byteOrder = BYTE_ORDER;
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   This is a big-endian representation of a 16 bit integer.  I.e.
+   bytes[0] is the most significant 8 bits; bytes[1] is the least
+   significant 8 bits of the number in pure binary.
+
+   On a big-endian machines, this is bit for bit identical to uint16_t.
+   On a little-endian machine, it isn't.
+
+   This is an important data type because decent file formats use
+   big-endian -- they don't care if some CPU happens to use some other
+   code for its own work.
+-----------------------------------------------------------------------------*/
+    unsigned char bytes[2];
+} bigend16;
+
+
+static __inline__ uint16_t
+pm_uintFromBigend16(bigend16 const arg) {
+
+    uint16_t retval;
+
+    switch (pm_byteOrder) {
+    case BIG_ENDIAN: {
+        union {
+            bigend16 bigend;
+            uint16_t native;
+        } converter;
+        converter.bigend = arg;
+        retval = converter.native;
+    } break;
+
+    default: {
+        retval =
+            (arg.bytes[0] << 8) |
+            (arg.bytes[1] << 0);
+    }
+    }
+    return retval;
+}
+
+
+
+static __inline__ bigend16
+pm_bigendFromUint16(uint16_t const arg) {
+
+    bigend16 retval;
+
+    switch (pm_byteOrder) {
+    case BIG_ENDIAN: {
+        union {
+            bigend16 bigend;
+            uint16_t native;
+        } converter;
+        converter.native = arg;
+        retval = converter.bigend;
+    } break;
+
+    default: {
+        uint16_t shift;
+        shift = arg;
+        retval.bytes[1] = shift;  /* Takes lower 8 bits */
+        shift >>= 8;
+        retval.bytes[0] = shift;  /* Takes lower 8 bits */
+    }
+    }
+    return retval;
+}
 
 typedef struct {
 /*----------------------------------------------------------------------------
@@ -20,9 +91,6 @@ typedef struct {
 } bigend32;
 
 
-unsigned int const pm_byteOrder = BYTE_ORDER;
-
-
 static __inline__ uint32_t
 pm_uintFromBigend32(bigend32 const arg) {
 
@@ -34,19 +102,30 @@ pm_uintFromBigend32(bigend32 const arg) {
             bigend32 bigend;
             uint32_t native;
         } converter;
-        
         converter.bigend = arg;
-        
         retval = converter.native;
-    }; break;
+    } break;
+
+#if HAVE_GCC_BSWAP
     case LITTLE_ENDIAN: {
+        /* Use GCC built-in */  
+        union {
+            bigend32 bigend;
+            uint32_t native;
+        } converter;
+        converter.bigend = arg;
+        retval = __builtin_bswap32(converter.native);
+    } break;
+#endif
+    
+    default:
         retval =
             (arg.bytes[0] << 24) |
             (arg.bytes[1] << 16) |
             (arg.bytes[2] <<  8) |
             (arg.bytes[3] <<  0);
-    } break;
     }
+
     return retval;
 }
 
@@ -63,12 +142,23 @@ pm_bigendFromUint32(uint32_t const arg) {
             bigend32 bigend;
             uint32_t native;
         } converter;
-        
         converter.native = arg;
-
         retval = converter.bigend;
     } break;
+
+#if HAVE_GCC_BSWAP    
     case LITTLE_ENDIAN: {
+        /* Use GCC built-in */  
+        union {
+            bigend32 bigend;
+            uint32_t native;
+        } converter;
+        converter.native = __builtin_bswap32(arg);
+        retval = converter.bigend;
+    } break;
+#endif    
+
+    default: {
         uint32_t shift;
         shift = arg;
         retval.bytes[3] = shift;  /* Takes lower 8 bits */
@@ -78,9 +168,127 @@ pm_bigendFromUint32(uint32_t const arg) {
         retval.bytes[1] = shift;  /* Takes lower 8 bits */
         shift >>= 8;
         retval.bytes[0] = shift;  /* Takes lower 8 bits */
+    }
+    }
+    return retval;
+}
+
+
+#if HAVE_INT64
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   This is a big-endian representation of a 64 bit integer.  I.e.
+   bytes[0] is the most significant 8 bits; bytes[7] is the least
+   significant 8 bits of the number in pure binary.
+
+   On a big-endian machines, this is bit for bit identical to uint64_t.
+   On a little-endian machine, it isn't.
+
+   This is an important data type because decent file formats use
+   big-endian -- they don't care if some CPU happens to use some other
+   code for its own work.
+
+   uint64_t is supported only when available.
+-----------------------------------------------------------------------------*/
+    unsigned char bytes[8];
+} bigend64;
+
+
+static __inline__ uint64_t
+pm_uintFromBigend64(bigend64 const arg) {
+
+    uint64_t retval;
+
+    switch (pm_byteOrder) {
+    case BIG_ENDIAN: {
+        union {
+            bigend64 bigend;
+            uint64_t native;
+        } converter;
+        converter.bigend = arg;
+        retval = converter.native;
     } break;
+
+#if HAVE_GCC_BSWAP    
+    case LITTLE_ENDIAN: {
+        /* Use GCC built-in */  
+        union {
+            bigend64 bigend;
+            uint64_t native;
+        } converter;
+        converter.bigend = arg;
+        retval = __builtin_bswap64(converter.native);
+    } break;
+#endif
+    default:
+        retval =
+            ((uint64_t)arg.bytes[0] << 56) | ((uint64_t)arg.bytes[1] << 48) |
+            ((uint64_t)arg.bytes[2] << 40) | ((uint64_t)arg.bytes[3] << 32) |
+            ((uint64_t)arg.bytes[4] << 24) | ((uint64_t)arg.bytes[5] << 16) |
+            ((uint64_t)arg.bytes[6] <<  8) | ((uint64_t)arg.bytes[7] <<  0);
     }
     return retval;
 }
 
+
+
+static __inline__ bigend64
+pm_bigendFromUint64(uint64_t const arg) {
+
+    bigend64 retval;
+
+    switch (pm_byteOrder) {
+    case BIG_ENDIAN: {
+        union {
+            bigend64 bigend;
+            uint64_t native;
+        } converter;
+        converter.native = arg;
+        retval = converter.bigend;
+    } break;
+
+#if HAVE_GCC_BSWAP
+    case LITTLE_ENDIAN: {
+
+        /* Use GCC built-in */  
+        union {
+            bigend64 bigend;
+            uint64_t native;
+        } converter;
+        converter.native = __builtin_bswap64(arg);
+        retval = converter.bigend;
+    } break;
 #endif
+    
+    default: {
+        uint64_t shift;
+        shift = arg;
+        retval.bytes[7] = shift;  /* Takes lower 8 bits */
+        shift >>= 8;
+        retval.bytes[6] = shift;  /* Takes lower 8 bits */
+        shift >>= 8;
+        retval.bytes[5] = shift;  /* Takes lower 8 bits */
+        shift >>= 8;
+        retval.bytes[4] = shift;  /* Takes lower 8 bits */
+        shift >>= 8;
+        retval.bytes[3] = shift;  /* Takes lower 8 bits */
+        shift >>= 8;
+        retval.bytes[2] = shift;  /* Takes lower 8 bits */
+        shift >>= 8;
+        retval.bytes[1] = shift;  /* Takes lower 8 bits */
+        shift >>= 8;
+        retval.bytes[0] = shift;  /* Takes lower 8 bits */
+    }
+    }
+    return retval;
+}
+
+#endif /* HAVE_INT64 */
+
+#endif
+
+
+
+
+
diff --git a/lib/util/mallocvar.h b/lib/util/mallocvar.h
index a26d007b..1f2be127 100644
--- a/lib/util/mallocvar.h
+++ b/lib/util/mallocvar.h
@@ -57,11 +57,22 @@ static __inline__ void
 reallocProduct(void **      const blockP,
                unsigned int const factor1,
                unsigned int const factor2) {
+
+    void * const oldBlockP = *blockP;
+
+    void * newBlockP;
     
     if (UINT_MAX / factor2 < factor1) 
-        *blockP = NULL;
+        newBlockP = NULL;
     else 
-        *blockP = realloc(*blockP, factor1 * factor2); 
+        newBlockP = realloc(oldBlockP, factor1 * factor2); 
+
+    if (newBlockP)
+        *blockP = newBlockP;
+    else {
+        free(oldBlockP);
+        *blockP = NULL;
+    }
 }
 
 
@@ -72,10 +83,12 @@ reallocProduct(void **      const blockP,
     arrayName = array; \
 } while (0)
 
-#define REALLOCARRAY(arrayName, nElements) { \
+#define REALLOCARRAY(arrayName, nElements) do { \
     void * array; \
     array = arrayName; \
     reallocProduct(&array, nElements, sizeof(arrayName[0])); \
+    if (!array) \
+        free(arrayName); \
     arrayName = array; \
 } while (0)
 
diff --git a/lib/util/nsleep.c b/lib/util/nsleep.c
new file mode 100644
index 00000000..943b8c77
--- /dev/null
+++ b/lib/util/nsleep.c
@@ -0,0 +1,27 @@
+#ifdef WIN32
+  #include <windows.h>
+  #include <process.h>
+#else
+  #include <unistd.h>
+#endif
+
+#include "nsleep.h"
+
+
+
+void
+sleepN(unsigned int const milliseconds) {
+
+#ifdef WIN32
+    SleepEx(milliseconds, TRUE);
+#else
+
+    /* We could use usleep() here if millisecond resolution is really
+       important, but since Netpbm has no need for it today, we don't
+       want to deal with the possibility that usleep() doesn't exist.
+       08.08.01.
+    */
+
+    sleep((milliseconds + 999)/1000);
+#endif
+}
diff --git a/lib/util/nsleep.h b/lib/util/nsleep.h
new file mode 100644
index 00000000..372b8008
--- /dev/null
+++ b/lib/util/nsleep.h
@@ -0,0 +1,7 @@
+#ifndef NSLEEP_H_INCLUDED
+#define NSLEEP_H_INCLUDED
+
+void
+sleepN(unsigned int const milliseconds);
+
+#endif
diff --git a/lib/util/nstring.c b/lib/util/nstring.c
index 66d636d5..8842aa05 100644
--- a/lib/util/nstring.c
+++ b/lib/util/nstring.c
@@ -740,15 +740,6 @@ const char * const strsol = "NO MEMORY TO CREATE STRING!";
 
 
 
-/* We would like to have vasprintfN(), but it is difficult because you
-   can't run through a va_list twice, which we would want to do: once
-   to measure the length; once actually to build the string.  On some
-   machines, you can simply make two copies of the va_list variable in
-   normal C fashion, but on others you need va_copy, which is a
-   relatively recent invention.  In particular, the simple va_list copy
-   failed on an AMD64 Gcc Linux system in March 2006.
-*/
-
 void PM_GNU_PRINTF_ATTR(2,3)
 asprintfN(const char ** const resultP,
           const char *  const fmt, 
@@ -887,20 +878,80 @@ stripeq(const char * const comparand,
 
 
 
-const char *
-memmemN(const char * const haystack,
+const void *
+memmemN(const void * const haystackArg,
         size_t       const haystacklen,
-        const char * const needle,
+        const void * const needleArg,
         size_t       const needlelen) {
 
+    const unsigned char * const haystack = haystackArg;
+    const unsigned char * const needle   = needleArg;
+
     /* This does the same as the function of the same name in the GNU
        C library
     */
-    const char * p;
+    const unsigned char * p;
 
     for (p = haystack; p <= haystack + haystacklen - needlelen; ++p)
-        if (MEMEQ(p, needle, needlelen))
+        if (memeq(p, needle, needlelen))
             return p;
 
     return NULL;
 }
+
+
+
+bool
+strishex(const char * const subject) {
+
+    bool retval;
+    unsigned int i;
+
+    retval = TRUE;  /* initial assumption */
+
+    for (i = 0; i < strlen(subject); ++i)
+        if (!ISXDIGIT(subject[i]))
+            retval = FALSE;
+
+    return retval;
+}
+
+
+
+void
+interpret_uint(const char *   const string,
+               unsigned int * const valueP,
+               const char **  const errorP) {
+
+    if (string[0] == '\0')
+        asprintfN(errorP, "Null string.");
+    else {
+        /* strtoul() does a bizarre thing where if the number is out
+           of range, it returns a clamped value but tells you about it
+           by setting errno = ERANGE.  If it is not out of range,
+           strtoul() leaves errno alone.
+        */
+        char * tail;
+        unsigned long ulongValue;
+        
+        errno = 0;  /* So we can tell if strtoul() overflowed */
+
+        ulongValue = strtoul(string, &tail, 10);
+
+        if (tail[0] != '\0')
+            asprintfN(errorP, "Non-digit stuff in string: %s", tail);
+        else if (errno == ERANGE)
+            asprintfN(errorP, "Number too large");
+        else if (ulongValue > UINT_MAX)
+            asprintfN(errorP, "Number too large");
+        else if (string[0] == '-')
+            asprintfN(errorP, "Negative number");
+            /* Sleazy code; string may have leading spaces. */
+        else {
+            *valueP = ulongValue;
+            *errorP = NULL;
+        }
+    }
+}
+
+
diff --git a/lib/util/nstring.h b/lib/util/nstring.h
index 9ed20051..53f1e4c0 100644
--- a/lib/util/nstring.h
+++ b/lib/util/nstring.h
@@ -5,6 +5,7 @@
 #include <string.h>
 #include <ctype.h>
 
+#include "pm_c_util.h"
 #include "pm.h"  /* For PM_GNU_PRINTF_ATTR, __inline__ */
 
 #ifdef __cplusplus
@@ -14,7 +15,7 @@ extern "C" {
 } /* to fake out automatic code indenters */
 #endif
 
-/* Here is are string functions that respect the size of the array
+/* Here are string functions that respect the size of the array
    into which you are copying -- E.g. STRSCPY truncates the source string as
    required so that it fits, with the terminating null, in the destination
    array.
@@ -25,22 +26,18 @@ extern "C" {
 	(strncmp((A), (B), sizeof(A)))
 #define STRSCAT(A,B) \
     (strncpy(A+strlen(A), B, sizeof(A)-strlen(A)), *((A)+sizeof(A)-1) = '\0')
-
-#define STREQ(A, B) \
-    (strcmp((A), (B)) == 0)
-#define STRNEQ(A, B, C) \
-    (strncmp((A), (B), (C)) == 0)
-#define STRCASEEQ(A, B) \
-    (strcasecmp((A), (B)) == 0)
-#define STRNCASEEQ(A, B, C) \
-    (strncasecmp((A), (B), (C)) == 0)
 #define STRSEQ(A, B) \
-	(strncmp((A), (B), sizeof(A)) == 0)
+	(strneq((A), (B), sizeof(A)))
+
+#define MEMEQ(a,b,c) (memcmp(a, b, c) == 0)
+
+#define MEMSEQ(a,b) (memeq(a, b, sizeof(*(a))) == 0)
+
+#define MEMSSET(a,b) (memset(a, b, sizeof(*(a))))
 
-#define MEMEQ(A, B, C) \
-    (memcmp((A), (B), (C)) == 0)
-#define MEMSZERO(A) \
-    bzero((A), sizeof(A))
+#define MEMSCPY(a,b) (memcpy(a, b, sizeof(*(a))))
+
+#define MEMSZERO(a) (MEMSSET(a, 0))
 
 
 static __inline__ int
@@ -50,6 +47,42 @@ streq(const char * const comparand,
     return strcmp(comparand, comparator) == 0;
 }
 
+static __inline__ int
+strneq(const char * const comparand,
+       const char * const comparator,
+       size_t       const size) {
+
+    return strncmp(comparand, comparator, size) == 0;
+}
+
+static __inline__ int
+memeq(const void * const comparand,
+      const void * const comparator,
+      size_t       const size) {
+    
+    return memcmp(comparand, comparator, size) == 0;
+}
+
+/* The Standard C Library may not declare strcasecmp() if the including
+   source file doesn't request BSD functions, with _BSD_SOURCE.  So
+   we don't define functions that use strcasecmp() in that case.
+*/
+#ifdef _BSD_SOURCE
+static __inline__ int
+strcaseeq(const char * const comparand,
+          const char * const comparator) {
+
+    return strcasecmp(comparand, comparator) == 0;
+}
+
+static __inline__ int
+strncaseeq(const char * const comparand,
+           const char * const comparator,
+           size_t       const size) {
+
+    return strncasecmp(comparand, comparator, size) == 0;
+}
+#endif
 
 
 /* The standard C library routines isdigit(), for some weird 
@@ -134,6 +167,11 @@ asprintfN(const char ** const resultP,
           const char *  const fmt,
           ...) PM_GNU_PRINTF_ATTR(2,3);
 
+void
+vasprintfN(const char ** const resultP,
+           const char *  const format,
+           va_list             args);
+
 void 
 strfree(const char * const string);
 
@@ -144,12 +182,20 @@ int
 stripeq(const char * const comparand,
         const char * const comparator);
 
-const char *
-memmemN(const char * const haystack,
+const void *
+memmemN(const void * const haystackArg,
         size_t       const haystacklen,
-        const char * const needle,
+        const void * const needleArg,
         size_t       const needlelen);
 
+bool
+strishex(const char * const subject);
+
+void
+interpret_uint(const char *   const string,
+               unsigned int * const valueP,
+               const char **  const errorP);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/util/pm_c_util.h b/lib/util/pm_c_util.h
index f21a2f82..07913f30 100644
--- a/lib/util/pm_c_util.h
+++ b/lib/util/pm_c_util.h
@@ -15,6 +15,16 @@
 #define ROUND(X) (((X) >= 0) ? (int)((X)+0.5) : (int)((X)-0.5))
 #undef ROUNDU
 #define ROUNDU(X) ((unsigned int)((X)+0.5))
+
+/* ROUNDUP rounds up to a specified multiple.  E.g. ROUNDUP(22, 8) == 24 */
+
+#undef ROUNDUP
+#define ROUNDUP(X,M) (((X)+(M)-1)/(M)*(M))
+#undef ROUNDDN
+#define ROUNDDN(X,M) ((X)/(M)*(M))
+
+#define ROUNDDIV(DIVIDEND,DIVISOR) (((DIVIDEND) + (DIVISOR)/2)/(DIVISOR))
+
 #undef SQR
 #define SQR(a) ((a)*(a))
 
diff --git a/lib/util/shhopt.c b/lib/util/shhopt.c
index 7722b5d5..718186fa 100644
--- a/lib/util/shhopt.c
+++ b/lib/util/shhopt.c
@@ -89,9 +89,13 @@ optStructCount(const optEntry opt[])
     return ret;
 }
 
+
+
+static int
+optMatch(optEntry     const opt[],
+         const char * const s,
+         int          const lng) {
 /*------------------------------------------------------------------------
- |  NAME          optMatch
- |
  |  FUNCTION      Find a matching option.
  |
  |  INPUT         opt     array of possible options.
@@ -103,35 +107,39 @@ optStructCount(const optEntry opt[])
  |  DESCRIPTION   Short options are matched from the first character in
  |                the given string.
  */
-static int
-optMatch(const optEntry opt[], const char *s, int lng)
-{
-    int        nopt, q, matchlen = 0;
-    const char *p;
 
-    nopt = optStructCount(opt);
+    unsigned int const nopt = optStructCount(opt);
+
+    unsigned int q;
+    unsigned int matchlen;
+    const char * p;
+
+    matchlen = 0;  /* initial value */
+
     if (lng) {
         if ((p = strchr(s, '=')) != NULL)
             matchlen = p - s;
         else
             matchlen = strlen(s);
     }
-    for (q = 0; q < nopt; q++) {
+    for (q = 0; q < nopt; ++q) {
         if (lng) {
-            if (!opt[q].longName)
-                continue;
-            if (strncmp(s, opt[q].longName, matchlen) == 0)
-                return q;
+            if (opt[q].longName) {
+                if (strncmp(s, opt[q].longName, matchlen) == 0)
+                    return q;
+            }
         } else {
-            if (!opt[q].shortName)
-                continue;
-            if (*s == opt[q].shortName)
-                return q;
+            if (opt[q].shortName) {
+                if (s[0] == opt[q].shortName)
+                    return q;
+            }
         }
     }
     return -1;
 }
 
+
+
 /*------------------------------------------------------------------------
  |  NAME          optString
  |
@@ -422,13 +430,17 @@ optExecute(optEntry  const opt, char *arg, int lng)
     case OPT_UINT:
     case OPT_ULONG: {
         unsigned long tmp;
-        char *e;
+        char * tailPtr;
         
         if (arg == NULL)
             optFatal("internal error: optExecute() called with NULL argument "
                      "'%s'", optString(opt, lng));
-        tmp = strtoul(arg, &e, 10);
-        if (*e)
+
+        if (arg[0] == '-' || arg[1] == '+')
+            optFatal("unsigned number '%s' has a sign ('%c')",
+                     arg, arg[0]);
+        tmp = strtoul(arg, &tailPtr, 10);
+        if (*tailPtr)
             optFatal("invalid number `%s'", arg);
         if (errno == ERANGE
             || (opt.type == OPT_UINT && tmp > UINT_MAX))
@@ -643,7 +655,15 @@ static void
 parse_short_option_token(char *argv[], const int argc, const int ai,
                          const optEntry opt_table[], 
                          int * const tokens_consumed_p) {
+/*----------------------------------------------------------------------------
+   Parse a cluster of short options, e.g. -walne .
+
+   The last option in the cluster might take an argument, and we parse
+   that as well.  e.g. -cf myfile or -cfmyfile .
 
+   argv[] and argc describe the whole program argument set.  'ai' is the
+   index of the argument that is the short option cluster.
+-----------------------------------------------------------------------------*/
     char *o;  /* A short option character */
     char *arg;
     int mi;   /* index into option table */
@@ -685,11 +705,60 @@ parse_short_option_token(char *argv[], const int argc, const int ai,
 
 
 static void
-parse_long_option(char *argv[], const int argc, const int ai,
-                  const int namepos,
-                  const optEntry opt_table[], 
-                  int * const tokens_consumed_p) {
+fatalUnrecognizedLongOption(const char * const optionName,
+                            optEntry     const optTable[]) {
+
+    unsigned int const nopt = optStructCount(optTable);
+
+    unsigned int q;
+
+    char optList[1024];
+
+    optList[0] = '\0';  /* initial value */
+
+    for (q = 0;
+         q < nopt && strlen(optList) + 1 <= sizeof(optList);
+         ++q) {
+
+        const optEntry * const optEntryP = &optTable[q];
+        const char * entry;
+
+        if (optEntryP->longName)
+            asprintfN(&entry, "-%s ", optEntryP->longName);
+        else
+            asprintfN(&entry, "-%c ", optEntryP->shortName);
+
+        strncat(optList, entry, sizeof(optList) - strlen(optList) - 1);
+
+        strfree(entry);
+
+        if (strlen(optList) + 1 == sizeof(optList)) {
+            /* Buffer is full.  Overwrite end of list with ellipsis */
+            strcpy(&optList[sizeof(optList) - 4], "...");
+        }
+    }
+    optFatal("unrecognized option '%s'.  Recognized options are: %s",
+             optionName, optList);
+}
+
+
+
+static void
+parse_long_option(char *   const argv[],
+                  int      const argc,
+                  int      const ai,
+                  int      const namepos,
+                  optEntry const opt_table[], 
+                  int *    const tokens_consumed_p) {
+/*----------------------------------------------------------------------------
+   Parse a long option, e.g. -verbose or --verbose.
+
+   The option might take an argument, and we parse
+   that as well.  e.g. -file=myfile or -file myfile .
 
+   argv[] and argc describe the whole program argument set.  'ai' is the
+   index of the argument that is the long option.
+-----------------------------------------------------------------------------*/
     char *equals_arg;
       /* The argument of an option, included in the same token, after a
          "=".  NULL if no "=" in the token.
@@ -703,8 +772,8 @@ parse_long_option(char *argv[], const int argc, const int ai,
     *tokens_consumed_p = 1;  /* initial assumption */
     /* find matching option */
     if ((mi = optMatch(opt_table, &argv[ai][namepos], 1)) < 0)
-        optFatal("unrecognized option `%s'", argv[ai]);
-            
+        fatalUnrecognizedLongOption(argv[ai], opt_table);
+
     /* possibly locate the argument to this option. */
     { 
         char *p;
@@ -727,7 +796,8 @@ parse_long_option(char *argv[], const int argc, const int ai,
         }
     } else {
         if (equals_arg)
-            optFatal("option `%s' doesn't allow an argument",
+            optFatal("option `%s' doesn't allow an argument, but you "
+                     "have specified it in the form name=value",
                      optString(opt_table[mi], 1));
         else 
             arg = NULL;
diff --git a/lib/util/shhopt.h b/lib/util/shhopt.h
index 0c3c3ba4..99096a76 100644
--- a/lib/util/shhopt.h
+++ b/lib/util/shhopt.h
@@ -1,4 +1,4 @@
-/*==============================================================================
+/*=============================================================================
 HERE IS AN EXAMPLE OF THE USE OF SHHOPT:
 
 
@@ -6,6 +6,8 @@ HERE IS AN EXAMPLE OF THE USE OF SHHOPT:
 int 
 main ( int argc, char **argv ) {
 
+    // initial values here are just to demonstrate what gets set and
+    // what doesn't by the code below.
     int help_flag = 7;
     unsigned int help_spec =7;
     unsigned int height_spec =7;
@@ -186,12 +188,13 @@ typedef struct {
 
 /* OPTENT3 is the same as OPTENTRY except that it also sets the "specified"
    element of the table entry (so it assumes OPTION_DEF is a table of
-   optEntry instead of optStruct).
+   optEntry instead of optStruct).  It sets it to the number of times that
+   the option appears in the command line.
 
    Here is an example:
 
        unsigned int option_def_index = 0;
-       optEntry *option_def = malloc(100*sizeof(optEntry));
+       MALLOCARRAY_NOFAIL(option_def, 100);
        OPTENT3('h', "help",     OPT_FLAG, &help_flag, 0);
        OPTENT3(0,   "alphaout", OPT_STRING, &alpha_filename, 0);
 */
@@ -229,14 +232,4 @@ optDestroyNameValueList(struct optNameValue * const list);
 }
 #endif
 
-/* Here's a hack to help us introduce pm_c_util.h.  That should be
-   #included in nearly every Netpbm program, but we're too lazy to insert
-   it into hundreds of files right now.  But shhopt.h is included into
-   most of those files, so we #include it here!
-
-   Before 2005.12.03, the stuff that is now in pm_c_util.h was in pm.h,
-   but that's a bad place for it because pm.h is an external header file.
-*/
-#include "pm_c_util.h"
-
 #endif
diff --git a/lib/util/vasprintf.c b/lib/util/vasprintf.c
new file mode 100644
index 00000000..47b4079d
--- /dev/null
+++ b/lib/util/vasprintf.c
@@ -0,0 +1,58 @@
+#define _GNU_SOURCE
+   /* Due to conditional compilation, this is GNU source only if the C library
+      is GNU.
+   */
+#include <stdlib.h>
+#include <string.h>
+
+#include "pm_config.h"
+#include "nstring.h"
+
+
+
+void
+vasprintfN(const char ** const resultP,
+           const char *  const format,
+           va_list             varargs) {
+
+    char * result;
+
+#if HAVE_VASPRINTF
+    int rc;
+
+    rc = vasprintf(&result, format, varargs);
+
+    if (rc < 0)
+        *resultP = strsol;
+    else
+        *resultP = result;
+#else
+    /* We have a big compromise here.  To do this right, without a
+       huge amount of work, we need to go through the variable
+       arguments twice: once to determine how much memory to allocate,
+       and once to format the string.  On some machines, you can
+       simply make two copies of the va_list variable in normal C
+       fashion, but on others you need va_copy, which is a relatively
+       recent invention.  In particular, the simple va_list copy
+       failed on an AMD64 Gcc Linux system in March 2006.  
+
+       So instead, we just allocate 4K and truncate or waste as
+       necessary.
+    */
+    size_t const allocSize = 4096;
+    result = malloc(allocSize);
+    
+    if (result == NULL)
+        *resultP = strsol;
+    else {
+        size_t realLen;
+
+        vsnprintfN(result, allocSize, format, varargs, &realLen);
+        
+        if (realLen >= allocSize)
+            strcpy(result + allocSize - 15, "<<<TRUNCATED");
+
+        *resultP = result;
+    }
+#endif
+}
diff --git a/lib/util/wordaccess.h b/lib/util/wordaccess.h
index 28963aee..2eaa2b24 100644
--- a/lib/util/wordaccess.h
+++ b/lib/util/wordaccess.h
@@ -36,28 +36,39 @@
    work with that.
 
    We also assume that a char is 8 bits.
+
+   HAVE_GCC_BITCOUNT and HAVE_GCC_BSWAP are set in pm_config.h
+
+   BITS_PER_LONG is the number of bits in long int.
 */
-#if (!defined(WORDACCESS_GENERIC) \
-     && defined(__GNUC__) && defined(__GLIBC__) \
-     && (__GNUC__ * 100 + __GNUC_MINOR__ >= 304) )
 
-    #if BYTE_ORDER==BIG_ENDIAN    /* defined by GCC */
+#include "pm_config.h"
 
-        #include "wordaccess_gcc3_be.h"
+#if (!defined(WORDACCESS_GENERIC) && HAVE_GCC_BITCOUNT )
 
-    #elif defined(__ia64__) || defined(__amd64__) || defined(__x86_64__)
-         /* all these macros are defined by GCC */
+    #if BYTE_ORDER == BIG_ENDIAN    /* See pm_config.h */
+        /* Sun Sparc 64, etc */ 
+        #include "wordaccess_gcc3_be.h"
 
+    #elif (BITS_PER_LONG == 64)
+        /* AMD Athlon 64, Intel x86_64, Intel Itanium, etc. */
         #include "wordaccess_64_le.h"
 
-    #else
+    #elif (BITS_PER_LONG == 32)
+        /* Intel x86_32 (80386, 80486, Pentium), etc. */
+        #include "wordaccess_generic.h"
 
-        #include "wordaccess_gcc3_le.h"
+    #else
+        /* Extremely rare case.
+           If long is neither 32 nor 64 bits, (say, 128) it comes here.
+        */
+        #define WORDACCESS_GENERIC
+        #include "wordaccess_generic.h"
 
     #endif
 
 #else
-
+    /* Non GCC, GCC prior to v.3.4 or WORDACCESS_GENERIC defined  */
     #include "wordaccess_generic.h"
 
 #endif
diff --git a/lib/util/wordaccess_64_le.h b/lib/util/wordaccess_64_le.h
index 4bb52b2e..4d148ad2 100644
--- a/lib/util/wordaccess_64_le.h
+++ b/lib/util/wordaccess_64_le.h
@@ -2,26 +2,21 @@
   This file is the part of wordaccess.h for use under these
   conditions:
 
-  * GCC (>=3.4), GLIBC
-  * 64 bit Little-Endian machines (IA64, X86-64, AMD64)
-=============================================================================*/
-   
-/*  
-    64 bit hton and ntoh do not exist.  Here we use bswap_64.
-    
-    While bswap_64 works on 64 bit data, __builtin_clzl works on "long" which
-    may or may not be 64 bits.  Code provided to find the right data type and
-    file off any extra when necessary.
-*/
-
-#include <byteswap.h>  /* See note above on bswap_64 */
+  * GCC (>=3.4)  (__builtin_clz appears in GCC 3.4)
+  * Little-Endian machines (IA64, X86-64, AMD64)
+  * 64 bit long
  
+=============================================================================*/
+
+#include "intcode.h"
+
 typedef uint64_t wordint;
 typedef unsigned char wordintBytes[sizeof(wordint)];
 
+
 static __inline__ wordint
-bytesToWordint(wordintBytes bytes) {
-    return ((wordint) bswap_64(*(wordint *)bytes));
+bytesToWordint(wordintBytes const bytes) {
+    return (wordint) pm_uintFromBigend64(*(bigend64*)bytes);
 }
 
 
@@ -29,24 +24,5 @@ bytesToWordint(wordintBytes bytes) {
 static __inline__ void
 wordintToBytes(wordintBytes * const bytesP,
                wordint        const wordInt) {
-    *(wordint *)bytesP = bswap_64(wordInt);
-}
-
-
-
-static __inline__ unsigned int
-wordintClz(wordint const x){
-
-    unsigned int s;
-
-    if (x == 0)
-        return sizeof(wordint) * 8;
-
-    /* Find the data type closest to 64 bits, and file off any extra. */
-    else if ((s=sizeof(long int)) >= 8)
-        return (__builtin_clzl((long int)x << (s - 8) * 8));
-    else if ((s=sizeof(long long int)) >= 8)
-        return (__builtin_clzll((long long int)x << (s - 8) * 8));
-    else
-        pm_error("Long long int is less than 64 bits on this machine"); 
+     *(bigend64*)bytesP = pm_bigendFromUint64(wordInt);
 }
diff --git a/lib/util/wordaccess_gcc3_be.h b/lib/util/wordaccess_gcc3_be.h
index 6f5d86fc..5aa63521 100644
--- a/lib/util/wordaccess_gcc3_be.h
+++ b/lib/util/wordaccess_gcc3_be.h
@@ -4,16 +4,6 @@
 
   * GCC (>=3.4), GLIBC
   * Big-Endian machines
-  
-  __builtin_clz is available on GCC 3.4 and above
-     
-  Note that the clz scheme does not work and requires adjustment
-  if long type does not make use of all bits for data storage.
-  
-  This is unlikely.  According to GNU MP (http://www.swox.com/gmp/),
-  in rare cases such as Cray, there are smaller data types that take up
-  the same space as long, but leave the higher bits silent.  Currently,
-  there are no known such cases for data type long.
 *===========================================================================*/
 
 typedef unsigned long int wordint;
@@ -31,10 +21,3 @@ wordintToBytes(wordintBytes * const bytesP,
                wordint        const wordInt) {
     *(wordint *)bytesP = wordInt;
 }
-
-
-
-static __inline__ unsigned int
-wordintClz(wordint const x) {
-    return (x==0 ? sizeof(wordint)*8 : __builtin_clzl(x));
-}
diff --git a/lib/util/wordaccess_gcc3_le.h b/lib/util/wordaccess_gcc3_le.h
deleted file mode 100644
index 7db218db..00000000
--- a/lib/util/wordaccess_gcc3_le.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*=============================================================================
-
-  This file is the part of wordaccess.h for use under these
-  conditions:
-
-  * GCC (>=3.4), GLIBC
-  * 32 bit Little-Endian machines (intel MPUs 80386, Pentium, etc.)
-  * Other non-Big-Endian machines (very rare)
-  
-=============================================================================*/
-
-typedef uint32_t wordint;
-typedef unsigned char wordintBytes[sizeof(wordint)];
-
-#include <sys/types.h>
-#include <netinet/in.h>
-
-/*
-  Here we use the more widely used functions htonl and ntohl instead of
-  bswap_32.  This makes possible the handling of weird byte ordering
-  (neither Big-Endian nor Little-Endian) schemes, if any.
-*/
-
-static __inline__ wordint
-bytesToWordint(wordintBytes const bytes) {
-    return (wordint) ntohl(*(wordint *)bytes);
-}
-
-
-
-static __inline__ void
-wordintToBytes(wordintBytes * const bytesP,
-               wordint        const wordInt) {
-
-    *(wordint *)bytesP = htonl(wordInt);
-}
-
-
-
-static __inline__ unsigned int
-wordintClz(wordint const x) {
-
-    /* Find the data type closest to 32 bits, and file off any extra.  */
-
-    if (x == 0)
-        return sizeof(wordint) * 8;
-    else if (sizeof(int) >= 4)
-        return __builtin_clz((int)x << (sizeof(int) - 4) * 8);
-    else if (sizeof(long int) >= 4)
-        return __builtin_clzl((long int)x << (sizeof(long int) - 4) * 8);
-    else
-        pm_error("Long int is less than 32 bits on this machine"); 
-}
-
diff --git a/lib/util/wordaccess_generic.h b/lib/util/wordaccess_generic.h
index 7f27ef74..94cc8124 100644
--- a/lib/util/wordaccess_generic.h
+++ b/lib/util/wordaccess_generic.h
@@ -5,85 +5,25 @@
 
   * Compilers other than GCC
   * GCC before version 3.4
-  * c libraries other than Glibc
   * Specified by the user with WORDACCESS_GENERIC
 =============================================================================*/
 
+#include "intcode.h"
+
 typedef uint32_t wordint;
 typedef unsigned char wordintBytes[sizeof(wordint)];
+
     
 static __inline__ wordint
-bytesToWordint(wordintBytes const bytes) {
-    wordint retval;
-    unsigned int i;
+bytesToWordint(wordintBytes  const bytes) {
 
-    /* Note that 'bytes' is a pointer, due to C array degeneration.
-       That means sizeof(bytes) isn't what you think it is.
-    */
-    
-    for (i = 1, retval = bytes[0]; i < sizeof(wordint); ++i) {
-        retval = (retval << 8) + bytes[i];
-    }
-    return retval;
+    return (wordint)  pm_uintFromBigend32( * (bigend32*) bytes);
 }
 
 
-
 static __inline__ void
 wordintToBytes(wordintBytes * const bytesP,
-               wordint        const wordInt) {
-
-    wordint buffer;
-    int i;
-
-    for (i = sizeof(*bytesP)-1, buffer = wordInt; i >= 0; --i) {
-        (*bytesP)[i] = buffer & 0xFF;
-        buffer >>= 8;
-    }
-}
-    
-static unsigned char const clz8[256]= {
-    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
-    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 
-};
-
-
-
-static __inline__ unsigned int
-clz16(wordint const x) {
-    if (x >> 8  != 0)
-        return clz8[x >> 8];
-    else
-        return clz8[x] + 8;
-}
-
-
-
-static __inline__  unsigned int
-clz32(wordint const x) {
-    if (x >> 16  != 0)
-        return clz16(x >> 16);
-    else
-        return clz16(x) +16;
-}
-
-
+               wordint    const wordInt) {
 
-static __inline__  unsigned int
-wordintClz(wordint const x) {
-    return clz32(x);
+    * (bigend32*) bytesP = pm_bigendFromUint32((uint32_t)wordInt);
 }
diff --git a/lib/util/wordintclz.h b/lib/util/wordintclz.h
new file mode 100644
index 00000000..32e6ade8
--- /dev/null
+++ b/lib/util/wordintclz.h
@@ -0,0 +1,93 @@
+#ifndef WORDINTCLZ_H_INCLUDED
+#define WORDINTCLZ_H_INCLUDED
+
+#if (!defined(WORDACCESS_GENERIC) && HAVE_GCC_BITCOUNT )
+/* 
+   Compiler is GCC and has __builtin_clz()
+   wordint is long 
+ 
+   __builtin_clz is available on GCC 3.4 and above
+     
+   Note that the clz scheme does not work and requires adjustment
+   if long type does not make use of all bits for data storage.
+  
+   This is unlikely.  According to GNU MP (http://www.swox.com/gmp/),
+   in rare cases such as Cray, there are smaller data types that take up
+   the same space as long, but leave the higher bits silent.
+   Currently, there are no known such cases for data type long.
+ */
+
+static __inline__ unsigned int
+wordintClz(wordint const x){
+
+    assert(sizeof(unsigned long int) == sizeof(wordint));
+
+    if (x == 0)
+        return sizeof(wordint) * 8;
+    else
+        return (__builtin_clzl( (unsigned long int) x ));
+}
+  
+#else
+
+/* wordint is uint32_t: exactly 32 bits wide */
+ 
+static unsigned char const clz8[256]= {
+    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 
+};
+
+
+
+static __inline__ unsigned int
+clz16(wordint const x) {
+
+    if (x >> 8 != 0)
+        return clz8[x >> 8];
+    else
+        return clz8[x] + 8;
+}
+
+
+
+static __inline__  unsigned int
+clz32(wordint const x) {
+
+    if (x >> 16 != 0)
+        return clz16(x >> 16);
+    else
+        return clz16(x) + 16;
+}
+
+
+
+static __inline__  unsigned int
+wordintClz(wordint const x) {
+
+    assert(sizeof(wordint) == 4);
+
+    return clz32(x);
+}
+
+/* Another way to calculate leading zeros:
+   x == 0 ? 32 : 31 - floor(log(x)/log(2))
+   (Beware: insufficient precision will cause errors)
+*/
+
+#endif
+
+#endif