/*
  basen.c - Convert numbers between bases.

  Jason Hood, 18 & 19 October, 2003 (originally 8 April, 1997).
  Public Domain.
*/

#define PVERS "1.00"
#define PDATE "19 October, 2003"


#include 
#include 
#include 
#include 
#include 

#ifdef __DJGPP__
void   __crt0_load_environment_file( char* dummy ) { }
char** __crt0_glob_function( char* dummy ) { return 0; }
#endif


#define DIGITS (sizeof(unsigned long) * CHAR_BIT)
#define MAXBASE 36		// 0..9, A..Z

char point = '.';               // The separator between integer and fraction
int  places = 9;
int  fraction;			// A vulgar fraction was given
unsigned long whole, numer, denom; // The number to convert


int   strtonum( const char* str, int base );
char* numtostr( char* str, int base );
char* ultostr( unsigned long num, char* str, int base );
void  printnum( int base, int frac );


void help( void )
{
  printf(

"BaseN by Jason Hood .\n"
"Version "PVERS" ("PDATE"). Public Domain.\n"
"http://misc.adoxa.cjb.net/\n"
"\n"
"Convert numbers in any base (2-%d) to any other base(s).\n"
"\n"
"basen [*places] [#base] number... [=base[-base]]...\n"
"\n"
"  *places  Maximum number of digits after the point (default %d)\n"
"  #base    Input base (default 10)\n"
"  number   Number(s) in the input base\n"
"  =base    Output base(s) (default 10)\n"
"\n"
"Numbers can contain points and fractions, but are limited to 32 bits.\n"
"If a minus sign is present, it is ignored.\n"
"Eg: 3.333333 3,333333 3-1/3 3+1/3 \"3 1/3\"\n"

	  , MAXBASE, places );

  exit( 0 );
}


void check_base( int base )
{
  if (base < 2 || base > MAXBASE)
  {
    fprintf( stderr, "Invalid base: %d\n", base );
    exit( 1 );
  }
}


int main( int argc, char* argv[] )
{
  int	inpos,	outpos, lastnum;
  int	inbase, outbase[MAXBASE - 1];
  int	bases;
  char* bp;
  int	j, k;

  if (argc < 2 || strcmp( argv[1], "/?" ) == 0
	       || strcmp( argv[1], "-?" ) == 0
	       || strcmp( argv[1], "--help" ) == 0)
  {
    help();
  }

  if (argv[1][0] == '*')
  {
    places = atoi( argv[1] + 1 );
    if (places < 1 || places >= DIGITS)
    {
      fprintf( stderr, "Places must be between 1 and %d: %s\n",
		       (int)DIGITS - 1, argv[1] );
      return 1;
    }
    inpos = 2;
  }
  else
    inpos = 1;

  while (inpos < argc)
  {
    inbase = 10;
    bases = 0;
    for (lastnum = inpos; lastnum < argc; ++lastnum)
    {
      if (argv[lastnum][0] == '=')
	break;
    }
    outpos = lastnum;
    while (outpos < argc && argv[outpos][0] == '=')
    {
      if (bases == MAXBASE - 1)
      {
	bases = MAXBASE;
	break;
      }
      j = (int)strtol( argv[outpos] + 1, &bp, 10 );
      check_base( j );
      outbase[bases++] = j;
      if (*bp == '-')
      {
	k = atoi( bp + 1 );
	check_base( k );
	if (bases + abs( k - j ) >= MAXBASE)
	{
	  bases = MAXBASE;
	  break;
	}
	if (j < k)
	{
	  while (++j <= k)
	    outbase[bases++] = j;
	}
	else
	{
	  while (--j >= k)
	    outbase[bases++] = j;
	}
      }
      ++outpos;
    }
    if (bases == MAXBASE)
    {
      fputs( "Too many output bases.\n", stderr );
      return 1;
    }
    else if (bases == 0)
      outbase[bases++] = 10;

    for (j = inpos; j < lastnum; ++j)
    {
      if (argv[j][0] == '#')
      {
	inbase = atoi( argv[j++] + 1 );
	check_base( inbase );
	if (j == lastnum)
	  break;
      }
      if (!strtonum( argv[j], inbase ))
      {
	fprintf( stderr, "%s: %s\n",
		 (errno == ERANGE) ? "Number out of range"
				   : "Invalid number", argv[j] );
      }
      else
      {
	for (k = 0; k < bases; ++k)
	{
	  if (inbase == outbase[k] && bases == 1)
	  {
	    if (fraction)
	      printnum( inbase, 1 );
	  }
	  else
	  {
	    printnum( inbase, 0 );
	    fputs( " = ", stdout );
	    printnum( outbase[k], 0 );
	    putchar( '\n' );
	  }
	}
      }
    }
    inpos = outpos;
  }

  return 0;
}


