Help with sscanf()

Discussion in 'C Programming' started by Default User, Feb 28, 2005.

  1. Default User

    Default User Guest

    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
     
    Default User, Feb 28, 2005
    #1
    1. Advertising

  2. Default User

    Eric Sosman Guest

    Default User wrote:
    > 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;
    }

    --
     
    Eric Sosman, Feb 28, 2005
    #2
    1. Advertising

  3. Default User

    Default User Guest

    Eric Sosman wrote:
    > Default User wrote:
    > > 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
     
    Default User, Feb 28, 2005
    #3
  4. Default User

    Eric Sosman Guest

    Default User wrote:
    > Eric Sosman wrote:
    >> [...]
    >> 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.

    --
     
    Eric Sosman, Feb 28, 2005
    #4
  5. Default User

    Default User Guest

    Eric Sosman wrote:
    > Default User wrote:


    > > 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.


    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
     
    Default User, Mar 1, 2005
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Anonymous
    Replies:
    0
    Views:
    498
    Anonymous
    Oct 30, 2003
  2. Andrej Hocevar
    Replies:
    1
    Views:
    486
    Nick Austin
    Aug 18, 2003
  3. Artemio

    Help with sscanf() needed desperately

    Artemio, Jul 29, 2006, in forum: C Programming
    Replies:
    8
    Views:
    351
    Default User
    Jul 30, 2006
  4. BlueJ

    help to explain sscanf()

    BlueJ, Nov 5, 2007, in forum: C Programming
    Replies:
    7
    Views:
    451
    Charlie Gordon
    Nov 8, 2007
  5. JoeT

    sscanf help

    JoeT, Aug 21, 2010, in forum: C Programming
    Replies:
    7
    Views:
    504
    David Thompson
    Sep 4, 2010
Loading...

Share This Page