mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
Converted all ASCII tabs to ASCII spaces using a 8 character tab stop, for all files, except for all Makefiles (plus rpm.mk). The `git diff -w` reports no changes.
1059 lines
32 KiB
C
1059 lines
32 KiB
C
/*
|
|
* hash - one-way hash routines
|
|
*
|
|
* Copyright (C) 1999-2007,2021-2023 Landon Curt Noll
|
|
*
|
|
* Calc is open software; you can redistribute it and/or modify it under
|
|
* the terms of the version 2.1 of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* Calc is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
|
* Public License for more details.
|
|
*
|
|
* A copy of version 2.1 of the GNU Lesser General Public License is
|
|
* distributed with calc under the filename COPYING-LGPL. You should have
|
|
* received a copy with calc; if not, write to Free Software Foundation, Inc.
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Under source code control: 1995/11/23 05:13:11
|
|
* File existed as early as: 1995
|
|
*
|
|
* chongo <was here> /\oo/\ http://www.isthe.com/chongo/
|
|
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include "have_string.h"
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include "calc.h"
|
|
#include "alloc.h"
|
|
#include "value.h"
|
|
#include "zrand.h"
|
|
#include "zrandom.h"
|
|
#include "hash.h"
|
|
|
|
|
|
#include "errtbl.h"
|
|
#include "banned.h" /* include after system header <> includes */
|
|
|
|
|
|
/*
|
|
* external hash_setup functions
|
|
*/
|
|
E_FUNC void shs_init_state(HASH*);
|
|
E_FUNC void sha1_init_state(HASH*);
|
|
E_FUNC void MD5_init_state(HASH*);
|
|
|
|
|
|
/*
|
|
* hash_long can deal with bool's, int's, FLAGS's and LEN's
|
|
*/
|
|
#define hash_bool(type, val, state) (hash_long((type), (long)(val), (state)))
|
|
#define hash_int(type, val, state) (hash_long((type), (long)(val), (state)))
|
|
#define hash_flag(type, val, state) (hash_long((type), (long)(val), (state)))
|
|
#define hash_len(type, val, state) (hash_long((type), (long)(val), (state)))
|
|
|
|
|
|
/*
|
|
* hash_setup - setup the hash state for a given hash
|
|
*/
|
|
STATIC struct hash_setup {
|
|
int type; /* hash type (see XYZ_HASH_TYPE below) */
|
|
void (*init_state)(HASH*); /* initialize a hash state */
|
|
} htbl[] = {
|
|
{ SHA1_HASH_TYPE, sha1_init_state }, /* SHA-1 / SHA-1 */
|
|
{ -1, NULL } /* must be last */
|
|
};
|
|
|
|
|
|
/*
|
|
* hash_init - initialize a hash state
|
|
*
|
|
* given:
|
|
* type - hash type (see hash.h)
|
|
* state - the state to initialize, or NULL to malloc it
|
|
*
|
|
* returns:
|
|
* initialized state
|
|
*/
|
|
HASH *
|
|
hash_init(int type, HASH *state)
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* malloc if needed
|
|
*/
|
|
if (state == NULL) {
|
|
state = (HASH *)malloc(sizeof(HASH));
|
|
if (state == NULL) {
|
|
math_error("hash_init: cannot malloc HASH");
|
|
not_reached();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* clear hash value
|
|
*/
|
|
memset((void*)state, 0, sizeof(HASH));
|
|
state->bytes = true;
|
|
|
|
/*
|
|
* search for the hash_setup function
|
|
*/
|
|
for (i=0; htbl[i].init_state != NULL; ++i) {
|
|
|
|
/* if we found the state that we were looking for */
|
|
if (type == htbl[i].type) {
|
|
|
|
/* initialize state and return */
|
|
(htbl[i].init_state)(state);
|
|
|
|
/* firewall - MAX_CHUNKSIZE must be >= chunksize */
|
|
if (state->chunksize > MAX_CHUNKSIZE) {
|
|
math_error(
|
|
"internal error: MAX_CHUNKSIZE is too small");
|
|
not_reached();
|
|
}
|
|
return state;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* no such hash state
|
|
*/
|
|
math_error("internal error: hash type not found in htbl[]");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_free - free the hash state
|
|
*/
|
|
void
|
|
hash_free(HASH *state)
|
|
{
|
|
/*
|
|
* do nothing if state is NULL
|
|
*/
|
|
if (state == NULL) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* free main state and return
|
|
*/
|
|
free(state);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_copy - copy a hash state
|
|
*
|
|
* given:
|
|
* state - the state to copy
|
|
*
|
|
* returns:
|
|
* pointer to copy of state
|
|
*/
|
|
HASH *
|
|
hash_copy(HASH *state)
|
|
{
|
|
HASH *hnew; /* copy of state */
|
|
|
|
/*
|
|
* malloc new state
|
|
*/
|
|
hnew = (HASH *)malloc(sizeof(HASH));
|
|
if (hnew == NULL) {
|
|
math_error("hash_init: cannot malloc HASH");
|
|
not_reached();
|
|
}
|
|
|
|
/*
|
|
* duplicate state
|
|
*/
|
|
memcpy((void *)hnew, (void *)state, sizeof(HASH));
|
|
return hnew;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_cmp - compare hash values
|
|
*
|
|
* given:
|
|
* a first hash state
|
|
* b second hash state
|
|
*
|
|
* returns:
|
|
* true => hash states are different
|
|
* false => hash states are the same
|
|
*/
|
|
int
|
|
hash_cmp(HASH *a, HASH *b)
|
|
{
|
|
/*
|
|
* firewall and quick check
|
|
*/
|
|
if (a == b) {
|
|
/* pointers to the same object */
|
|
return false;
|
|
}
|
|
if (a == NULL || b == NULL) {
|
|
/* one pointer is NULL, so they differ */
|
|
return true;
|
|
}
|
|
if (a->cmp == NULL || b->cmp == NULL) {
|
|
/* one cmp function is NULL, so they differ */
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* compare hash types
|
|
*/
|
|
if (a->hashtype != b->hashtype) {
|
|
/* different hash types are different */
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* perform the hash specific comparison
|
|
*/
|
|
return ((a->cmp)(a,b));
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_print - print the name and value of a hash
|
|
*
|
|
* given:
|
|
* state the hash state to print name and value of
|
|
*/
|
|
void
|
|
hash_print(HASH *state)
|
|
{
|
|
/* print the hash */
|
|
(state->print)(state);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_final - finalize the state of a hash and return a ZVALUE
|
|
*
|
|
* given:
|
|
* state the hash state to finalize
|
|
*
|
|
* returns:
|
|
* hash state as a ZVALUE
|
|
*/
|
|
ZVALUE
|
|
hash_final(HASH *state)
|
|
{
|
|
/* return the finalized the hash value */
|
|
return (state->final)(state);
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_long - note a long value
|
|
*
|
|
* given:
|
|
* type - hash type (see hash.h)
|
|
* longval - a long value
|
|
* state - the state to hash
|
|
*
|
|
* returns:
|
|
* the new state
|
|
*
|
|
* This function will hash a long value as if it were a 64 bit value.
|
|
* The input is a long. If a long is smaller than 64 bits, we will
|
|
* hash a final 32 bits of zeros.
|
|
*
|
|
* This function is OK to hash bool's, unsigned long's, unsigned int's
|
|
* signed int's as well as FLAG's and LEN's.
|
|
*/
|
|
HASH *
|
|
hash_long(int type, long longval, HASH *state)
|
|
{
|
|
long lval[64/LONG_BITS]; /* 64 bits of longs */
|
|
|
|
/*
|
|
* initialize if state is NULL
|
|
*/
|
|
if (state == NULL) {
|
|
state = hash_init(type, NULL);
|
|
}
|
|
|
|
/*
|
|
* setup for the hash_long
|
|
*/
|
|
(state->chkpt)(state);
|
|
state->bytes = false; /* data to be read as words */
|
|
|
|
/*
|
|
* catch the zero numeric value special case
|
|
*/
|
|
if (longval == 0) {
|
|
/* note a zero numeric value and return */
|
|
(state->note)(HASH_ZERO(state->base), state);
|
|
return state;
|
|
}
|
|
|
|
/*
|
|
* prep for a long value hash
|
|
*/
|
|
(state->note)(state->base, state);
|
|
|
|
/*
|
|
* hash as if we have a 64 bit value
|
|
*/
|
|
memset((char *)lval, 0, sizeof(lval));
|
|
lval[0] = longval;
|
|
(state->update)(state, (USB8 *)lval, sizeof(lval));
|
|
|
|
/*
|
|
* all done
|
|
*/
|
|
return state;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_zvalue - hash a ZVALUE
|
|
*
|
|
* given:
|
|
* type - hash type (see hash.h)
|
|
* zval - the ZVALUE
|
|
* state - the state to hash or NULL
|
|
*
|
|
* returns:
|
|
* the new state
|
|
*/
|
|
HASH *
|
|
hash_zvalue(int type, ZVALUE zval, HASH *state)
|
|
{
|
|
|
|
#if CALC_BYTE_ORDER == BIG_ENDIAN && BASEB == 16
|
|
int full_lim; /* HALFs in whole chunks in zval */
|
|
int chunkhalf; /* size of half buffer in HALFs */
|
|
int i;
|
|
int j;
|
|
#endif
|
|
#if BASEB == 16
|
|
HALF half[MAX_CHUNKSIZE]; /* For endian reversal */
|
|
#endif
|
|
|
|
/*
|
|
* initialize if state is NULL
|
|
*/
|
|
if (state == NULL) {
|
|
state = hash_init(type, NULL);
|
|
}
|
|
|
|
/*
|
|
* setup for the ZVALUE hash
|
|
*/
|
|
(state->chkpt)(state);
|
|
state->bytes = false; /* data to be read as words */
|
|
|
|
/*
|
|
* catch the zero numeric value special case
|
|
*/
|
|
if (ziszero(zval)) {
|
|
/* note a zero numeric value and return */
|
|
(state->note)(HASH_ZERO(state->base), state);
|
|
return state;
|
|
}
|
|
|
|
/*
|
|
* prep for a ZVALUE hash
|
|
*/
|
|
(state->note)(HASH_ZVALUE(state->base), state);
|
|
/* note if we have a negative value */
|
|
if (zisneg(zval)) {
|
|
(state->note)(HASH_NEG(state->base), state);
|
|
}
|
|
|
|
#if CALC_BYTE_ORDER == BIG_ENDIAN && BASEB == 16
|
|
|
|
/*
|
|
* hash full chunks
|
|
*
|
|
* We need to convert the array of HALFs into canonical architectural
|
|
* independent form -- 32 bit arrays. Because we have 16 bit values
|
|
* in Big Endian form, we need to swap 16 bit values so that they
|
|
* appear as 32 bit Big Endian values.
|
|
*/
|
|
chunkhalf = state->chunksize/sizeof(HALF);
|
|
full_lim = (zval.len / chunkhalf) * chunkhalf;
|
|
for (i=0; i < full_lim; i += chunkhalf) {
|
|
/* HALF swap copy a chunk into a data buffer */
|
|
for (j=0; j < chunkhalf; j += 2) {
|
|
half[j] = zval.v[i+j+1];
|
|
half[j+1] = zval.v[i+j];
|
|
}
|
|
(state->update)(state, (USB8*) half, state->chunksize);
|
|
}
|
|
|
|
/*
|
|
* hash the final partial chunk (if any)
|
|
*
|
|
* We need to convert the array of HALFs into canonical architectural
|
|
* independent form -- 32 bit arrays. Because we have 16 bit values
|
|
* in Big Endian form, we need to swap 16 bit values so that they
|
|
* appear as 32 bit Big Endian values.
|
|
*/
|
|
if (zval.len > full_lim) {
|
|
for (j=0; j < zval.len-full_lim-1; j += 2) {
|
|
half[j] = zval.v[full_lim+j+1];
|
|
half[j+1] = zval.v[full_lim+j];
|
|
}
|
|
if (j < zval.len-full_lim) {
|
|
half[j] = (HALF)0;
|
|
half[j+1] = zval.v[zval.len-1];
|
|
--full_lim;
|
|
}
|
|
(state->update)(state, (USB8 *) half,
|
|
(zval.len-full_lim)*sizeof(HALF));
|
|
}
|
|
|
|
#else
|
|
|
|
/*
|
|
* hash the array of HALFs
|
|
*
|
|
* The array of HALFs is equivalent to the canonical architectural
|
|
* independent form. We either have 32 bit HALFs (in which case
|
|
* we do not case the byte order) or we have 16 bit HALFs in Little
|
|
* Endian order (which happens to be laid out in the same order as
|
|
* 32 bit values).
|
|
*/
|
|
(state->update)(state, (USB8 *)zval.v, zval.len*sizeof(HALF));
|
|
|
|
#if BASEB == 16
|
|
if (zval.len & 1) { /* padding to complete word */
|
|
half[0] = 0;
|
|
(state->update)(state, (USB8 *) half, 2);
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/*
|
|
* all done
|
|
*/
|
|
return state;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_number - hash a NUMBER
|
|
*
|
|
* given:
|
|
* type - hash type (see hash.h)
|
|
* n - the NUMBER
|
|
* state - the state to hash or NULL
|
|
*
|
|
* returns:
|
|
* the new state
|
|
*/
|
|
HASH *
|
|
hash_number(int type, void *n, HASH *state)
|
|
{
|
|
NUMBER *number = (NUMBER *)n; /* n as a NUMBER pointer */
|
|
bool sign; /* sign of the denominator */
|
|
|
|
/*
|
|
* initialize if state is NULL
|
|
*/
|
|
if (state == NULL) {
|
|
state = hash_init(type, NULL);
|
|
}
|
|
|
|
/*
|
|
* setup for the NUMBER hash
|
|
*/
|
|
(state->chkpt)(state);
|
|
state->bytes = false;
|
|
|
|
/*
|
|
* process the numerator
|
|
*/
|
|
state = hash_zvalue(type, number->num, state);
|
|
|
|
/*
|
|
* if the NUMBER is not an integer, process the denominator
|
|
*/
|
|
if (qisfrac(number)) {
|
|
|
|
/* note the division */
|
|
(state->note)(HASH_DIV(state->base), state);
|
|
|
|
/* hash denominator as positive -- just in case */
|
|
sign = number->den.sign;
|
|
number->den.sign = 0;
|
|
|
|
/* hash the denominator */
|
|
state = hash_zvalue(type, number->den, state);
|
|
|
|
/* restore the sign */
|
|
number->den.sign = sign;
|
|
}
|
|
|
|
/*
|
|
* all done
|
|
*/
|
|
return state;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_complex - hash a COMPLEX
|
|
*
|
|
* given:
|
|
* type - hash type (see hash.h)
|
|
* c - the COMPLEX
|
|
* state - the state to hash or NULL
|
|
*
|
|
* returns:
|
|
* the new state
|
|
*/
|
|
HASH *
|
|
hash_complex(int type, void *c, HASH *state)
|
|
{
|
|
COMPLEX *complex = (COMPLEX *)c; /* c as a COMPLEX pointer */
|
|
|
|
/*
|
|
* initialize if state is NULL
|
|
*/
|
|
if (state == NULL) {
|
|
state = hash_init(type, NULL);
|
|
}
|
|
|
|
/*
|
|
* setup for the COMPLEX hash
|
|
*/
|
|
(state->chkpt)(state);
|
|
state->bytes = false;
|
|
|
|
/*
|
|
* catch the zero special case
|
|
*/
|
|
if (ciszero(complex)) {
|
|
/* note a zero numeric value and return */
|
|
(state->note)(HASH_ZERO(state->base), state);
|
|
return state;
|
|
}
|
|
|
|
/*
|
|
* process the real value if not pure imaginary
|
|
*
|
|
* We will ignore the real part if the value is of the form 0+xi.
|
|
*/
|
|
if (!qiszero(complex->real)) {
|
|
state = hash_number(type, complex->real, state);
|
|
}
|
|
|
|
/*
|
|
* if the NUMBER is not real, process the imaginary value
|
|
*
|
|
* We will ignore the imaginary part of the value is of the form x+0i.
|
|
*/
|
|
if (!cisreal(complex)) {
|
|
|
|
/* note the sqrt(-1) */
|
|
(state->note)(HASH_COMPLEX(state->base), state);
|
|
|
|
/* hash the imaginary value */
|
|
state = hash_number(type, complex->imag, state);
|
|
}
|
|
|
|
/*
|
|
* all done
|
|
*/
|
|
return state;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_str - hash a null-terminated string
|
|
*
|
|
* given:
|
|
* type - hash type (see hash.h)
|
|
* str - the string
|
|
* state - the state to hash or NULL
|
|
*
|
|
* returns:
|
|
* the new state
|
|
*/
|
|
HASH *
|
|
hash_str(int type, char *str, HASH *state)
|
|
{
|
|
size_t len; /* string length */
|
|
|
|
/*
|
|
* initialize if state is NULL
|
|
*/
|
|
if (state == NULL) {
|
|
state = hash_init(type, NULL);
|
|
}
|
|
|
|
/*
|
|
* setup for the string hash
|
|
*/
|
|
if (!state->bytes) {
|
|
(state->chkpt)(state);
|
|
state->bytes = true;
|
|
}
|
|
|
|
len = strlen(str);
|
|
|
|
/*
|
|
* hash the string
|
|
*/
|
|
(state->update)(state, (USB8*)str, len);
|
|
|
|
/*
|
|
* all done
|
|
*/
|
|
return state;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_STR - hash a STRING
|
|
*
|
|
* given:
|
|
* type - hash type (see hash.h)
|
|
* str - the STRING
|
|
* state - the state to hash or NULL
|
|
*
|
|
* returns:
|
|
* the new state
|
|
*/
|
|
HASH *
|
|
hash_STR(int type, STRING *str, HASH *state)
|
|
{
|
|
/*
|
|
* initialize if state is NULL
|
|
*/
|
|
if (state == NULL) {
|
|
state = hash_init(type, NULL);
|
|
}
|
|
|
|
/*
|
|
* setup for the string hash
|
|
*/
|
|
if (!state->bytes) {
|
|
(state->chkpt)(state);
|
|
state->bytes = true;
|
|
}
|
|
|
|
/*
|
|
* hash the string
|
|
*/
|
|
(state->update)(state, (USB8*) str->s_str, (USB32) str->s_len);
|
|
|
|
/*
|
|
* all done
|
|
*/
|
|
return state;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_usb8 - hash an array of USB8s
|
|
*
|
|
* given:
|
|
* type - hash type (see hash.h)
|
|
* byte - pointer to an array of USB8s
|
|
* len - number of USB8s to hash
|
|
* state - the state to hash or NULL
|
|
*
|
|
* returns:
|
|
* the new state
|
|
*/
|
|
HASH *
|
|
hash_usb8(int type, USB8 *byte, int len, HASH *state)
|
|
{
|
|
/*
|
|
* initialize if state is NULL
|
|
*/
|
|
if (state == NULL) {
|
|
state = hash_init(type, NULL);
|
|
}
|
|
|
|
/*
|
|
* setup for the string hash
|
|
*/
|
|
if (!state->bytes) {
|
|
(state->chkpt)(state);
|
|
state->bytes = true;
|
|
}
|
|
|
|
/*
|
|
* hash the array of octets
|
|
*/
|
|
(state->update)(state, byte, (USB32)len);
|
|
|
|
/*
|
|
* all done
|
|
*/
|
|
return state;
|
|
}
|
|
|
|
|
|
/*
|
|
* hash_value - hash a value
|
|
*
|
|
* given:
|
|
* type - hash type (see hash.h)
|
|
* v - the value
|
|
* state - the state to hash or NULL
|
|
*
|
|
* returns:
|
|
* the new state
|
|
*/
|
|
HASH *
|
|
hash_value(int type, void *v, HASH *state)
|
|
{
|
|
LISTELEM *ep; /* list element pointer */
|
|
ASSOCELEM **assochead; /* association chain head */
|
|
ASSOCELEM *aep; /* current association value */
|
|
ASSOCELEM *nextaep; /* next association value */
|
|
VALUE *value = (VALUE *)v; /* v cast to a VALUE */
|
|
VALUE *vp; /* pointer to next OBJ table value */
|
|
ZVALUE fileval; /* size, position, dev, inode of a file */
|
|
int i;
|
|
|
|
/*
|
|
* initialize if state is NULL
|
|
*/
|
|
if (state == NULL) {
|
|
state = hash_init(type, NULL);
|
|
}
|
|
|
|
/*
|
|
* process the value type
|
|
*/
|
|
switch (value->v_type) {
|
|
case V_NULL:
|
|
(state->chkpt)(state);
|
|
state->bytes = true;
|
|
break;
|
|
|
|
case V_INT:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
|
|
/* hash as if we have a 64 bit value */
|
|
state = hash_int(type, value->v_int, state);
|
|
break;
|
|
|
|
case V_NUM:
|
|
/* hash this type */
|
|
state = hash_number(type, value->v_num, state);
|
|
break;
|
|
|
|
case V_COM:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
|
|
/* hash this type */
|
|
state = hash_complex(type, value->v_com, state);
|
|
break;
|
|
|
|
case V_ADDR:
|
|
/* there is nothing to setup, simply hash what we point at */
|
|
state = hash_value(type, value->v_addr, state);
|
|
break;
|
|
|
|
case V_STR:
|
|
/* strings have no setup */
|
|
|
|
/* hash this type */
|
|
state = hash_STR(type, value->v_str, state);
|
|
break;
|
|
|
|
case V_MAT:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
state->bytes = true;
|
|
|
|
/* hash all the elements of the matrix */
|
|
for (i=0; i < value->v_mat->m_size; ++i) {
|
|
|
|
/* hash the next matrix value */
|
|
state = hash_value(type,
|
|
value->v_mat->m_table+i, state);
|
|
state->bytes = false; /* as if reading words */
|
|
}
|
|
break;
|
|
|
|
case V_LIST:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
|
|
/* hash all the elements of the list */
|
|
for (i=0, ep = value->v_list->l_first;
|
|
ep != NULL && i < value->v_list->l_count;
|
|
++i, ep = ep->e_next) {
|
|
|
|
/* hash the next list value */
|
|
state = hash_value(type, &ep->e_value, state);
|
|
state->bytes = false; /* as if reading words */
|
|
}
|
|
break;
|
|
|
|
case V_ASSOC:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
state->bytes = true;
|
|
|
|
/* hash the association */
|
|
assochead = value->v_assoc->a_table;
|
|
for (i = 0; i < value->v_assoc->a_size; i++) {
|
|
nextaep = *assochead;
|
|
while (nextaep) {
|
|
aep = nextaep;
|
|
nextaep = aep->e_next;
|
|
|
|
/* hash the next association value */
|
|
state = hash_value(type, &aep->e_value, state);
|
|
state->bytes = false; /* as if reading words */
|
|
}
|
|
assochead++;
|
|
}
|
|
break;
|
|
|
|
case V_OBJ:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
state->bytes = true; /* reading bytes */
|
|
|
|
/* hash the object name and then the element values */
|
|
|
|
state = hash_str(type, objtypename(
|
|
value->v_obj->o_actions->oa_index), state);
|
|
(state->chkpt)(state);
|
|
|
|
for (i=value->v_obj->o_actions->oa_count,
|
|
vp=value->v_obj->o_table;
|
|
i-- > 0;
|
|
vp++) {
|
|
|
|
/* hash the next object value */
|
|
state = hash_value(type, vp, state);
|
|
state->bytes = false; /* as if reading words */
|
|
}
|
|
break;
|
|
|
|
case V_FILE:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
|
|
/* hash file length if possible */
|
|
if (getsize(value->v_file, &fileval) == 0) {
|
|
state = hash_zvalue(type, fileval, state);
|
|
zfree(fileval);
|
|
} else {
|
|
/* hash -1 for invalid length */
|
|
state = hash_long(type, (long)-1, state);
|
|
}
|
|
/* hash the file position if possible */
|
|
if (getloc(value->v_file, &fileval) == 0) {
|
|
state = hash_zvalue(type, fileval, state);
|
|
zfree(fileval);
|
|
} else {
|
|
/* hash -1 for invalid location */
|
|
state = hash_long(type, (long)-1, state);
|
|
}
|
|
/* hash the file device if possible */
|
|
if (get_device(value->v_file, &fileval) == 0) {
|
|
state = hash_zvalue(type, fileval, state);
|
|
zfree(fileval);
|
|
} else {
|
|
/* hash -1 for invalid device */
|
|
state = hash_long(type, (long)-1, state);
|
|
}
|
|
/* hash the file inode if possible */
|
|
if (get_inode(value->v_file, &fileval) == 0) {
|
|
state = hash_zvalue(type, fileval, state);
|
|
zfree(fileval);
|
|
} else {
|
|
/* hash -1 for invalid inode */
|
|
state = hash_long(type, (long)-1, state);
|
|
}
|
|
break;
|
|
|
|
case V_RAND:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
|
|
/* hash the RAND state */
|
|
state = hash_int(type, value->v_rand->seeded, state);
|
|
state = hash_int(type, value->v_rand->bits, state);
|
|
(state->update)(state,
|
|
(USB8 *)value->v_rand->buffer, SLEN*FULL_BITS/8);
|
|
state = hash_int(type, value->v_rand->j, state);
|
|
state = hash_int(type, value->v_rand->k, state);
|
|
state = hash_int(type, value->v_rand->need_to_skip, state);
|
|
(state->update)(state,
|
|
(USB8 *)value->v_rand->slot, SCNT*FULL_BITS/8);
|
|
(state->update)(state,
|
|
(USB8*)value->v_rand->shuf, SHUFLEN*FULL_BITS/8);
|
|
state->bytes = false; /* as if reading words */
|
|
break;
|
|
|
|
case V_RANDOM:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
|
|
/* hash the RANDOM state */
|
|
state = hash_int(type, value->v_random->seeded, state);
|
|
state = hash_int(type, value->v_random->bits, state);
|
|
(state->update)(state,
|
|
(USB8 *)&(value->v_random->buffer), BASEB/8);
|
|
state = hash_zvalue(type, value->v_random->r, state);
|
|
state = hash_zvalue(type, value->v_random->n, state);
|
|
state->bytes = false; /* as if reading words */
|
|
break;
|
|
|
|
case V_CONFIG:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
|
|
/* hash the CONFIG state */
|
|
state = hash_int(type, value->v_config->outmode, state);
|
|
state = hash_int(type, value->v_config->outmode2, state);
|
|
state = hash_long(type,(long)value->v_config->outdigits, state);
|
|
state = hash_number(type, value->v_config->epsilon, state);
|
|
state = hash_long(type,
|
|
(long)value->v_config->epsilonprec, state);
|
|
state = hash_flag(type, value->v_config->traceflags, state);
|
|
state = hash_long(type, (long)value->v_config->maxprint, state);
|
|
state = hash_len(type, value->v_config->mul2, state);
|
|
state = hash_len(type, value->v_config->sq2, state);
|
|
state = hash_len(type, value->v_config->pow2, state);
|
|
state = hash_len(type, value->v_config->redc2, state);
|
|
state = hash_bool(type, value->v_config->tilde_ok, state);
|
|
state = hash_bool(type, value->v_config->tilde_space, state);
|
|
state = hash_bool(type, value->v_config->tab_ok, state);
|
|
state = hash_long(type, (long)value->v_config->quomod, state);
|
|
state = hash_long(type, (long)value->v_config->quo, state);
|
|
state = hash_long(type, (long)value->v_config->mod, state);
|
|
state = hash_long(type, (long)value->v_config->sqrt, state);
|
|
state = hash_long(type, (long)value->v_config->appr, state);
|
|
state = hash_long(type, (long)value->v_config->cfappr, state);
|
|
state = hash_long(type, (long)value->v_config->cfsim, state);
|
|
state = hash_long(type, (long)value->v_config->outround, state);
|
|
state = hash_long(type, (long)value->v_config->round, state);
|
|
state = hash_long(type, (long)value->v_config->triground, state);
|
|
state = hash_bool(type, value->v_config->leadzero, state);
|
|
state = hash_bool(type, value->v_config->fullzero, state);
|
|
state = hash_long(type,
|
|
(long)value->v_config->maxscancount, state);
|
|
state = hash_str(type, value->v_config->prompt1, state);
|
|
state->bytes = false; /* as if just read words */
|
|
state = hash_str(type, value->v_config->prompt2, state);
|
|
state->bytes = false; /* as if just read words */
|
|
state = hash_int(type, value->v_config->blkmaxprint, state);
|
|
state = hash_bool(type, value->v_config->blkverbose, state);
|
|
state = hash_int(type, value->v_config->blkbase, state);
|
|
state = hash_int(type, value->v_config->blkfmt, state);
|
|
state = hash_long(type,
|
|
(long)value->v_config->resource_debug, state);
|
|
state = hash_long(type,
|
|
(long)value->v_config->calc_debug, state);
|
|
state = hash_long(type,
|
|
(long)value->v_config->user_debug, state);
|
|
state = hash_bool(type, value->v_config->verbose_quit, state);
|
|
state = hash_int(type, value->v_config->ctrl_d, state);
|
|
state = hash_str(type, value->v_config->program, state);
|
|
state = hash_str(type, value->v_config->base_name, state);
|
|
state = hash_bool(type, value->v_config->windows, state);
|
|
state = hash_bool(type, value->v_config->cygwin, state);
|
|
state = hash_bool(type, value->v_config->compile_custom, state);
|
|
if (value->v_config->allow_custom != NULL &&
|
|
*(value->v_config->allow_custom)) {
|
|
state = hash_bool(type, true, state);
|
|
} else {
|
|
state = hash_bool(type, false, state);
|
|
}
|
|
state = hash_str(type, value->v_config->version, state);
|
|
state = hash_int(type, value->v_config->baseb, state);
|
|
state = hash_bool(type, value->v_config->redecl_warn, state);
|
|
state = hash_bool(type, value->v_config->dupvar_warn, state);
|
|
state = hash_bool(type, value->v_config->fraction_space, state);
|
|
break;
|
|
|
|
case V_HASH:
|
|
/* setup for the this value type */
|
|
(state->chkpt)(state);
|
|
(state->type)(value->v_type, state);
|
|
|
|
/* hash the HASH state */
|
|
state = hash_int(type, value->v_hash->type, state);
|
|
state = hash_bool(type, value->v_hash->bytes,state);
|
|
state = hash_int(type, value->v_hash->base, state);
|
|
state = hash_int(type, value->v_hash->chunksize, state);
|
|
state = hash_int(type, value->v_hash->unionsize, state);
|
|
(state->update)(state,
|
|
value->v_hash->h_union.data, state->unionsize);
|
|
state->bytes = false; /* as if reading words */
|
|
break;
|
|
|
|
case V_BLOCK:
|
|
/* there is no setup for a BLOCK */
|
|
|
|
/* hash the octets in the BLOCK */
|
|
if (value->v_block->datalen > 0) {
|
|
state = hash_usb8(type, value->v_block->data,
|
|
value->v_block->datalen, state);
|
|
}
|
|
break;
|
|
|
|
case V_OCTET:
|
|
/* there is no setup for an OCTET */
|
|
|
|
/* hash the OCTET */
|
|
state = hash_usb8(type, value->v_octet, 1, state);
|
|
break;
|
|
|
|
case V_NBLOCK:
|
|
/* there is no setup for a NBLOCK */
|
|
|
|
/* hash the octets in the NBLOCK */
|
|
if (value->v_nblock->blk->datalen > 0) {
|
|
state = hash_usb8(type, value->v_nblock->blk->data,
|
|
value->v_nblock->blk->datalen,
|
|
state);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
math_error("hashing an unknown value");
|
|
not_reached();
|
|
}
|
|
return state;
|
|
}
|