net-snmp 5.7
int64.c
00001 
00008 #include <net-snmp/net-snmp-config.h>
00009 #include <sys/types.h>
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <ctype.h>
00013 #if HAVE_STRING_H
00014 #include <string.h>
00015 #else
00016 #include <strings.h>
00017 #endif
00018 
00019 #include <net-snmp/types.h>
00020 #include <net-snmp/library/int64.h>
00021 #include <net-snmp/library/snmp_assert.h>
00022 #include <net-snmp/library/snmp_debug.h>
00023 #include <net-snmp/library/snmp_logging.h>
00024 
00025 #include <net-snmp/net-snmp-features.h>
00026 
00027 #define TRUE 1
00028 #define FALSE 0
00029 
00038 void
00039 divBy10(U64 u64, U64 * pu64Q, unsigned int *puR)
00040 {
00041     unsigned long   ulT;
00042     unsigned long   ulQ;
00043     unsigned long   ulR;
00044 
00045 
00046     /*
00047      * top 16 bits 
00048      */
00049     ulT = (u64.high >> 16) & 0x0ffff;
00050     ulQ = ulT / 10;
00051     ulR = ulT % 10;
00052     pu64Q->high = ulQ << 16;
00053 
00054     /*
00055      * next 16 
00056      */
00057     ulT = (u64.high & 0x0ffff);
00058     ulT += (ulR << 16);
00059     ulQ = ulT / 10;
00060     ulR = ulT % 10;
00061     pu64Q->high = pu64Q->high | ulQ;
00062 
00063     /*
00064      * next 16 
00065      */
00066     ulT = ((u64.low >> 16) & 0x0ffff) + (ulR << 16);
00067     ulQ = ulT / 10;
00068     ulR = ulT % 10;
00069     pu64Q->low = ulQ << 16;
00070 
00071     /*
00072      * final 16 
00073      */
00074     ulT = (u64.low & 0x0ffff);
00075     ulT += (ulR << 16);
00076     ulQ = ulT / 10;
00077     ulR = ulT % 10;
00078     pu64Q->low = pu64Q->low | ulQ;
00079 
00080     *puR = (unsigned int) (ulR);
00081 
00082 
00083 }                               /* divBy10 */
00084 
00085 
00093 void
00094 multBy10(U64 u64, U64 * pu64P)
00095 {
00096     unsigned long   ulT;
00097     unsigned long   ulP;
00098     unsigned long   ulK;
00099 
00100 
00101     /*
00102      * lower 16 bits 
00103      */
00104     ulT = u64.low & 0x0ffff;
00105     ulP = ulT * 10;
00106     ulK = ulP >> 16;
00107     pu64P->low = ulP & 0x0ffff;
00108 
00109     /*
00110      * next 16 
00111      */
00112     ulT = (u64.low >> 16) & 0x0ffff;
00113     ulP = (ulT * 10) + ulK;
00114     ulK = ulP >> 16;
00115     pu64P->low = (ulP & 0x0ffff) << 16 | pu64P->low;
00116 
00117     /*
00118      * next 16 bits 
00119      */
00120     ulT = u64.high & 0x0ffff;
00121     ulP = (ulT * 10) + ulK;
00122     ulK = ulP >> 16;
00123     pu64P->high = ulP & 0x0ffff;
00124 
00125     /*
00126      * final 16 
00127      */
00128     ulT = (u64.high >> 16) & 0x0ffff;
00129     ulP = (ulT * 10) + ulK;
00130     ulK = ulP >> 16;
00131     pu64P->high = (ulP & 0x0ffff) << 16 | pu64P->high;
00132 
00133 
00134 }                               /* multBy10 */
00135 
00136 
00144 void
00145 incrByU16(U64 * pu64, unsigned int u16)
00146 {
00147     unsigned long   ulT1;
00148     unsigned long   ulT2;
00149     unsigned long   ulR;
00150     unsigned long   ulK;
00151 
00152 
00153     /*
00154      * lower 16 bits 
00155      */
00156     ulT1 = pu64->low;
00157     ulT2 = ulT1 & 0x0ffff;
00158     ulR = ulT2 + u16;
00159     ulK = ulR >> 16;
00160     if (ulK == 0) {
00161         pu64->low = ulT1 + u16;
00162         return;
00163     }
00164 
00165     /*
00166      * next 16 bits 
00167      */
00168     ulT2 = (ulT1 >> 16) & 0x0ffff;
00169     ulR = ulT2 + 1;
00170     ulK = ulR >> 16;
00171     if (ulK == 0) {
00172         pu64->low = ulT1 + u16;
00173         return;
00174     }
00175 
00176     /*
00177      * next 32 - ignore any overflow 
00178      */
00179     pu64->low = (ulT1 + u16) & 0x0FFFFFFFFL;
00180     pu64->high++;
00181 #if SIZEOF_LONG != 4
00182     pu64->high &= 0xffffffff;
00183 #endif
00184 }                               /* incrByV16 */
00185 
00186 void
00187 incrByU32(U64 * pu64, unsigned int u32)
00188 {
00189     unsigned int    tmp;
00190     tmp = pu64->low;
00191     pu64->low += u32;
00192 #if SIZEOF_LONG != 4
00193     pu64->low &= 0xffffffff;
00194 #endif
00195     if (pu64->low < tmp) {
00196         pu64->high++;
00197 #if SIZEOF_LONG != 4
00198         pu64->high &= 0xffffffff;
00199 #endif
00200     }
00201 }
00202 
00206 void
00207 u64Subtract(const U64 * pu64one, const U64 * pu64two, U64 * pu64out)
00208 {
00209     if (pu64one->low < pu64two->low) {
00210         pu64out->low = 0xffffffff - pu64two->low + pu64one->low + 1;
00211         pu64out->high = pu64one->high - pu64two->high - 1;
00212     } else {
00213         pu64out->low = pu64one->low - pu64two->low;
00214         pu64out->high = pu64one->high - pu64two->high;
00215     }
00216 }
00217 
00221 void
00222 u64Incr(U64 * pu64out, const U64 * pu64one)
00223 {
00224     pu64out->high += pu64one->high;
00225 #if SIZEOF_LONG != 4
00226     pu64out->high &= 0xffffffff;
00227 #endif
00228     incrByU32(pu64out, pu64one->low);
00229 }
00230 
00234 void
00235 u64UpdateCounter(U64 * pu64out, const U64 * pu64one, const U64 * pu64two)
00236 {
00237     U64 tmp;
00238     u64Subtract(pu64one, pu64two, &tmp);
00239     u64Incr(pu64out, &tmp);
00240 }
00241 
00245 netsnmp_feature_child_of(u64copy, netsnmp_unused)
00246 #ifndef NETSNMP_FEATURE_REMOVE_U64COPY
00247 void
00248 u64Copy(U64 * pu64one, const U64 * pu64two)
00249 {
00250     pu64one->high = pu64two->high;
00251     pu64one->low =  pu64two->low;
00252 }
00253 #endif /* NETSNMP_FEATURE_REMOVE_U64COPY */
00254 
00261 void
00262 zeroU64(U64 * pu64)
00263 {
00264     pu64->low = 0;
00265     pu64->high = 0;
00266 }                               /* zeroU64 */
00267 
00268 
00275 int
00276 isZeroU64(const U64 * pu64)
00277 {
00278 
00279     if ((pu64->low == 0) && (pu64->high == 0))
00280         return (TRUE);
00281     else
00282         return (FALSE);
00283 
00284 }                               /* isZeroU64 */
00285 
00309 int
00310 netsnmp_c64_check_for_32bit_wrap(struct counter64 *old_val,
00311                                  struct counter64 *new_val,
00312                                  int adjust)
00313 {
00314     if( (NULL == old_val) || (NULL == new_val) )
00315         return -1;
00316 
00317     DEBUGMSGTL(("9:c64:check_wrap", "check wrap 0x%0lx.0x%0lx 0x%0lx.0x%0lx\n",
00318                 old_val->high, old_val->low, new_val->high, new_val->low));
00319     
00320     /*
00321      * check for wraps
00322      */
00323     if ((new_val->low >= old_val->low) &&
00324         (new_val->high == old_val->high)) {
00325         DEBUGMSGTL(("9:c64:check_wrap", "no wrap\n"));
00326         return 0;
00327     }
00328 
00329     /*
00330      * low wrapped. did high change?
00331      */
00332     if (new_val->high == old_val->high) {
00333         DEBUGMSGTL(("c64:check_wrap", "32 bit wrap\n"));
00334         if (adjust) {
00335             ++new_val->high;
00336 #if SIZEOF_LONG != 4
00337             new_val->high &= 0xffffffff;
00338 #endif
00339         }
00340         return 32;
00341     }
00342     else if ((new_val->high == (old_val->high + 1)) ||
00343              ((0 == new_val->high) && (0xffffffff == old_val->high))) {
00344         DEBUGMSGTL(("c64:check_wrap", "64 bit wrap\n"));
00345         return 64;
00346     }
00347 
00348     return -2;
00349 }
00350 
00386 int
00387 netsnmp_c64_check32_and_update(struct counter64 *prev_val, struct counter64 *new_val,
00388                                struct counter64 *old_prev_val, int *need_wrap_check)
00389 {
00390     int rc;
00391 
00392     /*
00393      * counters are 32bit or unknown (which we'll treat as 32bit).
00394      * update the prev values with the difference between the
00395      * new stats and the prev old_stats:
00396      *    prev->stats += (new->stats - prev->old_stats)
00397      */
00398     if ((NULL == need_wrap_check) || (0 != *need_wrap_check)) {
00399         rc = netsnmp_c64_check_for_32bit_wrap(old_prev_val,new_val, 1);
00400         if (rc < 0) {
00401             snmp_log(LOG_ERR,"c64 32 bit check failed\n");
00402             return -1;
00403         }
00404     }
00405     else
00406         rc = 0;
00407     
00408     /*
00409      * update previous values
00410      */
00411     (void) u64UpdateCounter(prev_val, new_val, old_prev_val);
00412 
00413     /*
00414      * if wrap check was 32 bit, undo adjust, now that prev is updated
00415      */
00416     if (32 == rc) {
00417         /*
00418          * check wrap incremented high, so reset it. (Because having
00419          * high set for a 32 bit counter will confuse us in the next update).
00420          */
00421         netsnmp_assert(1 == new_val->high);
00422         new_val->high = 0;
00423     }
00424     else if (64 == rc) {
00425         /*
00426          * if we really have 64 bit counters, the summing we've been
00427          * doing for prev values should be equal to the new values.
00428          */
00429         if ((prev_val->low != new_val->low) ||
00430             (prev_val->high != new_val->high)) {
00431             snmp_log(LOG_ERR, "looks like a 64bit wrap, but prev!=new\n");
00432             return -2;
00433         }
00434         else if (NULL != need_wrap_check)
00435             *need_wrap_check = 0;
00436     }
00437     
00438     return 0;
00439 }
00440 
00441 void
00442 printU64(char *buf,     /* char [I64CHARSZ+1]; */
00443                          const U64 * pu64) {
00444     U64             u64a;
00445     U64             u64b;
00446 
00447     char            aRes[I64CHARSZ + 1];
00448     unsigned int    u;
00449     int             j;
00450 
00451     u64a.high = pu64->high;
00452     u64a.low = pu64->low;
00453     aRes[I64CHARSZ] = 0;
00454     for (j = 0; j < I64CHARSZ; j++) {
00455         divBy10(u64a, &u64b, &u);
00456         aRes[(I64CHARSZ - 1) - j] = (char) ('0' + u);
00457         u64a.high = u64b.high;
00458         u64a.low = u64b.low;
00459         if (isZeroU64(&u64a))
00460             break;
00461     }
00462     strcpy(buf, &aRes[(I64CHARSZ - 1) - j]);
00463 }
00464 
00465 void
00466 printI64(char *buf,     /* char [I64CHARSZ+1]; */
00467                          const U64 * pu64) {
00468     U64             u64a;
00469     U64             u64b;
00470 
00471     char            aRes[I64CHARSZ + 1];
00472     unsigned int    u;
00473     int             j, sign = 0;
00474 
00475     if (pu64->high & 0x80000000) {
00476         u64a.high = ~pu64->high;
00477         u64a.low = ~pu64->low;
00478         sign = 1;
00479         incrByU32(&u64a, 1);    /* bit invert and incr by 1 to print 2s complement */
00480     } else {
00481         u64a.high = pu64->high;
00482         u64a.low = pu64->low;
00483     }
00484 
00485     aRes[I64CHARSZ] = 0;
00486     for (j = 0; j < I64CHARSZ; j++) {
00487         divBy10(u64a, &u64b, &u);
00488         aRes[(I64CHARSZ - 1) - j] = (char) ('0' + u);
00489         u64a.high = u64b.high;
00490         u64a.low = u64b.low;
00491         if (isZeroU64(&u64a))
00492             break;
00493     }
00494     if (sign == 1) {
00495         aRes[(I64CHARSZ - 1) - j - 1] = '-';
00496         strcpy(buf, &aRes[(I64CHARSZ - 1) - j - 1]);
00497         return;
00498     }
00499     strcpy(buf, &aRes[(I64CHARSZ - 1) - j]);
00500 }
00501 
00502 int
00503 read64(U64 * i64, const char *str)
00504 {
00505     U64             i64p;
00506     unsigned int    u;
00507     int             sign = 0;
00508     int             ok = 0;
00509 
00510     zeroU64(i64);
00511     if (*str == '-') {
00512         sign = 1;
00513         str++;
00514     }
00515 
00516     while (*str && isdigit((unsigned char)(*str))) {
00517         ok = 1;
00518         u = *str - '0';
00519         multBy10(*i64, &i64p);
00520         memcpy(i64, &i64p, sizeof(i64p));
00521         incrByU16(i64, u);
00522         str++;
00523     }
00524     if (sign) {
00525         i64->high = ~i64->high;
00526         i64->low = ~i64->low;
00527         incrByU16(i64, 1);
00528     }
00529     return ok;
00530 }
00531 
00532 
00533 
00534 
00535 #ifdef TESTING
00536 void
00537 main(int argc, char *argv[])
00538 {
00539     int             i;
00540     int             j;
00541     int             l;
00542     unsigned int    u;
00543     U64             u64a;
00544     U64             u64b;
00545 #define MXSZ 20
00546     char            aRes[MXSZ + 1];
00547 
00548 
00549     if (argc < 2) {
00550         printf("This program takes numbers from the command line\n"
00551                "and prints them out.\n" "Usage: test <unsignedInt>...\n");
00552         exit(1);
00553     }
00554 
00555     aRes[MXSZ] = 0;
00556 
00557     for (i = 1; i < argc; i++) {
00558         l = strlen(argv[i]);
00559         zeroU64(&u64a);
00560         for (j = 0; j < l; j++) {
00561             if (!isdigit(argv[i][j])) {
00562                 printf("Argument is not a number \"%s\"\n", argv[i]);
00563                 exit(1);
00564             }
00565             u = argv[i][j] - '0';
00566             multBy10(u64a, &u64b);
00567             u64a = u64b;
00568             incrByU16(&u64a, u);
00569         }
00570 
00571         printf("number \"%s\" in hex is '%08x%08x'h\n",
00572                argv[i], u64a.high, u64a.low);
00573 
00574         printf("number is \"%s\"\n", printU64(&u64a));
00575         for (j = 0; j < MXSZ; j++) {
00576             divBy10(u64a, &u64b, &u);
00577             aRes[(MXSZ - 1) - j] = (char) ('0' + u);
00578             u64a = u64b;
00579             if (isZeroU64(&u64a))
00580                 break;
00581         }
00582 
00583         printf("number is \"%s\"\n", &aRes[(MXSZ - 1) - j]);
00584     }
00585     exit(0);
00586 }                               /* main */
00587 #endif                          /* TESTING */
00588 
00589 /*
00590  * file: test.c 
00591  */