/* 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