int64.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:13k
- /** file: test.c - test of 64-bit integer stuff
- *
- *
- * 21-jan-1998: David Perkins <dperkins@dsperkins.com>
- *
- */
- #include <net-snmp/net-snmp-config.h>
- #include <sys/types.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #if HAVE_STRING_H
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #if HAVE_WINSOCK_H
- #include <winsock.h>
- #endif
- #include <net-snmp/types.h>
- #include <net-snmp/library/int64.h>
- #include <net-snmp/library/snmp_assert.h>
- #include <net-snmp/library/snmp_debug.h>
- #include <net-snmp/library/snmp_logging.h>
- #define TRUE 1
- #define FALSE 0
- /** divBy10 - divide an unsigned 64-bit integer by 10
- *
- * call with:
- * u64 - number to be divided
- * pu64Q - location to store quotient
- * puR - location to store remainder
- *
- */
- void
- divBy10(U64 u64, U64 * pu64Q, unsigned int *puR)
- {
- unsigned long ulT;
- unsigned long ulQ;
- unsigned long ulR;
- /*
- * top 16 bits
- */
- ulT = (u64.high >> 16) & 0x0ffff;
- ulQ = ulT / 10;
- ulR = ulT % 10;
- pu64Q->high = ulQ << 16;
- /*
- * next 16
- */
- ulT = (u64.high & 0x0ffff);
- ulT += (ulR << 16);
- ulQ = ulT / 10;
- ulR = ulT % 10;
- pu64Q->high = pu64Q->high | ulQ;
- /*
- * next 16
- */
- ulT = ((u64.low >> 16) & 0x0ffff) + (ulR << 16);
- ulQ = ulT / 10;
- ulR = ulT % 10;
- pu64Q->low = ulQ << 16;
- /*
- * final 16
- */
- ulT = (u64.low & 0x0ffff);
- ulT += (ulR << 16);
- ulQ = ulT / 10;
- ulR = ulT % 10;
- pu64Q->low = pu64Q->low | ulQ;
- *puR = (unsigned int) (ulR);
- } /* divBy10 */
- /** multBy10 - multiply an unsigned 64-bit integer by 10
- *
- * call with:
- * u64 - number to be multiplied
- * pu64P - location to store product
- *
- */
- void
- multBy10(U64 u64, U64 * pu64P)
- {
- unsigned long ulT;
- unsigned long ulP;
- unsigned long ulK;
- /*
- * lower 16 bits
- */
- ulT = u64.low & 0x0ffff;
- ulP = ulT * 10;
- ulK = ulP >> 16;
- pu64P->low = ulP & 0x0ffff;
- /*
- * next 16
- */
- ulT = (u64.low >> 16) & 0x0ffff;
- ulP = (ulT * 10) + ulK;
- ulK = ulP >> 16;
- pu64P->low = (ulP & 0x0ffff) << 16 | pu64P->low;
- /*
- * next 16 bits
- */
- ulT = u64.high & 0x0ffff;
- ulP = (ulT * 10) + ulK;
- ulK = ulP >> 16;
- pu64P->high = ulP & 0x0ffff;
- /*
- * final 16
- */
- ulT = (u64.high >> 16) & 0x0ffff;
- ulP = (ulT * 10) + ulK;
- ulK = ulP >> 16;
- pu64P->high = (ulP & 0x0ffff) << 16 | pu64P->high;
- } /* multBy10 */
- /** incrByU16 - add an unsigned 16-bit int to an unsigned 64-bit integer
- *
- * call with:
- * pu64 - number to be incremented
- * u16 - amount to add
- *
- */
- void
- incrByU16(U64 * pu64, unsigned int u16)
- {
- unsigned long ulT1;
- unsigned long ulT2;
- unsigned long ulR;
- unsigned long ulK;
- /*
- * lower 16 bits
- */
- ulT1 = pu64->low;
- ulT2 = ulT1 & 0x0ffff;
- ulR = ulT2 + u16;
- ulK = ulR >> 16;
- if (ulK == 0) {
- pu64->low = ulT1 + u16;
- return;
- }
- /*
- * next 16 bits
- */
- ulT2 = (ulT1 >> 16) & 0x0ffff;
- ulR = ulT2 + 1;
- ulK = ulR >> 16;
- if (ulK == 0) {
- pu64->low = ulT1 + u16;
- return;
- }
- /*
- * next 32 - ignore any overflow
- */
- pu64->low = (ulT1 + u16) & 0x0FFFFFFFFL;
- pu64->high++;
- #if SIZEOF_LONG != 4
- pu64->high &= 0xffffffff;
- #endif
- } /* incrByV16 */
- void
- incrByU32(U64 * pu64, unsigned int u32)
- {
- unsigned int tmp;
- tmp = pu64->low;
- pu64->low += u32;
- #if SIZEOF_LONG != 4
- pu64->low &= 0xffffffff;
- #endif
- if (pu64->low < tmp) {
- pu64->high++;
- #if SIZEOF_LONG != 4
- pu64->high &= 0xffffffff;
- #endif
- }
- }
- /**
- * pu64out = pu64one - pu64two
- */
- void
- u64Subtract(const U64 * pu64one, const U64 * pu64two, U64 * pu64out)
- {
- if (pu64one->low < pu64two->low) {
- pu64out->low = 0xffffffff - pu64two->low + pu64one->low + 1;
- pu64out->high = pu64one->high - pu64two->high - 1;
- } else {
- pu64out->low = pu64one->low - pu64two->low;
- pu64out->high = pu64one->high - pu64two->high;
- }
- }
- /**
- * pu64out += pu64one
- */
- void
- u64Incr(U64 * pu64out, const U64 * pu64one)
- {
- pu64out->high += pu64one->high;
- #if SIZEOF_LONG != 4
- pu64out->high &= 0xffffffff;
- #endif
- incrByU32(pu64out, pu64one->low);
- }
- /**
- * pu64out += (pu64one - pu64two)
- */
- void
- u64UpdateCounter(U64 * pu64out, const U64 * pu64one, const U64 * pu64two)
- {
- U64 tmp;
- u64Subtract(pu64one, pu64two, &tmp);
- u64Incr(pu64out, &tmp);
- }
- /**
- * pu64one = pu64two
- */
- void
- u64Copy(U64 * pu64one, const U64 * pu64two)
- {
- pu64one->high = pu64two->high;
- pu64one->low = pu64two->low;
- }
- /** zeroU64 - set an unsigned 64-bit number to zero
- *
- * call with:
- * pu64 - number to be zero'ed
- *
- */
- void
- zeroU64(U64 * pu64)
- {
- pu64->low = 0;
- pu64->high = 0;
- } /* zeroU64 */
- /** isZeroU64 - check if an unsigned 64-bit number is
- *
- * call with:
- * pu64 - number to be zero'ed
- *
- */
- int
- isZeroU64(const U64 * pu64)
- {
- if ((pu64->low == 0) && (pu64->high == 0))
- return (TRUE);
- else
- return (FALSE);
- } /* isZeroU64 */
- /**
- * check the old and new values of a counter64 for 32bit wrapping
- *
- * @param adjust : set to 1 to auto-increment new_val->high
- * if a 32bit wrap is detected.
- *
- *@Note:
- * The old and new values must be be from within a time period
- * which would only allow the 32bit portion of the counter to
- * wrap once. i.e. if the 32bit portion of the counter could
- * wrap every 60 seconds, the old and new values should be compared
- * at least every 59 seconds (though I'd recommend at least every
- * 50 seconds to allow for timer inaccuracies).
- *
- * @retval 64 : 64bit wrap
- * @retval 32 : 32bit wrap
- * @retval 0 : did not wrap
- * @retval -1 : bad parameter
- * @retval -2 : unexpected high value (changed by more than 1)
- */
- int
- netsnmp_c64_check_for_32bit_wrap(struct counter64 *old_val,
- struct counter64 *new_val,
- int adjust)
- {
- if( (NULL == old_val) || (NULL == new_val) )
- return -1;
- DEBUGMSGTL(("9:c64:check_wrap", "check wrap 0x%0x.0x%0x 0x%0x.0x%0xn",
- old_val->high, old_val->low, new_val->high, new_val->low));
-
- /*
- * check for wraps
- */
- if ((new_val->low >= old_val->low) &&
- (new_val->high == old_val->high)) {
- DEBUGMSGTL(("9:c64:check_wrap", "no wrapn"));
- return 0;
- }
- /*
- * low wrapped. did high change?
- */
- if (new_val->high == old_val->high) {
- DEBUGMSGTL(("c64:check_wrap", "32 bit wrapn"));
- if (adjust) {
- ++new_val->high;
- #if SIZEOF_LONG != 4
- new_val->high &= 0xffffffff;
- #endif
- }
- return 32;
- }
- else if ((new_val->high == (old_val->high + 1)) ||
- ((0 == new_val->high) && (0xffffffff == old_val->high))) {
- DEBUGMSGTL(("c64:check_wrap", "64 bit wrapn"));
- return 64;
- }
- return -2;
- }
- /**
- * update a 64 bit value with the difference between two (possibly) 32 bit vals
- *
- * @param prev_val : the 64 bit current counter
- * @param old_prev_val : the (possibly 32 bit) previous value
- * @param new_val : the (possible 32bit) new value
- * @param need_wrap_check: pointer to integer indicating if wrap check is needed
- * flag may be cleared if 64 bit counter is detected
- *
- *@Note:
- * The old_prev_val and new_val values must be be from within a time
- * period which would only allow the 32bit portion of the counter to
- * wrap once. i.e. if the 32bit portion of the counter could
- * wrap every 60 seconds, the old and new values should be compared
- * at least every 59 seconds (though I'd recommend at least every
- * 50 seconds to allow for timer inaccuracies).
- *
- * Suggested use:
- *
- * static needwrapcheck = 1;
- * static counter64 current, prev_val, new_val;
- *
- * your_functions_to_update_new_value(&new_val);
- * if (0 == needwrapcheck)
- * memcpy(current, new_val, sizeof(new_val));
- * else {
- * netsnmp_c64_check32_and_update(¤t,&new,&prev,&needwrapcheck);
- * memcpy(prev_val, new_val, sizeof(new_val));
- * }
- *
- *
- * @retval 0 : success
- * @retval -1 : error checking for 32 bit wrap
- * @retval -2 : look like we have 64 bit values, but sums aren't consistent
- */
- int
- netsnmp_c64_check32_and_update(struct counter64 *prev_val, struct counter64 *new_val,
- struct counter64 *old_prev_val, int *need_wrap_check)
- {
- int rc;
- /*
- * counters are 32bit or unknown (which we'll treat as 32bit).
- * update the prev values with the difference between the
- * new stats and the prev old_stats:
- * prev->stats += (new->stats - prev->old_stats)
- */
- if ((NULL == need_wrap_check) || (0 != *need_wrap_check)) {
- rc = netsnmp_c64_check_for_32bit_wrap(old_prev_val,new_val, 1);
- if (rc < 0) {
- snmp_log(LOG_ERR,"c64 32 bit check failedn");
- return -1;
- }
- }
- else
- rc = 0;
-
- /*
- * update previous values
- */
- (void) u64UpdateCounter(prev_val, new_val, old_prev_val);
- /*
- * if wrap check was 32 bit, undo adjust, now that prev is updated
- */
- if (32 == rc) {
- /*
- * check wrap incremented high, so reset it. (Because having
- * high set for a 32 bit counter will confuse us in the next update).
- */
- netsnmp_assert(1 == new_val->high);
- new_val->high = 0;
- }
- else if (64 == rc) {
- /*
- * if we really have 64 bit counters, the summing we've been
- * doing for prev values should be equal to the new values.
- */
- if ((prev_val->low != new_val->low) ||
- (prev_val->high != new_val->high)) {
- snmp_log(LOG_ERR, "looks like a 64bit wrap, but prev!=newn");
- return -2;
- }
- else if (NULL != need_wrap_check)
- *need_wrap_check = 0;
- }
-
- return 0;
- }
- void
- printU64(char *buf, /* char [I64CHARSZ+1]; */
- const U64 * pu64) {
- U64 u64a;
- U64 u64b;
- char aRes[I64CHARSZ + 1];
- unsigned int u;
- int j;
- u64a.high = pu64->high;
- u64a.low = pu64->low;
- aRes[I64CHARSZ] = 0;
- for (j = 0; j < I64CHARSZ; j++) {
- divBy10(u64a, &u64b, &u);
- aRes[(I64CHARSZ - 1) - j] = (char) ('0' + u);
- u64a.high = u64b.high;
- u64a.low = u64b.low;
- if (isZeroU64(&u64a))
- break;
- }
- strcpy(buf, &aRes[(I64CHARSZ - 1) - j]);
- }
- void
- printI64(char *buf, /* char [I64CHARSZ+1]; */
- const U64 * pu64) {
- U64 u64a;
- U64 u64b;
- char aRes[I64CHARSZ + 1];
- unsigned int u;
- int j, sign = 0;
- if (pu64->high & 0x80000000) {
- u64a.high = ~pu64->high;
- u64a.low = ~pu64->low;
- sign = 1;
- incrByU32(&u64a, 1); /* bit invert and incr by 1 to print 2s complement */
- } else {
- u64a.high = pu64->high;
- u64a.low = pu64->low;
- }
- aRes[I64CHARSZ] = 0;
- for (j = 0; j < I64CHARSZ; j++) {
- divBy10(u64a, &u64b, &u);
- aRes[(I64CHARSZ - 1) - j] = (char) ('0' + u);
- u64a.high = u64b.high;
- u64a.low = u64b.low;
- if (isZeroU64(&u64a))
- break;
- }
- if (sign == 1) {
- aRes[(I64CHARSZ - 1) - j - 1] = '-';
- strcpy(buf, &aRes[(I64CHARSZ - 1) - j - 1]);
- return;
- }
- strcpy(buf, &aRes[(I64CHARSZ - 1) - j]);
- }
- int
- read64(U64 * i64, const char *str)
- {
- U64 i64p;
- unsigned int u;
- int sign = 0;
- int ok = 0;
- zeroU64(i64);
- if (*str == '-') {
- sign = 1;
- str++;
- }
- while (*str && isdigit(*str)) {
- ok = 1;
- u = *str - '0';
- multBy10(*i64, &i64p);
- memcpy(i64, &i64p, sizeof(i64p));
- incrByU16(i64, u);
- str++;
- }
- if (sign) {
- i64->high = ~i64->high;
- i64->low = ~i64->low;
- incrByU16(i64, 1);
- }
- return ok;
- }
- #ifdef TESTING
- void
- main(int argc, char *argv[])
- {
- int i;
- int j;
- int l;
- unsigned int u;
- U64 u64a;
- U64 u64b;
- #define MXSZ 20
- char aRes[MXSZ + 1];
- if (argc < 2) {
- printf("This program takes numbers from the command linen"
- "and prints them out.n" "Usage: test <unsignedInt>...n");
- exit(1);
- }
- aRes[MXSZ] = 0;
- for (i = 1; i < argc; i++) {
- l = strlen(argv[i]);
- zeroU64(&u64a);
- for (j = 0; j < l; j++) {
- if (!isdigit(argv[i][j])) {
- printf("Argument is not a number "%s"n", argv[i]);
- exit(1);
- }
- u = argv[i][j] - '0';
- multBy10(u64a, &u64b);
- u64a = u64b;
- incrByU16(&u64a, u);
- }
- printf("number "%s" in hex is '%08x%08x'hn",
- argv[i], u64a.high, u64a.low);
- printf("number is "%s"n", printU64(&u64a));
- for (j = 0; j < MXSZ; j++) {
- divBy10(u64a, &u64b, &u);
- aRes[(MXSZ - 1) - j] = (char) ('0' + u);
- u64a = u64b;
- if (isZeroU64(&u64a))
- break;
- }
- printf("number is "%s"n", &aRes[(MXSZ - 1) - j]);
- }
- exit(0);
- } /* main */
- #endif /* TESTING */
- /*
- * file: test.c
- */