/* 1315, Wed 10 Sep 97

   NMC_C64.C:  Counter64 format routines.  
                  Could become a 64-bit class one day ...

   Copyright (C) 1997-2002 by Nevil Brownlee,
   CAIDA | University of Auckland */

/*
 * $Log: nmc_c64.c,v $
 * Revision 1.1.1.2.2.7  2002/02/23 01:57:21  nevil
 * Moving srl examples to examples/ directory.  Modified examples/Makefile.in
 *
 * Revision 1.1.1.2.2.3  2000/06/06 03:38:12  nevil
 * Combine NEW_ATR with TCP_ATR, various bug fixes
 *
 * Revision 1.1.1.2  1999/10/03 21:06:17  nevil
 * *** empty log message ***
 *
 * Revision 1.1.1.1.2.1  1999/01/08 01:38:31  nevil
 * Distribution file for 4.3b7
 *
 * Revision 1.1.1.1  1998/11/16 03:57:27  nevil
 * Import of NeTraMet 4.3b3
 *
 * Revision 1.1.1.1  1998/11/16 03:22:00  nevil
 * Import of release 4.3b3
 *
 * Revision 1.1.1.1  1998/10/28 20:31:25  nevil
 * Import of NeTraMet 4.3b1
 *
 * Revision 1.1.3.2  1998/10/18 23:44:10  nevil
 * Added Nicolai's patches, some 'tidying up' of the source
 *
 * Revision 1.1.3.1  1998/10/13 02:48:23  nevil
 * Import of Nicolai's 4.2.2
 *
 * Revision 1.1.1.1  1998/08/24 12:09:28  nguba
 * NetraMet 4.2 Original Distribution
 *
 * Revision 1.3  1998/05/07 04:28:53  rtfm
 * Implement NetFlowMet, the Cisco NetFlow RTFM meter
 */

#if HAVE_CONFIG_H
#include <ntm_conf.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "ausnmp.h"
#include "asn1.h"

#include "nmc.h"
#include "nmc_c64.h"


#if SIZEOF_LONG_LONG == 8 || SIZEOF_LONG == 8


char *putc64(char *bp, counter64 *c)
{
   sprintf(bp, "%lu", *c);
   return bp + strlen(bp);
   }   

char *getc64(counter64 *c, char *bp)
{
   *c = 0;
   while (isdigit(*bp)) {
      *c *= 10;
      *c += *bp-'0';
      ++bp;
      }
   return bp;
   }


#elif SIZEOF_LONG == 4


/* counter64 formatting routines for machines which use 32-bit integers */

union u64 {
   counter64 c;   /*   high      low    */
   unsigned short u[4];  /*  [0] [1]  [2] [3]  */
   };
                         /*  [1] [0]  [3] [2]  on little-endian machines */

void c64timesu16(union u64 *p, union u64 *j, unsigned short k)
{                             /* p = j * k */
   unsigned long x;

#if WORDS_BIGENDIAN
   x = j->u[3] * k;
   p->u[3] = x & 0xFFFF;
   x = j->u[2] * k + (x >> 16);
   p->u[2] = x & 0xFFFF;
   x = j->u[1] * k + (x >> 16);
   p->u[1] = x & 0xFFFF;
   x = j->u[0] * k + (x >> 16);
   p->u[0] = x & 0xFFFF;
#else
   x = j->u[2] * k;
   p->u[2] = x & 0xFFFF;
   x = j->u[3] * k + (x >> 16);
   p->u[3] = x & 0xFFFF;
   x = j->u[0] * k + (x >> 16);
   p->u[0] = x & 0xFFFF;
   x = j->u[1] * k + (x >> 16);
   p->u[1] = x & 0xFFFF;
#endif
   }

unsigned int c64divu16(union u64 *q, union u64 *j, unsigned short k)
{                             /* q = j / k,  result = j % k */
   unsigned long x;

#if WORDS_BIGENDIAN
   q->u[0] = j->u[0] / k;
   x = ((j->u[0] % k) << 16) + j->u[1];
   q->u[1] = x / k;
   x = ((x % k) << 16) + j->u[2];
   q->u[2] = x / k;
   x = ((x % k) << 16) + j->u[3];
   q->u[3] = x / k;
#else
   q->u[1] = j->u[1] / k;
   x = ((j->u[1] % k) << 16) + j->u[0];
   q->u[0] = x / k;
   x = ((x % k) << 16) + j->u[3];
   q->u[3] = x / k;
   x = ((x % k) << 16) + j->u[2];
   q->u[2] = x / k;
#endif
   return  x % k;
   }

char *putc64(char *bp, counter64 *c)
{
   char nb[30];  int x;
   counter64 cc, d;

   nb[x = sizeof(nb)-1] = '\0';
   memcpy(&cc, c, sizeof(counter64));
   do {
      nb[--x] = c64divu16((union u64 *)&d, (union u64 *)&cc, 10) + '0';      
      memcpy(&cc, &d, sizeof(counter64));
      } while (cc.low != 0 || cc.high != 0);
   while (nb[x] != '\0') *bp++ = nb[x++];
   *bp = '\0';
   return bp;
   }   

char *getc64(counter64 *c, char *bp)
{
   counter64 cc, m;

   cc.high = cc.low = 0;
   while (isdigit(*bp)) {
      c64timesu16((union u64 *)&m, (union u64 *)&cc, 10);
      memcpy(&cc, &m, sizeof(counter64));
      add_Bit32_to_counter64(cc, *bp-'0');
      ++bp;
      }
   memcpy(c, &cc, sizeof(counter64));
   return bp;
   }


#else
#error  sizeof(long) not 4 or 8 <<<<<
#endif
