strtok

M

Mark

I have a text file with values written in a format: <value
1-25><space><0xhex_value>. Tthese values represent a structure with two
fields:

typedef structure
{
uint32_t vid;
uint32_t member_port;
} vlanParam_t;

I need to extract the values, I though the following code would be
sufficient for that:

int save_cfg(vlanParam_t *cfg)
{
FILE *fp;
char name[] = "vlanXXXX.cfg";

snprintf(name, sizeof(name), "vlan%d.cfg", cfg->vid);
if ((fp = fopen(name, "w+")) == NULL)
return -1;

fprintf(fp, "%u 0x%04x\n", cfg->vid, cfg->memberPort);
}

int read_cfg(vlanParam_t *cfg)
{
FILE *fp;
char name[] = "vlanXXXX.cfg";
char buf[30];
char *token;

snprintf(name, sizeof(name), "vlan%d.cfg", cfg->vid);
if ((fp = fopen(name, "r")) == NULL)
return -1;

while (fgets(buf, sizeof(buf), fp) != NULL) {
for (token = strtok(buf, " "); token != NULL; token = strtok(NULL, "
")) {
printf("%d ", atoi(token));
}
putchar('\n');
}
}

But read_cfg() only prints first field, followed by one space (so far so
good) and the leading zero of a hex value. What am I doing wrong?
 
M

Mark

Mark said:
while (fgets(buf, sizeof(buf), fp) != NULL) {
for (token = strtok(buf, " "); token != NULL; token =
strtok(NULL, " ")) {
printf("%d ", atoi(token));
}
[skip]

I just found that strtol(token, NULL, 16) does the job. What is the
explanation?
 
B

Ben Pfaff

Mark said:
But read_cfg() only prints first field, followed by one space (so far
so good) and the leading zero of a hex value. What am I doing wrong?

You are assuming that atoi() accepts numbers written in hex
(beginning with "0x"), but it doesn't. It only accepts numbers
written in decimal.
 
M

Mark

Ben said:
You are assuming that atoi() accepts numbers written in hex
(beginning with "0x"), but it doesn't. It only accepts numbers
written in decimal.
Oh, shame on me :(
 
C

Curtis Dyer

Mark said:
I have a text file with values written in a format: <value
1-25><space><0xhex_value>. Tthese values represent a structure
with two fields:

typedef structure
{
uint32_t vid;
uint32_t member_port;
} vlanParam_t;

I need to extract the values, I though the following code would
be sufficient for that:

int save_cfg(vlanParam_t *cfg)
{
FILE *fp;
char name[] = "vlanXXXX.cfg";

snprintf(name, sizeof(name), "vlan%d.cfg", cfg->vid);

You should probably check snprintf()'s return value to see if any
truncation was necessary.
if ((fp = fopen(name, "w+")) == NULL)
return -1;

fprintf(fp, "%u 0x%04x\n", cfg->vid, cfg->memberPort);

It seems to me you should probably use the appropriate format
specifier macros that are defined in <inttypes.h>. (See C99 7.8.)

Notice that your function doesn't always return an `int'.
}

int read_cfg(vlanParam_t *cfg)
{
FILE *fp;
char name[] = "vlanXXXX.cfg";
char buf[30];
char *token;

snprintf(name, sizeof(name), "vlan%d.cfg", cfg->vid);

Again, you'll probably want to check the return value.
if ((fp = fopen(name, "r")) == NULL)
return -1;

while (fgets(buf, sizeof(buf), fp) != NULL) {

[White space reformatted because of wrapping issues:]
for (token = strtok(buf, " ");
token != NULL;
token = strtok(NULL, " ")) {
printf("%d ", atoi(token));

As you note in your follow-up, strtol() is more appropriate. See
below.
}
putchar('\n');
}

Again, you don't always return an `int'.
}

But read_cfg() only prints first field, followed by one space
(so far so good) and the leading zero of a hex value. What am I
doing wrong?

For one, the atoi() function can't check for overflow/underflow. It
also only converts base 10 numeric values, so something like "0xFE"
wouldn't be recognized as a hexadecimal value. Since "x" isn't part
of a valid base 10 number, only "0" is considered.

See C99, 7.20.1.4.
 
D

Denis McMahon

printf("%d ", atoi(token));
But read_cfg() only prints first field, followed by one space (so far so
good) and the leading zero of a hex value. What am I doing wrong?

Looking for decimal numbers with atoi?

#include <stdlib.h>
#include <stdio.h>

int main () {

char str[] = "0xd3a87f61\0x00";

printf ("%d %x %d %x %ld %ld %ld\n",
atoi(" 55 "),
atoi(" 55 "),
atoi(" 0x55 "),
atoi(" 0x55 "),
strtol(" 55 ", NULL, 16),
strtol(" 55 ", NULL, 10),
strtol(&str[2], NULL, 16)
);
return 0;
}

Prints: 55 37 0 0 85 55 3551035233

It looks to me like atoi will only work on a decimal number.

However, if your token starts off with "0x", then:

strtol(&str[2], NULL, 16)

might bear investigation.

Rgds

Denis McMahon
 
M

Mark

Thanks to everyone for valuable comments.
I have one more issue to fix. Consider the following snippet:

char name[] = "vlanXXXX.cfg";
snprintf(name, sizeof(name), "vlan%d.cfg", vid);
if ((fp = fopen(name, "w")) == NULL)
....

As I understand size of 'name' is evaluated at compile time. What if I want
to prepend a prefix to the file name and the prefix should be defined at
compile time, suppose:

#define PREFIX "/long/path/to/storage/"
snprintf(name, sizeof(name), PREFIX"vlan%d.cfg", 1);

This won't work, as the size of name isn't enough to hold the entire string.
One method is to define 'name' large enough. Is there any other way, more
elegant and safe?
 
M

Mark

Mark said:
#define PREFIX "/long/path/to/storage/"
snprintf(name, sizeof(name), PREFIX"vlan%d.cfg", 1);

This won't work, as the size of name isn't enough to hold the entire
string. One method is to define 'name' large enough. Is there any
other way, more elegant and safe?

On the other hand, this looks fine for me:

#define PREFIX "/long/path/to/storage/"
char name[] = PREFIX"vlanXXXX.cfg";
....
except the possibility to loose traling slash in PREFIX.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

strtok() 13
Can't solve problems! please Help 0
URGENT 1
Access violation reading location 0
error 28
strtok problem 16
string parametres becoming empty 14
String copy with pointers not working as expected 6

Members online

Forum statistics

Threads
474,044
Messages
2,570,388
Members
47,052
Latest member
ketan

Latest Threads

Top