diff options
Diffstat (limited to 'lib/util')
-rw-r--r-- | lib/util/Makefile | 14 | ||||
-rw-r--r-- | lib/util/bitarith.h | 42 | ||||
-rw-r--r-- | lib/util/floatcode.h | 185 | ||||
-rw-r--r-- | lib/util/intcode.h | 228 | ||||
-rw-r--r-- | lib/util/mallocvar.h | 19 | ||||
-rw-r--r-- | lib/util/nsleep.c | 27 | ||||
-rw-r--r-- | lib/util/nsleep.h | 7 | ||||
-rw-r--r-- | lib/util/nstring.c | 79 | ||||
-rw-r--r-- | lib/util/nstring.h | 82 | ||||
-rw-r--r-- | lib/util/pm_c_util.h | 10 | ||||
-rw-r--r-- | lib/util/shhopt.c | 124 | ||||
-rw-r--r-- | lib/util/shhopt.h | 21 | ||||
-rw-r--r-- | lib/util/vasprintf.c | 59 | ||||
-rw-r--r-- | lib/util/wordaccess.h | 31 | ||||
-rw-r--r-- | lib/util/wordaccess_64_le.h | 46 | ||||
-rw-r--r-- | lib/util/wordaccess_gcc3_be.h | 17 | ||||
-rw-r--r-- | lib/util/wordaccess_gcc3_le.h | 54 | ||||
-rw-r--r-- | lib/util/wordaccess_generic.h | 74 | ||||
-rw-r--r-- | lib/util/wordintclz.h | 93 |
19 files changed, 936 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..99aec256 --- /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) { + + uint32_t 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) { + + uint32_t 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 702a3c44..0fa78c7a 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 fd15b53c..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); */ @@ -202,6 +205,8 @@ typedef struct { OPTENTRY(shortvalue, longvalue, typevalue, outputvalue, flagvalue) \ } +#define OPTENTINIT OPTION_DEF[0].type = OPT_END + struct optNameValue { const char * name; @@ -227,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..9d8fe590 --- /dev/null +++ b/lib/util/vasprintf.c @@ -0,0 +1,59 @@ +#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 "nstring.h" + +#if defined(__GNUC__) && !defined(__MINGW32__) + #define HAVE_VASPRINTF 1 +#else + #define HAVE_VASPRINTF 0 +#endif + +void +vasprintfN(const char ** const resultP, + const char * const format, + va_list varargs) { + + char * result; + +#if HAVE_VASPRINTF + vasprintf(&result, format, varargs); + + if (result == NULL) + *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 |