[comp.sources.misc] v04i038: generalized base converter

mouse%mcgill-vision.UUCP@Larry.McRCIM.McGill.EDU (der Mouse ) (08/27/88)

Posting-number: Volume 4, Issue 38
Submitted-by: "der Mouse " <mouse%mcgill-vision.UUCP@Larry.McRCIM.McGill.EDU>
Archive-name: cvtbase

A generalized base-conversion program.  No compilation options needed;
"cc -o cvtbase cvtbase.c" should work fine.

Known to work on BSD and at least one SV-based system.  Read the
leading comment for more info.

As always, bug reports are welcome.  Bug fixes are even more welcome.
Flames are merely accepted :-).  All of the above should be mailed to
me at one of the addresses below.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

#! /bin/sh
#
# Shar: Shell Archiver
#
# This archive created Sat Aug 27 07:01:24 1988
# Run this through sh to create:
#	cvtbase.c
echo x - cvtbase.c \(4639 characters\)
sed 's/^X//' > cvtbase.c << \EOF
X/*
X * cvtbase -- convert from one base to another.  Usage:
X *
X * cvtbase input-base-spec output-base-spec < input > output
X *
X * where a base spec is one of:
X *
X *	d
X *	D	Specifies "decimal" -- digits 0 through 9
X *
X *	x
X *	h	Specifies "hexadecimal" -- digits 0-9 and a-f
X *
X *	X
X *	H	Specifies "Hexadecimal" -- digits 0-9 and A-F
X *
X *	o
X *	O	Specifies "octal" -- digits 0 through 7
X *
X *	b
X *	B	Specifies "binary" -- digits 0 and 1
X *
X * or a string of two or more characters, which are the digits (eg. 012 would
X *  use ternary notation).  Any of these may be preceded by a - sign to
X *  indicate that the base in question is negative.  A leading + sign is
X *  stripped; to enter a string of digits beginning with a + or - sign, you
X *  must precede the string with a + or - sign (depending on whether you want
X *  a positive or negative base).
X *
X * Any base specifier may be preceded by an m (or an M) and one other
X *  character to change the minus sign (the default is of course -).
X *
X * For a minus sign to be recognized in the input, it must be immediately
X *  followed by the number.  If anything (such as a space) intervenes, the
X *  minus sign will be echoed and ignored (as if it were an ordinary
X *  character).
X *
X * Bases -1, 0, and 1 are disallowed.
X *
X * Input is taken from the standard input; the converted output appears
X *  on the standard output.
X *
X * Copyright 1988 by Mike Parker.  All rights reserved.  Non-profit
X *  redistribution permitted.
X */
X#include <stdio.h>
X
X/* extern */ char **argvec;
X
Xstatic int errs;
X
Xstatic int indig;
Xstatic char *idigits;
Xstatic char isign;
Xstatic int ondig;
Xstatic char *odigits;
Xstatic char osign;
X
Xchar *index();
X
Xlong int get_number(ndig,digits,sign)
Xint ndig;
Xchar *digits;
Xchar sign;
X{
X long int retval;
X int minus;
X char c;
X char *cp;
X
X retval = 0;
X minus = 1;
X while (1)
X  { c = getchar();
X    if (feof(stdin))
X     { if (minus < 0)
X	{ putchar(sign);
X	  minus = 1;
X	}
X       exit(0);
X     }
X    if ((cp=index(digits,c)) != 0)
X     { break;
X     }
X    if ((c == sign) && (ndig > 0))
X     { minus = - minus;
X     }
X    else
X     { if (minus < 0)
X	{ putchar(sign);
X	  minus = 1;
X	}
X       putchar(c);
X     }
X  }
X while (1)
X  { retval *= ndig;
X    retval += (cp-digits);
X    c = getchar();
X    if (feof(stdin))
X     { break;
X     }
X    if ((cp=index(digits,c)) == 0)
X     { break;
X     }
X  }
X ungetc(c,stdin);
X return(minus*retval);
X}
X
Xput_number(ndig,digits,sign,value)
Xint ndig;
Xchar *digits;
Xchar sign;
Xlong int value;
X{
X if ((value < 0) && (ndig > 0))
X  { putchar(sign);
X    value = - value;
X  }
X _put_number(ndig,digits,value);
X}
X
X_put_number(ndig,digits,value)
Xint ndig;
Xchar *digits;
Xlong int value;
X{
X long int i;
X int j;
X
X i = value / ndig;
X j = value % ndig;
X if (j < 0)
X  { j -= ndig;
X    i ++;
X  }
X if (i != 0)
X  { _put_number(ndig,digits,i);
X  }
X putchar(digits[j]);
X}
X
Xget_base(arg,Ndig,Digits,Sign)
Xchar *arg;
Xint *Ndig;
X#define ndig (*Ndig)
Xchar **Digits;
X#define digits (*Digits)
Xchar *Sign;
X#define sign (*Sign)
X{
X int isneg;
X char *origarg = arg;
X
X sign = '-';
X isneg = 0;
X if ((*arg == 'm') || (*arg == 'M'))
X  { sign = *++arg;
X    if (sign == '\0')
X     { fprintf(stderr,"%s: %c must be followed by a sign character\n",
X			argvec[0],arg[-1]);
X       errs = 1;
X       return;
X     }
X    arg ++;
X  }
X if ((*arg == '+') || (*arg == '-'))
X  { isneg = (*arg++ == '-');
X  }
X switch (*arg++)
X  { case 'b': case 'B':
X       digits = "01";
X       break;
X    case 'o': case 'O':
X       digits = "01234567";
X       break;
X    case 'd': case 'D':
X       digits = "0123456789";
X       break;
X    case 'h': case 'x':
X       digits = "0123456789abcdef";
X       break;
X    case 'H': case 'X':
X       digits = "0123456789ABCDEF";
X       break;
X    case '\0':
X       fprintf(stderr,"%s: null base specifier `%s'\n",argvec[0],origarg);
X       errs = 1;
X       return;
X       break;
X    default:
X       if (*arg == '\0')
X	{ fprintf(stderr,"%s: unknown base key `%c' (or base 1)\n",
X			argvec[0],arg[-1]);
X	  errs = 1;
X	  return;
X	}
X       digits = arg-1;
X       arg = "";
X       break;
X  }
X if (*arg)
X  { fprintf(stderr,"%s: junk `%s' at end of base spec `%s'\n",
X				argvec[0],arg,origarg);
X    errs = 1;
X    return;
X  }
X ndig = strlen(digits) * (isneg ? -1 : 1);
X}
X
Xmain(ac,av)
Xint ac;
Xchar **av;
X{
X long int value;
X
Xargvec=av;/*grrr...*/
X if (ac < 3)
X  { fprintf(stderr,"Usage: %s <input-base> <output-base>\n",
X			argvec[0]);
X    exit(1);
X  }
X errs = 0;
X get_base(av[1],&indig,&idigits,&isign);
X get_base(av[2],&ondig,&odigits,&osign);
X if (errs)
X  { exit(1);
X  }
X while (1)
X  { value = get_number(indig,idigits,isign);
X    put_number(ondig,odigits,osign,value);
X  }
X}
EOF
if test 4639 -ne "`wc -c cvtbase.c`"
then
echo shar: error transmitting cvtbase.c \(should have been 4639 characters\)
fi
exit 0
# end of shell archive