void printnum( int base, int frac )
{
  char	sbuf[DIGITS + 1 + DIGITS-1 + 1];
  char	fbuf[2][DIGITS + 1];
  char* str;

  str = numtostr( sbuf, base );
  if (fraction)
  {
    if (whole)
      printf( "%s ",  ultostr( whole, fbuf[0], base ) );
    printf( "%s/%s ", ultostr( numer, fbuf[0], base ),
		      ultostr( denom, fbuf[1], base ) );
    if (frac)
      printf( "= %s (base %d)\n", str, base );
    else
      printf( "(%s) base %d", str, base );
  }
  else
    printf( "%s base %d", str, base );
}


// Convert the number in str according to base.
// Returns 1 if successful, 0 otherwise (errno == ERANGE if too big).
int strtonum( const char* str, int base )
{
  unsigned long limit;
  char* bp;

  if (*str == '-')
    ++str;

  fraction = 0;
  numer = 0;
  denom = 1;

  limit = ULONG_MAX / base;
  errno = 0;

  whole = strtoul( str, &bp, base );
  if (*bp == '.' || *bp == ',')
  {
    point = *bp;
    str = bp + 1;
    numer = strtoul( str, &bp, base );
    if (*bp == '\0')
    {
      denom = base;
      while (++str < bp)
      {
	if (denom >= limit)
	{
	  errno = ERANGE;
	  break;
	}
	denom *= base;
      }
    }
  }
  else if (*bp == '-' || *bp == '+' || *bp == ' ')
  {
    numer = strtoul( bp + 1, &bp, base );
    if (*bp == '/')
    {
      denom = strtoul( bp + 1, &bp, base );
      fraction = 1;
    }
  }
  else if (*bp == '/')
  {
    fraction = 1;
    numer = whole;
    denom = strtoul( bp + 1, &bp, base );
    whole = 0;
  }

  return (*bp == '\0' && errno != ERANGE);
}


// Convert num to a string, using base. The number is placed at the END of str,
// which should be at least DIGITS+1 bytes.
// Returns the start of the number.
char* ultostr( unsigned long num, char* str, int base )
{
  int digit;

  str += DIGITS;
  *str = '\0';
  do
  {
    digit = (int)(num % base);
    num  /= base;
    if (digit > 9)
      digit += 'A' - 10;
    else
      digit += '0';
    *--str = digit;
  } while (num != 0);

  return str;
}


// Convert the number to a string, using base. The point is placed in the
// middle of str, which should be at least DIGITS*2+1 bytes.
// Returns the start of the number.
char* numtostr( char* str, int base )
{
  unsigned long w, n;
  int	digit, cnt;
  char* start;

  w = whole;
  n = numer;
  if (numer >= denom)
  {
    do
    {
      ++w;
      n -= denom;
    } while (n > denom);
  }
  start = ultostr( w, str, base );

  if (n != 0)
  {
    unsigned long d, limit;
    d = denom;
    limit = ULONG_MAX / base;
    while (n >= limit)			// Not worried about overflow here
    {
      n >>= 1;
      d >>= 1;
    }
    cnt = 0;
    str += DIGITS;
    *str++ = point;
    do
    {
      n *= base;
      digit = (int)(n / d);
      n %= d;
      if (digit > 9)
	digit += 'A' - 10;
      else
	digit += '0';
      *str++ = digit;
    } while (n != 0 && ++cnt < places);
  }

  *str = '\0';
  return start;
}

    Source: geocities.com/jadoxa/misc

               ( geocities.com/jadoxa)