kyle.tk wrote:
I am trying to write a function to convert an ipv4 address that is held
in the string char *ip to its long value equivalent. Here is what I
have right now, but I can't seem to get it to work.
[snip]
Any suggestions? Maybe there is a better way to do this?
-kyle
This example is probably a little silly, but it has the advantage of
not relying on the standard library (other than printf()). It will
handle octets in different formats (e.g., 0.255.0377.0xff ) and it will
accept leading and trailing whitespace in each octet (e.g., "127. 0
..0. 1"). Whitespace embedded within the octet token ("1 27.0.0.1")
will cause the function to return 0.
Error handling is non-existent; it will not detect overflow in any of
the octets (e.g. 256.397.400.999 ), nor will it handle missing octets
(255.255.0). That should be relatively straightforward to fix, though.
#include <stdio.h>
typedef enum {start, lead, dec, oct, hex, tail, err} state_t;
typedef enum {shft, eval, none} action_t;
static state_t stateTable[7][20] = {
{lead, dec, dec, dec, dec, dec, dec, dec, dec, dec, err, err, err,
err, err, err, err, err, start, err},
{oct, oct, oct, oct, oct, oct, oct, oct, err, err, err, err, err,
err, err, err, hex, start, tail, err},
{dec, dec, dec, dec, dec, dec, dec, dec, dec, dec, err, err, err,
err, err, err, err, start, tail, err},
{oct, oct, oct, oct, oct, oct, oct, oct, err, err, err, err, err,
err, err, err, err, start, tail, err},
{hex, hex, hex, hex, hex, hex, hex, hex, hex, hex, hex, hex, hex,
hex, hex, hex, err, start, tail, err},
{err, err, err, err, err, err, err, err, err, err, err, err, err,
err, err, err, err, start, tail, err},
{err, err, err, err, err, err, err, err, err, err, err, err, err,
err, err, err, err, err, err, err}
};
static action_t actionTable[7][20] = {
{none, shft, shft, shft, shft, shft, shft, shft, shft, shft, none,
none, none, none, none, none, none, eval, none, none},
{shft, shft, shft, shft, shft, shft, shft, shft, none, none, none,
none, none, none, none, none, none, eval, none, none},
{shft, shft, shft, shft, shft, shft, shft, shft, shft, shft, none,
none, none, none, none, none, none, eval, none, none},
{shft, shft, shft, shft, shft, shft, shft, shft, none, none, none,
none, none, none, none, none, none, eval, none, none},
{shft, shft, shft, shft, shft, shft, shft, shft, shft, shft, shft,
shft, shft, shft, shft, shft, none, eval, none, none},
{none, none, none, none, none, none, none, none, none, none, none,
none, none, none, none, none, none, eval, none, none},
{none, none, none, none, none, none, none, none, none, none, none,
none, none, none, none, none, none, none, none, none}
};
static int mapchar(int c)
{
switch(c)
{
case '0': return 0; break;
case '1': return 1; break;
case '2': return 2; break;
case '3': return 3; break;
case '4': return 4; break;
case '5': return 5; break;
case '6': return 6; break;
case '7': return 7; break;
case '8': return 8; break;
case '9': return 9; break;
case 'a': case 'A': return 10; break;
case 'b': case 'B': return 11; break;
case 'c': case 'C': return 12; break;
case 'd': case 'D': return 13; break;
case 'e': case 'E': return 14; break;
case 'f': case 'F': return 15; break;
case 'x': case 'X': return 16; break;
case '.': case 0: return 17; break;
case ' ': case '\t': case '\n': return 18; break;
default: return 19;
}
}
unsigned long iptolong(const char *ip)
{
unsigned long ipval=0;
unsigned long octet=0;
int base=10;
state_t state = start;
do
{
action_t action = actionTable[state][mapchar(*ip)];
switch(action)
{
case shft:
octet = octet * base + mapchar(*ip);
break;
case eval:
ipval <<= 8;
ipval += octet;
octet = 0;
break;
default:
break;
}
state = stateTable[state][mapchar(*ip)];
switch(state)
{
case dec: base = 10; break;
case oct: base = 8; break;
case hex: base = 16; break;
}
} while(*ip++);
return ipval;
}
int main(int argc, char **argv)
{
unsigned long ipval;
ipval = iptolong(argv[1]);
printf("long value of \"%s\" is %lu (%x)\n", argv[1], ipval,
ipval);
return 0;
}