Help with sscanf()

D

Default User

I'm need to do some parsing of a line from a config file. The data
structure is:

typedef struct
{
unsigned int version;
unsigned char timestamp[8];
unsigned int num_clients;
unsigned int num_msgs;
unsigned int num_channels;
unsigned int num_minor_frames;
float minor_frame_time;
float ex_capacity;
} M1553_Config_File_T;


An example string from the file would be:

"001 2005022718023400 1 3 2 4 0.05 0.001";

Most of it isn't a problem reading via sscanf(), except for the
timestamp.

2005022718023400 is a time stamp of the form YYYYMMDDHHMMSSTZ. I'm
trying to store it in that array in the struct, such that:

timestamp[0] == 20;
timestamp[1] == 5;
timestamp[2] == 2;
timestamp[3] == 27;
timestamp[4] == 18;
timestamp[5] == 2;
timestamp[6] == 34;
timestamp[7] == 0;

Right now I'm scanning the timestamp values into a temp array of
unsigned int with a bunch of %02u sequences, then copying all those
values to the array in the struct. Works, but a bit messy.

unsigned int timestamp[8];

stat = sscanf(str,
"%u%02u%02u%02u%02u%02u%02u%02u%02u%u%u%u%u%f%f",
&(config->version),
&(timestamp[0]),
&(timestamp[1]),
&(timestamp[2]),
&(timestamp[3]),
&(timestamp[4]),
&(timestamp[5]),
&(timestamp[6]),
&(timestamp[7]),
&(config->num_clients),
&(config->num_msgs),
&(config->num_channels),
&(config->num_minor_frames),
&(config->minor_frame_time),
&(config->ex_capacity)) == NUM_HEADER_FIELDS ? 0 : -1;
#ifdef DEBUG
if (stat == -1)
{
printf("read_header_record: Error interpreting %s\n",
str);
}
#endif
for (i=0; i < 8; i++)
config->timestamp = timestamp;

I'd like to do it directly via sscanf() but haven't come up with a scan
sequence. Some of you guys are hot-shot scanf() wizzes. Any ideas on a
magic (but safe and portable) way to do this?



Brian
 
E

Eric Sosman

Default said:
I'm need to do some parsing of a line from a config file. The data
structure is:

typedef struct
{
unsigned int version;
unsigned char timestamp[8];
unsigned int num_clients;
unsigned int num_msgs;
unsigned int num_channels;
unsigned int num_minor_frames;
float minor_frame_time;
float ex_capacity;
} M1553_Config_File_T;


An example string from the file would be:

"001 2005022718023400 1 3 2 4 0.05 0.001";

Most of it isn't a problem reading via sscanf(), except for the
timestamp.

2005022718023400 is a time stamp of the form YYYYMMDDHHMMSSTZ. I'm
trying to store it in that array in the struct, such that:

timestamp[0] == 20;
timestamp[1] == 5;
timestamp[2] == 2;
timestamp[3] == 27;
timestamp[4] == 18;
timestamp[5] == 2;
timestamp[6] == 34;
timestamp[7] == 0;

Right now I'm scanning the timestamp values into a temp array of
unsigned int with a bunch of %02u sequences, then copying all those
values to the array in the struct. Works, but a bit messy.
[...]

If you have a C99 implementation, you can use the "hh"
length modifier as "%2hhu%2hhu..." and supply pointers to
the individual array elements: &config->timestamp[0],
&config->timestamp[1], ...

To the best of my knowledge, C89 *scanf() cannot do
what you want. However, your trick of scanning into an
intermediate variable and assigning to the array need not
be quite as verbose as the code you posted (see up-thread).
There is no requirement to scan an entire line in one gulp,
so you can do (error-checking omitted):

char *p = str + offset_of_first_timestamp_char;
int i;
for (i = 0; i < 8; p += 2, ++i) {
unsigned int temp;
sscanf(p, "%2u", &temp);
config->timestamp = temp;
}
 
D

Default User

Eric said:
Default said:
I'm need to do some parsing of a line from a config file.
Right now I'm scanning the timestamp values into a temp array of
unsigned int with a bunch of %02u sequences, then copying all those
values to the array in the struct. Works, but a bit messy.
[...]

If you have a C99 implementation, you can use the "hh"
length modifier as "%2hhu%2hhu..." and supply pointers to
the individual array elements: &config->timestamp[0],
&config->timestamp[1], ...

I don't.
To the best of my knowledge, C89 *scanf() cannot do
what you want. However, your trick of scanning into an
intermediate variable and assigning to the array need not
be quite as verbose as the code you posted (see up-thread).
There is no requirement to scan an entire line in one gulp,
so you can do (error-checking omitted):

char *p = str + offset_of_first_timestamp_char;

As I don't know for certain what the offset would be, that sounds
brittle.
int i;
for (i = 0; i < 8; p += 2, ++i) {
unsigned int temp;
sscanf(p, "%2u", &temp);
config->timestamp = temp;
}



I'll probably leave it as is.

Thanks.



Brian
 
E

Eric Sosman

Default said:
Eric said:
[...]
To the best of my knowledge, C89 *scanf() cannot do
what you want. However, your trick of scanning into an
intermediate variable and assigning to the array need not
be quite as verbose as the code you posted (see up-thread).
There is no requirement to scan an entire line in one gulp,
so you can do (error-checking omitted):

char *p = str + offset_of_first_timestamp_char;


As I don't know for certain what the offset would be, that sounds
brittle.

The "%n" specifier is often helpful for this sort
of thing.
 
D

Default User

Eric said:
Default User wrote:

The "%n" specifier is often helpful for this sort of thing.

Indeed it was. Here's what I ended up with, after incorporating your
previous suggestions:

int read_header_record(M1553_Config_File_T *config)
{
int stat = 0;
int i;
int offset;
const char *p;
int fields;

/* scan the version, then skip whitespace up to the next field
record how many characters were scanned */

fields = sscanf(str,"%u %n", &(config->version), &offset);

p = str + offset;

for (i = 0; i < 8; p += 2, ++i)
{
unsigned int temp;
fields += sscanf(p, "%2u", &temp);
config->timestamp = temp;
}

fields += sscanf(p,
"%u%u%u%u%f%f",
&(config->num_clients),
&(config->num_msgs),
&(config->num_channels),
&(config->num_minor_frames),
&(config->minor_frame_time),
&(config->ex_capacity));

if (fields != NUM_HEADER_FIELDS)
{
stat = -1;
}

return stat;
}

Some of the man pages for scanf() had this to say about %n, "Probably
it is wise not to make any assumptions on the effect of %n conversions
on the return value."

This was initially a concern. However, the C89 and C99 draft standards
indicated that this should not be a problem, so I didn't break the
"skip step" into a separate scan.


Thanks, Eric.


Brian
 

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

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top