int64.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:13k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /** file: test.c - test of 64-bit integer stuff
  2. *
  3. *
  4. * 21-jan-1998: David Perkins <dperkins@dsperkins.com>
  5. *
  6. */
  7. #include <net-snmp/net-snmp-config.h>
  8. #include <sys/types.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <ctype.h>
  12. #if HAVE_STRING_H
  13. #include <string.h>
  14. #else
  15. #include <strings.h>
  16. #endif
  17. #if HAVE_WINSOCK_H
  18. #include <winsock.h>
  19. #endif
  20. #include <net-snmp/types.h>
  21. #include <net-snmp/library/int64.h>
  22. #include <net-snmp/library/snmp_assert.h>
  23. #include <net-snmp/library/snmp_debug.h>
  24. #include <net-snmp/library/snmp_logging.h>
  25. #define TRUE 1
  26. #define FALSE 0
  27. /** divBy10 - divide an unsigned 64-bit integer by 10
  28. *
  29. * call with:
  30. *   u64 - number to be divided
  31. *   pu64Q - location to store quotient
  32. *   puR - location to store remainder
  33. *
  34. */
  35. void
  36. divBy10(U64 u64, U64 * pu64Q, unsigned int *puR)
  37. {
  38.     unsigned long   ulT;
  39.     unsigned long   ulQ;
  40.     unsigned long   ulR;
  41.     /*
  42.      * top 16 bits 
  43.      */
  44.     ulT = (u64.high >> 16) & 0x0ffff;
  45.     ulQ = ulT / 10;
  46.     ulR = ulT % 10;
  47.     pu64Q->high = ulQ << 16;
  48.     /*
  49.      * next 16 
  50.      */
  51.     ulT = (u64.high & 0x0ffff);
  52.     ulT += (ulR << 16);
  53.     ulQ = ulT / 10;
  54.     ulR = ulT % 10;
  55.     pu64Q->high = pu64Q->high | ulQ;
  56.     /*
  57.      * next 16 
  58.      */
  59.     ulT = ((u64.low >> 16) & 0x0ffff) + (ulR << 16);
  60.     ulQ = ulT / 10;
  61.     ulR = ulT % 10;
  62.     pu64Q->low = ulQ << 16;
  63.     /*
  64.      * final 16 
  65.      */
  66.     ulT = (u64.low & 0x0ffff);
  67.     ulT += (ulR << 16);
  68.     ulQ = ulT / 10;
  69.     ulR = ulT % 10;
  70.     pu64Q->low = pu64Q->low | ulQ;
  71.     *puR = (unsigned int) (ulR);
  72. }                               /* divBy10 */
  73. /** multBy10 - multiply an unsigned 64-bit integer by 10
  74. *
  75. * call with:
  76. *   u64 - number to be multiplied
  77. *   pu64P - location to store product
  78. *
  79. */
  80. void
  81. multBy10(U64 u64, U64 * pu64P)
  82. {
  83.     unsigned long   ulT;
  84.     unsigned long   ulP;
  85.     unsigned long   ulK;
  86.     /*
  87.      * lower 16 bits 
  88.      */
  89.     ulT = u64.low & 0x0ffff;
  90.     ulP = ulT * 10;
  91.     ulK = ulP >> 16;
  92.     pu64P->low = ulP & 0x0ffff;
  93.     /*
  94.      * next 16 
  95.      */
  96.     ulT = (u64.low >> 16) & 0x0ffff;
  97.     ulP = (ulT * 10) + ulK;
  98.     ulK = ulP >> 16;
  99.     pu64P->low = (ulP & 0x0ffff) << 16 | pu64P->low;
  100.     /*
  101.      * next 16 bits 
  102.      */
  103.     ulT = u64.high & 0x0ffff;
  104.     ulP = (ulT * 10) + ulK;
  105.     ulK = ulP >> 16;
  106.     pu64P->high = ulP & 0x0ffff;
  107.     /*
  108.      * final 16 
  109.      */
  110.     ulT = (u64.high >> 16) & 0x0ffff;
  111.     ulP = (ulT * 10) + ulK;
  112.     ulK = ulP >> 16;
  113.     pu64P->high = (ulP & 0x0ffff) << 16 | pu64P->high;
  114. }                               /* multBy10 */
  115. /** incrByU16 - add an unsigned 16-bit int to an unsigned 64-bit integer
  116. *
  117. * call with:
  118. *   pu64 - number to be incremented
  119. *   u16 - amount to add
  120. *
  121. */
  122. void
  123. incrByU16(U64 * pu64, unsigned int u16)
  124. {
  125.     unsigned long   ulT1;
  126.     unsigned long   ulT2;
  127.     unsigned long   ulR;
  128.     unsigned long   ulK;
  129.     /*
  130.      * lower 16 bits 
  131.      */
  132.     ulT1 = pu64->low;
  133.     ulT2 = ulT1 & 0x0ffff;
  134.     ulR = ulT2 + u16;
  135.     ulK = ulR >> 16;
  136.     if (ulK == 0) {
  137.         pu64->low = ulT1 + u16;
  138.         return;
  139.     }
  140.     /*
  141.      * next 16 bits 
  142.      */
  143.     ulT2 = (ulT1 >> 16) & 0x0ffff;
  144.     ulR = ulT2 + 1;
  145.     ulK = ulR >> 16;
  146.     if (ulK == 0) {
  147.         pu64->low = ulT1 + u16;
  148.         return;
  149.     }
  150.     /*
  151.      * next 32 - ignore any overflow 
  152.      */
  153.     pu64->low = (ulT1 + u16) & 0x0FFFFFFFFL;
  154.     pu64->high++;
  155. #if SIZEOF_LONG != 4
  156.     pu64->high &= 0xffffffff;
  157. #endif
  158. }                               /* incrByV16 */
  159. void
  160. incrByU32(U64 * pu64, unsigned int u32)
  161. {
  162.     unsigned int    tmp;
  163.     tmp = pu64->low;
  164.     pu64->low += u32;
  165. #if SIZEOF_LONG != 4
  166.     pu64->low &= 0xffffffff;
  167. #endif
  168.     if (pu64->low < tmp) {
  169.         pu64->high++;
  170. #if SIZEOF_LONG != 4
  171.         pu64->high &= 0xffffffff;
  172. #endif
  173.     }
  174. }
  175. /**
  176.  * pu64out = pu64one - pu64two 
  177.  */
  178. void
  179. u64Subtract(const U64 * pu64one, const U64 * pu64two, U64 * pu64out)
  180. {
  181.     if (pu64one->low < pu64two->low) {
  182.         pu64out->low = 0xffffffff - pu64two->low + pu64one->low + 1;
  183.         pu64out->high = pu64one->high - pu64two->high - 1;
  184.     } else {
  185.         pu64out->low = pu64one->low - pu64two->low;
  186.         pu64out->high = pu64one->high - pu64two->high;
  187.     }
  188. }
  189. /**
  190.  * pu64out += pu64one
  191.  */
  192. void
  193. u64Incr(U64 * pu64out, const U64 * pu64one)
  194. {
  195.     pu64out->high += pu64one->high;
  196. #if SIZEOF_LONG != 4
  197.     pu64out->high &= 0xffffffff;
  198. #endif
  199.     incrByU32(pu64out, pu64one->low);
  200. }
  201. /**
  202.  * pu64out += (pu64one - pu64two)
  203.  */
  204. void
  205. u64UpdateCounter(U64 * pu64out, const U64 * pu64one, const U64 * pu64two)
  206. {
  207.     U64 tmp;
  208.     u64Subtract(pu64one, pu64two, &tmp);
  209.     u64Incr(pu64out, &tmp);
  210. }
  211. /**
  212.  * pu64one = pu64two 
  213.  */
  214. void
  215. u64Copy(U64 * pu64one, const U64 * pu64two)
  216. {
  217.     pu64one->high = pu64two->high;
  218.     pu64one->low =  pu64two->low;
  219. }
  220. /** zeroU64 - set an unsigned 64-bit number to zero
  221. *
  222. * call with:
  223. *   pu64 - number to be zero'ed
  224. *
  225. */
  226. void
  227. zeroU64(U64 * pu64)
  228. {
  229.     pu64->low = 0;
  230.     pu64->high = 0;
  231. }                               /* zeroU64 */
  232. /** isZeroU64 - check if an unsigned 64-bit number is
  233. *
  234. * call with:
  235. *   pu64 - number to be zero'ed
  236. *
  237. */
  238. int
  239. isZeroU64(const U64 * pu64)
  240. {
  241.     if ((pu64->low == 0) && (pu64->high == 0))
  242.         return (TRUE);
  243.     else
  244.         return (FALSE);
  245. }                               /* isZeroU64 */
  246. /**
  247.  * check the old and new values of a counter64 for 32bit wrapping
  248.  *
  249.  * @param adjust : set to 1 to auto-increment new_val->high
  250.  *                 if a 32bit wrap is detected.
  251.  *
  252.  *@Note:
  253.  * The old and new values must be be from within a time period
  254.  * which would only allow the 32bit portion of the counter to
  255.  * wrap once. i.e. if the 32bit portion of the counter could
  256.  * wrap every 60 seconds, the old and new values should be compared
  257.  * at least every 59 seconds (though I'd recommend at least every
  258.  * 50 seconds to allow for timer inaccuracies).
  259.  *
  260.  * @retval 64 : 64bit wrap
  261.  * @retval 32 : 32bit wrap
  262.  * @retval  0 : did not wrap
  263.  * @retval -1 : bad parameter
  264.  * @retval -2 : unexpected high value (changed by more than 1)
  265.  */
  266. int
  267. netsnmp_c64_check_for_32bit_wrap(struct counter64 *old_val,
  268.                                  struct counter64 *new_val,
  269.                                  int adjust)
  270. {
  271.     if( (NULL == old_val) || (NULL == new_val) )
  272.         return -1;
  273.     DEBUGMSGTL(("9:c64:check_wrap", "check wrap 0x%0x.0x%0x 0x%0x.0x%0xn",
  274.                 old_val->high, old_val->low, new_val->high, new_val->low));
  275.     
  276.     /*
  277.      * check for wraps
  278.      */
  279.     if ((new_val->low >= old_val->low) &&
  280.         (new_val->high == old_val->high)) {
  281.         DEBUGMSGTL(("9:c64:check_wrap", "no wrapn"));
  282.         return 0;
  283.     }
  284.     /*
  285.      * low wrapped. did high change?
  286.      */
  287.     if (new_val->high == old_val->high) {
  288.         DEBUGMSGTL(("c64:check_wrap", "32 bit wrapn"));
  289.         if (adjust) {
  290.             ++new_val->high;
  291. #if SIZEOF_LONG != 4
  292.             new_val->high &= 0xffffffff;
  293. #endif
  294.         }
  295.         return 32;
  296.     }
  297.     else if ((new_val->high == (old_val->high + 1)) ||
  298.              ((0 == new_val->high) && (0xffffffff == old_val->high))) {
  299.         DEBUGMSGTL(("c64:check_wrap", "64 bit wrapn"));
  300.         return 64;
  301.     }
  302.     return -2;
  303. }
  304. /**
  305.  * update a 64 bit value with the difference between two (possibly) 32 bit vals
  306.  *
  307.  * @param prev_val       : the 64 bit current counter
  308.  * @param old_prev_val   : the (possibly 32 bit) previous value
  309.  * @param new_val        : the (possible 32bit) new value
  310.  * @param need_wrap_check: pointer to integer indicating if wrap check is needed
  311.  *                         flag may be cleared if 64 bit counter is detected
  312.  *
  313.  *@Note:
  314.  * The old_prev_val and new_val values must be be from within a time
  315.  * period which would only allow the 32bit portion of the counter to
  316.  * wrap once. i.e. if the 32bit portion of the counter could
  317.  * wrap every 60 seconds, the old and new values should be compared
  318.  * at least every 59 seconds (though I'd recommend at least every
  319.  * 50 seconds to allow for timer inaccuracies).
  320.  *
  321.  * Suggested use:
  322.  *
  323.  *   static needwrapcheck = 1;
  324.  *   static counter64 current, prev_val, new_val;
  325.  *
  326.  *   your_functions_to_update_new_value(&new_val);
  327.  *   if (0 == needwrapcheck)
  328.  *      memcpy(current, new_val, sizeof(new_val));
  329.  *   else {
  330.  *      netsnmp_c64_check32_and_update(&current,&new,&prev,&needwrapcheck);
  331.  *      memcpy(prev_val, new_val, sizeof(new_val));
  332.  *   }
  333.  *
  334.  *
  335.  * @retval  0 : success
  336.  * @retval -1 : error checking for 32 bit wrap
  337.  * @retval -2 : look like we have 64 bit values, but sums aren't consistent
  338.  */
  339. int
  340. netsnmp_c64_check32_and_update(struct counter64 *prev_val, struct counter64 *new_val,
  341.                                struct counter64 *old_prev_val, int *need_wrap_check)
  342. {
  343.     int rc;
  344.     /*
  345.      * counters are 32bit or unknown (which we'll treat as 32bit).
  346.      * update the prev values with the difference between the
  347.      * new stats and the prev old_stats:
  348.      *    prev->stats += (new->stats - prev->old_stats)
  349.      */
  350.     if ((NULL == need_wrap_check) || (0 != *need_wrap_check)) {
  351.         rc = netsnmp_c64_check_for_32bit_wrap(old_prev_val,new_val, 1);
  352.         if (rc < 0) {
  353.             snmp_log(LOG_ERR,"c64 32 bit check failedn");
  354.             return -1;
  355.         }
  356.     }
  357.     else
  358.         rc = 0;
  359.     
  360.     /*
  361.      * update previous values
  362.      */
  363.     (void) u64UpdateCounter(prev_val, new_val, old_prev_val);
  364.     /*
  365.      * if wrap check was 32 bit, undo adjust, now that prev is updated
  366.      */
  367.     if (32 == rc) {
  368.         /*
  369.          * check wrap incremented high, so reset it. (Because having
  370.          * high set for a 32 bit counter will confuse us in the next update).
  371.          */
  372.         netsnmp_assert(1 == new_val->high);
  373.         new_val->high = 0;
  374.     }
  375.     else if (64 == rc) {
  376.         /*
  377.          * if we really have 64 bit counters, the summing we've been
  378.          * doing for prev values should be equal to the new values.
  379.          */
  380.         if ((prev_val->low != new_val->low) ||
  381.             (prev_val->high != new_val->high)) {
  382.             snmp_log(LOG_ERR, "looks like a 64bit wrap, but prev!=newn");
  383.             return -2;
  384.         }
  385.         else if (NULL != need_wrap_check)
  386.             *need_wrap_check = 0;
  387.     }
  388.     
  389.     return 0;
  390. }
  391. void
  392. printU64(char *buf,     /* char [I64CHARSZ+1]; */
  393.                          const U64 * pu64) {
  394.     U64             u64a;
  395.     U64             u64b;
  396.     char            aRes[I64CHARSZ + 1];
  397.     unsigned int    u;
  398.     int             j;
  399.     u64a.high = pu64->high;
  400.     u64a.low = pu64->low;
  401.     aRes[I64CHARSZ] = 0;
  402.     for (j = 0; j < I64CHARSZ; j++) {
  403.         divBy10(u64a, &u64b, &u);
  404.         aRes[(I64CHARSZ - 1) - j] = (char) ('0' + u);
  405.         u64a.high = u64b.high;
  406.         u64a.low = u64b.low;
  407.         if (isZeroU64(&u64a))
  408.             break;
  409.     }
  410.     strcpy(buf, &aRes[(I64CHARSZ - 1) - j]);
  411. }
  412. void
  413. printI64(char *buf,     /* char [I64CHARSZ+1]; */
  414.                          const U64 * pu64) {
  415.     U64             u64a;
  416.     U64             u64b;
  417.     char            aRes[I64CHARSZ + 1];
  418.     unsigned int    u;
  419.     int             j, sign = 0;
  420.     if (pu64->high & 0x80000000) {
  421.         u64a.high = ~pu64->high;
  422.         u64a.low = ~pu64->low;
  423.         sign = 1;
  424.         incrByU32(&u64a, 1);    /* bit invert and incr by 1 to print 2s complement */
  425.     } else {
  426.         u64a.high = pu64->high;
  427.         u64a.low = pu64->low;
  428.     }
  429.     aRes[I64CHARSZ] = 0;
  430.     for (j = 0; j < I64CHARSZ; j++) {
  431.         divBy10(u64a, &u64b, &u);
  432.         aRes[(I64CHARSZ - 1) - j] = (char) ('0' + u);
  433.         u64a.high = u64b.high;
  434.         u64a.low = u64b.low;
  435.         if (isZeroU64(&u64a))
  436.             break;
  437.     }
  438.     if (sign == 1) {
  439.         aRes[(I64CHARSZ - 1) - j - 1] = '-';
  440.         strcpy(buf, &aRes[(I64CHARSZ - 1) - j - 1]);
  441.         return;
  442.     }
  443.     strcpy(buf, &aRes[(I64CHARSZ - 1) - j]);
  444. }
  445. int
  446. read64(U64 * i64, const char *str)
  447. {
  448.     U64             i64p;
  449.     unsigned int    u;
  450.     int             sign = 0;
  451.     int             ok = 0;
  452.     zeroU64(i64);
  453.     if (*str == '-') {
  454.         sign = 1;
  455.         str++;
  456.     }
  457.     while (*str && isdigit(*str)) {
  458.         ok = 1;
  459.         u = *str - '0';
  460.         multBy10(*i64, &i64p);
  461.         memcpy(i64, &i64p, sizeof(i64p));
  462.         incrByU16(i64, u);
  463.         str++;
  464.     }
  465.     if (sign) {
  466.         i64->high = ~i64->high;
  467.         i64->low = ~i64->low;
  468.         incrByU16(i64, 1);
  469.     }
  470.     return ok;
  471. }
  472. #ifdef TESTING
  473. void
  474. main(int argc, char *argv[])
  475. {
  476.     int             i;
  477.     int             j;
  478.     int             l;
  479.     unsigned int    u;
  480.     U64             u64a;
  481.     U64             u64b;
  482. #define MXSZ 20
  483.     char            aRes[MXSZ + 1];
  484.     if (argc < 2) {
  485.         printf("This program takes numbers from the command linen"
  486.                "and prints them out.n" "Usage: test <unsignedInt>...n");
  487.         exit(1);
  488.     }
  489.     aRes[MXSZ] = 0;
  490.     for (i = 1; i < argc; i++) {
  491.         l = strlen(argv[i]);
  492.         zeroU64(&u64a);
  493.         for (j = 0; j < l; j++) {
  494.             if (!isdigit(argv[i][j])) {
  495.                 printf("Argument is not a number "%s"n", argv[i]);
  496.                 exit(1);
  497.             }
  498.             u = argv[i][j] - '0';
  499.             multBy10(u64a, &u64b);
  500.             u64a = u64b;
  501.             incrByU16(&u64a, u);
  502.         }
  503.         printf("number "%s" in hex is '%08x%08x'hn",
  504.                argv[i], u64a.high, u64a.low);
  505.         printf("number is "%s"n", printU64(&u64a));
  506.         for (j = 0; j < MXSZ; j++) {
  507.             divBy10(u64a, &u64b, &u);
  508.             aRes[(MXSZ - 1) - j] = (char) ('0' + u);
  509.             u64a = u64b;
  510.             if (isZeroU64(&u64a))
  511.                 break;
  512.         }
  513.         printf("number is "%s"n", &aRes[(MXSZ - 1) - j]);
  514.     }
  515.     exit(0);
  516. }                               /* main */
  517. #endif                          /* TESTING */
  518. /*
  519.  * file: test.c 
  520.  */