/*
long cvtnum ( char *string);
long long cvtnum_ll ( char *string);
Convenience routine to convert a string to a number.
string can be a decimal,octal, or hexdecimal number.
hexadecimal may be noted as "0xhexdigits", or are recognized automatically
by occurances of digits A-F.
Numbers starting with leading zeroes without a following x are
interpreted octal.
Hex and Octal also can be denoted as %X,%O (VMS DCL compatibility).
(but a preceding negative sign is ignored for %x and %o).
In addition to binary notation is possible with %B: %b1111 = 0xF .
Syntax errors (characters other than digits) return value 0 and errno = -1;
No error will be detected if "x" or "O" follows some legal number: the preceeding
number will be hex/octal-converted.
The result returned is of type "long" for entry cvtnum.
The result returned is of type "long long" for entry cvtnum_ll .
Author: Joseph Huber , Munich,Germany
*/
#include
#include
#include
#include
#include
#include
#ifdef __vms
void set_errno( int );
#endif
/* just for VMS, in general how to ask if type "long long" available ? */
#ifdef __vax
#define NOLONGLONG
#endif
#ifdef NOLONGLONG
long cvtnum_ll ( char * string ) {
long result=0;
#else
long long cvtnum_ll ( char * string ) {
long long result=0;
#endif
int c=0,prev=0;
int i,radix = 0, start = 0;
char *begin,*end;
char length;
#ifdef __vms
set_errno(0);
#else
errno = 0;
#endif
length = strlen(string);
for ( i=0; i < length; i++) {
prev = c;
c = string[i];
if ( isspace(c) ) {
start = (i+1); /* whitespace */
continue;
}
if (c == '%') {
start = (i+1);
continue;
}
switch (c) {
case 'd': /*don't upcase these suffixes*/
case 'e': /*don't upcase these suffixes*/
case 'h': /*don't upcase these suffixes*/
case 'k': /*don't upcase these suffixes*/
break;
default:
c=toupper( c );
}
if ( (c == '-') || (c == '+') ) continue ; /* sign */
if ( isdigit(c) ) continue;
if ( (i > 0) && (prev == '%') && (c == 'B') )
{
radix = 2; /* %Bbinary */
start = (i+1);
continue;
}
if ( (i > 0) && (prev == '%') && (c == 'X') )
{
radix = 16; /* %Xhex */
start = (i+1);
continue;
}
if ( (i > 0) && (prev == '%') && (c == 'O') )
{
radix = 8; /* %Ooct */
start = (i+1);
continue;
}
if ( isxdigit(c) ) {
radix = 16;
continue;
}
if ( (i > 0) && ((c == 'X')||(c == 'Z')) )
{
radix = 16; /* numX or numz:hex */
continue;
}
if ( (i > 0) && (c == 'O') )
{
radix = 8; /* numO; octal */
continue;
}
/* #if 0: instead of an error case, simply pass whatever is following to strtol(l):
some RTLs may accept suffixes.
*/
#if 0
#ifdef DEBUG
printf("cvtnum: Illegal character in input: %c\n",c);
#endif
#ifdef __vms
set_errno(22);
#else
errno = 22;
#endif
return 0;
#endif
}
#ifdef __vms
set_errno(0);
#else
errno = 0;
#endif
begin = string;
if ( start ) begin += start;
#ifdef DEBUG
printf("cvtnum: radix: %d, start pos%d string at begin: %s\n",radix,start,begin);
#endif
#ifdef NOLONGLONG
#ifdef DEBUG
printf("cvtnum: result=%ld\n",result);
#endif
result = (long)strtol( begin, &end, radix ) ;
#else
result = (long long)strtoll( begin, &end, radix ) ;
#ifdef DEBUG
printf("cvtnum: result=%lld\n",result);
#endif
#endif
if (errno) return 0;
/* some RTL implementation allow magnitude suffixes like K,M,G,T
a simple version is implemented here
*/
#if 1
if (end) {
c=*end;
switch ( c ) {
#if 0
case 'Y': /*yotta 1e24 but does not fit in signed 64 bit*/
result *= 1000;
case 'Z': /*zeta 1e21 (But see 'z' case for hexadecimal earlier, and is too big to fit in signed 64 bit)*/
result *= 1000;
#endif
#if 0
case 'E': /*exa 1e18 (but is seen as a hex digit above )*/
result *= 1000;
#endif
case 'P': /*peta 1e15*/
result *= 1000;
case 'T': /*tera 1e12*/
result *= 1000;
case 'G': /*giga 1e9*/
result *= 1000;
case 'M': /*mega 1e6*/
result *= 1000;
case 'k': /*kilo 1e3*/
result *= 1000;
break;
case 'K': /*Computer K */
result *= 1024;
break;
case 'h': /*hecto *100 */
result *= 100;
break;
#if 0
case 'd': /*deca *10 (but might be interpretated earlier for hexadecimal!)*/
result *= 10;
break;
#endif
default: /*ignore anything else*/
}
}
#endif
return result;
}
long cvtnum ( char * string ) {
return (long) cvtnum_ll ( string );
}
#ifdef TESTLL
main () {
long long x;
char * end;
char line[80];
while (gets(line)) {
x = cvtnum_ll (line);
printf("String: %s : result = 0x%llx , %lld - errno %d\n",line,x,x,errno);
}
}
#endif
#ifdef TEST
main () {
long x;
char * end;
char line[80];
while (gets(line)) {
x = cvtnum (line);
printf("String: %s : result = 0x%x , %d - errno %d\n",line,x,x,errno);
}
}
/*
possible error check:
errno=0;
result=strtoul();
if (result == ULONG_MAX && errno == ERANGE) {
*/
#endif