[alt.sources] conv.c -- simple numeric base converter

djm@eng.umd.edu (David J. MacKenzie) (07/03/90)

/* conv - convert numbers between bases

   Usage: conv [-dho] number...

   Print the value of each given NUMBER in the output base selected
   by the options.

   Options:
   -d		Output in decimal.
   -h		Output in hexadecimal.
   -o		Output in octal.

   Non-option arguments are taken to be numbers in one of the three
   bases.  Hex numbers start with 0x; octal numbers start with 0; all
   other arguments are assumed to be decimal numbers.

   David MacKenzie <djm@eng.umd.edu>
   Public domain.
   Latest revision: 07/02/90 */

#include <stdio.h>

long convert ();
void invalid_num ();
void output ();

/* The name this program was run with. */
char *program_name;

void
main (argc, argv)
     int argc;
     char **argv;
{
  extern int optind;
  int optc;
  int output_base;

  program_name = argv[0];
  output_base = 0;

  while ((optc = getopt (argc, argv, "dho")) != EOF)
    {
      switch (optc)
	{
	case 'd':
	  output_base = 10;
	  break;
	case 'h':
	  output_base = 16;
	  break;
	case 'o':
	  output_base = 8;
	  break;
	default:
	  output_base = 0;
	  goto usage;
	}
    }

 usage:
  if (optind == argc || output_base == 0)
    {
      fprintf (stderr, "\
Usage: %s [-dho] [0xhexnum] [0octnum] [decnum] ...\n", argv[0]);
      exit (1);
    }

  for (; optind < argc; ++optind)
    output (convert (argv[optind]), output_base);

  putchar ('\n');

  exit (0);
}

long 
convert (anumber)
     char *anumber;
{
  long number;

  if (anumber[0] == '0' && anumber[1] == 'x')
    {
      /* Convert from hex; sscanf returns number of conversions performed. */
      if (anumber[2] == '\0' || sscanf (anumber + 2, "%lx", &number) == 0)
	invalid_num (anumber);
    }
  else if (anumber[0] == '0')
    {
      /* Convert from octal. */
      if (anumber[1] == '\0')
	number = 0L;
      else if (sscanf (anumber + 1, "%lo", &number) == 0)
	invalid_num (anumber);
    }
  else
    {
      /* Convert from decimal. */
      if (anumber[0] == '\0' || sscanf (anumber, "%ld", &number) == 0)
	invalid_num (anumber);
    }
  return number;
}

void 
output (number, base)
     long number;
     int base;
{
  switch (base)
    {
    case 10:
      printf ("%ld ", number);
      break;
    case 8:
      printf ("0%lo ", number);
      break;
    case 16:
      printf ("0x%lx ", number);
      break;
    }
}

void 
invalid_num (anumber)
     char *anumber;
{
  fprintf (stderr, "%s: %s: invalid number\n", program_name, anumber);
  exit (1);
}
--
David J. MacKenzie <djm@eng.umd.edu> <djm@ai.mit.edu>

jef@well.sf.ca.us (Jef Poskanzer) (07/03/90)

For such a simple interface, a script front-ending for bc would
work too.  For a somewhat more interesting interface, see below.
It's a base-conversion filter -- looks for any numbers in stdin,
converts them from any base to any base in [2..36], and leaves
non-numeric text alone.
---
Jef

  Jef Poskanzer  jef@well.sf.ca.us  {ucbvax, apple, hplabs}!well!jef
       "Publish and be damned." -- Wellesley, Duke of Wellington

/*
** baseconvert.c - base conversion filter
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include <strings.h>
#include <ctype.h>

static char *idigits = "0123456789abcdefghijklmnopqrstuvwxyz";
static char *odigits = "0123456789abcdefghijklmnopqrstuvwxyz";

main( argc, argv )
int argc;
char *argv[];
    {
    int ibase, obase;
    char *usage = "usage: %s <ibase> <obase>\n";
    int ic, i, gettingi, digit;
    char c, lc;
    char *digitp;
    void putint( );

    if ( argc != 3 ||
	 ( ibase = atoi( argv[1] ) ) < 2 || ibase > 36 ||
	 ( obase = atoi( argv[2] ) ) < 2 || obase > 36 )
	{
	fprintf( stderr, usage, argv[0] );
	exit( 1 );
	}
    idigits[ibase] = '\0';

    gettingi = 0;
    for ( ; ; )
	{
	ic = getchar( );
	if ( ic == EOF ) break;
	c = ic;
	if ( isupper( c ) )
	    lc = tolower( c );
	else
	    lc = c;
	digitp = index( idigits, lc );
	if ( digitp == (char *) 0 )
	    {
	    if ( gettingi )
		{
		putint( i, obase );
		gettingi = 0;
		}
	    putchar( c );
	    }
	else
	    {
	    digit = digitp - idigits;
	    if ( gettingi )
		{
		i = i * ibase + digit;
		}
	    else
		{
		gettingi = 1;
		i = digit;
		}
	    }
	}
    
    if ( gettingi )
	putint( i, obase );

    exit( 0 );
    }

void
putint( i, base )
int i, base;
    {
    if ( i >= base )
	putint( i / base, base );
    putchar( odigits[i % base] );
    }

koblas@mips.COM (David Koblas) (07/09/90)

Yet another base converter, but written as a replacement for atof.
Called as:
		val = atov("0x123", 0);
		val = atov("abz", 36);

Where the second argument is the default base, if == 0 then use
default conventions:  0x = 16, 0 = 8, 0% = binary, else base 10.

-----CUT---HERE----------------------------------------------------------

/* +------------------------------------------------------------------+ */
/* | Copyright 1989, David Koblas.                                    | */
/* |   You may copy this file in whole or in part as long as you      | */
/* |   don't try to make money off it, or pretend that you wrote it.  | */
/* +------------------------------------------------------------------+ */

#include	<ctype.h>

#ifdef TEST
main(argc,argv)
int	argc;
char	**argv;
{
	int	i;
	for (i=1;i<argc;i++)
		printf("%10s  == %d\n",argv[i],atov(argv[i],0));
}
#endif

atov(str,type)
char	*str;
int	type;
{
	int		sign = 1;
	int		i;
	char		c;
	int		val=0,n;

	i=0;
	while ((str[i]==' ') || (str[i]=='\t')) i++;
	if (str[i]=='-')  {
		sign = -1;
		i++;
	} else if (str[i]=='+') {
		sign = 1;
		i++;
	}
	if (type==0)  {
		if (str[i]=='0') {
			i++;
			if (str[i]=='%') {
				i++;
				type=2;
			} else if (str[i]=='x') {
				i++;
				type=16;
			} else {
				type=8;
			}
		} else {
			type=10;
		}
	}
	for (;i<strlen(str);i++) {
		c=str[i];
		if (isdigit(c)) {
			n = c - '0';
		} else if (isupper(c)) {
			n = c - 'A' + 10;
		} else if (islower(c)) {
			n = c - 'a' + 10;
		} else {
			goto	out;
		}
		if (n>=type)
			goto out;
		val = (val*type)+n;
	}
out:	
	return(val * sign);
}


-- 
name : David Koblas                        domain: koblas@cs.uoregon.edu
place: Nowhere, I'm just an AI batch job.  domain: koblas@mips.com
quote: "Time has little to do with         domain: koblas@riacs.edu
	infinity and jelly donuts."        domain: koblas@stellar.arc.nasa.gov