diff --git a/config.h-vms.template b/config.h-vms.template index 780ea0b0..3cb9a74a 100644 --- a/config.h-vms.template +++ b/config.h-vms.template @@ -417,6 +417,10 @@ this program. If not, see . */ #define alloca(n) __ALLOCA(n) #endif +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +/* # undef WORDS_BIGENDIAN */ + /* Output sync sypport */ #define NO_OUTPUT_SYNC diff --git a/config.h.W32.template b/config.h.W32.template index c36935c4..4b5da003 100644 --- a/config.h.W32.template +++ b/config.h.W32.template @@ -450,6 +450,10 @@ char *ttyname (int); /* # undef _ALL_SOURCE */ #endif +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +/* # undef WORDS_BIGENDIAN */ + /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ diff --git a/configure.ac b/configure.ac index 1b03135f..9b8aed96 100644 --- a/configure.ac +++ b/configure.ac @@ -49,6 +49,7 @@ AC_CANONICAL_HOST AC_AIX AC_ISC_POSIX AC_MINIX +AC_C_BIGENDIAN # Enable gettext, in "external" mode. AM_GNU_GETTEXT_VERSION([0.19.4]) diff --git a/hash.c b/hash.c index e1688870..c138aaf6 100644 --- a/hash.c +++ b/hash.c @@ -327,3 +327,151 @@ round_up_2 (unsigned long n) return n + 1; } + +#define rol32(v, n) \ + ((v) << (n) | ((v) >> (32 - (n)))) + +/* jhash_mix -- mix 3 32-bit values reversibly. */ +#define jhash_mix(a, b, c) \ +{ \ + a -= c; a ^= rol32(c, 4); c += b; \ + b -= a; b ^= rol32(a, 6); a += c; \ + c -= b; c ^= rol32(b, 8); b += a; \ + a -= c; a ^= rol32(c, 16); c += b; \ + b -= a; b ^= rol32(a, 19); a += c; \ + c -= b; c ^= rol32(b, 4); b += a; \ +} + +/* jhash_final - final mixing of 3 32-bit values (a,b,c) into c */ +#define jhash_final(a, b, c) \ +{ \ + c ^= b; c -= rol32(b, 14); \ + a ^= c; a -= rol32(c, 11); \ + b ^= a; b -= rol32(a, 25); \ + c ^= b; c -= rol32(b, 16); \ + a ^= c; a -= rol32(c, 4); \ + b ^= a; b -= rol32(a, 14); \ + c ^= b; c -= rol32(b, 24); \ +} + +/* An arbitrary initial parameter */ +#define JHASH_INITVAL 0xdeadbeef + +#define sum_get_unaligned_32(r, p) \ + do { \ + unsigned int val; \ + memcpy(&val, (p), 4); \ + r += val; \ + } while(0); + +unsigned jhash(unsigned const char *k, int length) +{ + unsigned int a, b, c; + + /* Set up the internal state */ + a = b = c = JHASH_INITVAL + length; + + /* All but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) { + sum_get_unaligned_32(a, k); + sum_get_unaligned_32(b, k + 4); + sum_get_unaligned_32(c, k + 8); + jhash_mix(a, b, c); + length -= 12; + k += 12; + } + + if (!length) + return c; + + if (length > 8) + { + sum_get_unaligned_32(a, k); + length -= 4; + k += 4; + } + if (length > 4) + { + sum_get_unaligned_32(b, k); + length -= 4; + k += 4; + } + + if (length == 4) + c += (unsigned)k[3]<<24; + if (length >= 3) + c += (unsigned)k[2]<<16; + if (length >= 2) + c += (unsigned)k[1]<<8; + c += k[0]; + jhash_final(a, b, c); + return c; +} + +#ifdef WORDS_BIGENDIAN +/* The ifs are ordered from the first byte in memory to the last. */ +#define sum_up_to_nul(r, p, flag) \ + do { \ + unsigned int val; \ + memcpy(&val, (p), 4); \ + if ((val & 0xFF000000) == 0) \ + flag = 1; \ + else if ((val & 0xFF0000) == 0) \ + r += val & ~0xFFFF, flag = 1; \ + else if ((val & 0xFF00) == 0) \ + r += val & ~0xFF, flag = 1; \ + else \ + r += val, flag = (val & 0xFF) == 0; \ + } while (0) +#else +/* First detect the presence of zeroes. If there is none, we can + sum the 4 bytes directly. Otherwise, the ifs are ordered as in the + big endian case, from the first byte in memory to the last. */ +#define sum_up_to_nul(r, p, flag) \ + do { \ + unsigned int val; \ + unsigned int zeroes; \ + memcpy(&val, (p), 4); \ + zeroes = ((val - 0x01010101) & ~val); \ + if (!(zeroes & 0x80808080)) \ + r += val; \ + else if ((val & 0xFF) == 0) \ + flag = 1; \ + else if ((val & 0xFF00) == 0) \ + r += val & 0xFF, flag = 1; \ + else if ((val & 0xFF0000) == 0) \ + r += val & 0xFFFF, flag = 1; \ + else \ + r += val, flag = 1; \ + } while (0) +#endif + +unsigned jhash_string(unsigned const char *k) +{ + unsigned int a, b, c; + unsigned int have_nul = 0; + unsigned const char *start = k; + + /* Set up the internal state */ + a = b = c = JHASH_INITVAL; + + /* All but the last block: affect some 32 bits of (a,b,c) */ + for (;;) { + sum_up_to_nul(a, k, have_nul); + if (have_nul) + break; + k += 4; + sum_up_to_nul(b, k, have_nul); + if (have_nul) + break; + k += 4; + sum_up_to_nul(c, k, have_nul); + if (have_nul) + break; + k += 4; + jhash_mix(a, b, c); + } + + jhash_final(a, b, c); + return c + (k - start); +} diff --git a/hash.h b/hash.h index 960cbd78..667d6508 100644 --- a/hash.h +++ b/hash.h @@ -73,6 +73,9 @@ void hash_map_arg __P((struct hash_table *ht, hash_map_arg_func_t map, void *arg void hash_print_stats __P((struct hash_table *ht, FILE *out_FILE)); void **hash_dump __P((struct hash_table *ht, void **vector_0, qsort_cmp_t compare)); +extern unsigned jhash(unsigned char const *key, int n); +extern unsigned jhash_string(unsigned char const *key); + extern void *hash_deleted_item; #define HASH_VACANT(item) ((item) == 0 || (void *) (item) == hash_deleted_item) @@ -83,9 +86,8 @@ extern void *hash_deleted_item; be identical. Take advantage of that to short-circuit string compares. */ #define STRING_HASH_1(KEY, RESULT) do { \ - unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ - while (*++_key_) \ - (RESULT) += (*_key_ << (_key_[1] & 0xf)); \ + unsigned char const *_key_ = (unsigned char const *) (KEY); \ + (RESULT) += jhash_string(_key_); \ } while (0) #define return_STRING_HASH_1(KEY) do { \ unsigned long _result_ = 0; \ @@ -93,10 +95,11 @@ extern void *hash_deleted_item; return _result_; \ } while (0) +/* No need for a second hash because jhash already provides + pretty good results. However, do evaluate the arguments + to avoid warnings. */ #define STRING_HASH_2(KEY, RESULT) do { \ - unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ - while (*++_key_) \ - (RESULT) += (*_key_ << (_key_[1] & 0x7)); \ + (void)(KEY); \ } while (0) #define return_STRING_HASH_2(KEY) do { \ unsigned long _result_ = 0; \ @@ -113,27 +116,24 @@ extern void *hash_deleted_item; #define STRING_N_HASH_1(KEY, N, RESULT) do { \ - unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ - int _n_ = (N); \ - if (_n_) \ - while (--_n_ && *++_key_) \ - (RESULT) += (*_key_ << (_key_[1] & 0xf)); \ - (RESULT) += *++_key_; \ + unsigned char const *_key_ = (unsigned char const *) (KEY); \ + (RESULT) += jhash(_key_, N); \ } while (0) + #define return_STRING_N_HASH_1(KEY, N) do { \ unsigned long _result_ = 0; \ STRING_N_HASH_1 ((KEY), (N), _result_); \ return _result_; \ } while (0) +/* No need for a second hash because jhash already provides + pretty good results. However, do evaluate the arguments + to avoid warnings. */ #define STRING_N_HASH_2(KEY, N, RESULT) do { \ - unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ - int _n_ = (N); \ - if (_n_) \ - while (--_n_ && *++_key_) \ - (RESULT) += (*_key_ << (_key_[1] & 0x7)); \ - (RESULT) += *++_key_; \ + (void)(KEY); \ + (void)(N); \ } while (0) + #define return_STRING_N_HASH_2(KEY, N) do { \ unsigned long _result_ = 0; \ STRING_N_HASH_2 ((KEY), (N), _result_); \ @@ -141,10 +141,10 @@ extern void *hash_deleted_item; } while (0) #define STRING_N_COMPARE(X, Y, N, RESULT) do { \ - RESULT = (X) == (Y) ? 0 : strncmp ((X), (Y), (N)); \ + RESULT = (X) == (Y) ? 0 : memcmp ((X), (Y), (N)); \ } while (0) #define return_STRING_N_COMPARE(X, Y, N) do { \ - return (X) == (Y) ? 0 : strncmp ((X), (Y), (N)); \ + return (X) == (Y) ? 0 : memcmp ((X), (Y), (N)); \ } while (0) #ifdef HAVE_CASE_INSENSITIVE_FS diff --git a/tests/scripts/targets/INTERMEDIATE b/tests/scripts/targets/INTERMEDIATE index 2b3021b2..512498c3 100644 --- a/tests/scripts/targets/INTERMEDIATE +++ b/tests/scripts/targets/INTERMEDIATE @@ -57,7 +57,7 @@ $answer = "cp foo.f foo.e\ncp foo.e foo.d\nrm foo.e\n"; # TEST #3 &run_make_with_options($makefile,'foo.c',&get_logfile); -$answer = "cp foo.f foo.e\ncp bar.f bar.e\ncat foo.e bar.e > foo.c\nrm bar.e foo.e\n"; +$answer = "cp foo.f foo.e\ncp bar.f bar.e\ncat foo.e bar.e > foo.c\nrm foo.e bar.e\n"; &compare_output($answer, &get_logfile(1)); # TEST #4 @@ -72,7 +72,7 @@ $answer = "$make_name: 'foo.c' is up to date.\n"; &touch('foo.f'); &run_make_with_options($makefile,'foo.c',&get_logfile); -$answer = "cp foo.f foo.e\ncp bar.f bar.e\ncat foo.e bar.e > foo.c\nrm bar.e foo.e\n"; +$answer = "cp foo.f foo.e\ncp bar.f bar.e\ncat foo.e bar.e > foo.c\nrm foo.e bar.e\n"; &compare_output($answer, &get_logfile(1)); # TEST #6 -- added for PR/1669: don't remove files mentioned on the cmd line. diff --git a/tests/scripts/targets/SECONDARY b/tests/scripts/targets/SECONDARY index 447c275e..963c2405 100644 --- a/tests/scripts/targets/SECONDARY +++ b/tests/scripts/targets/SECONDARY @@ -93,8 +93,7 @@ print MAKEFILE <<'EOF'; final: intermediate intermediate: source -final intermediate source: - echo $< > $@ +final intermediate source: ; echo $< > $@ EOF close(MAKEFILE); @@ -135,7 +134,7 @@ all : 1.c 2.c cp 1.b 1.c cp 2.a 2.b cp 2.b 2.c -rm 1.b 2.b'); +rm 2.b 1.b'); unlink(qw(1.a 2.a 1.c 2.c));