Design... the right way.

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • mike.rosset+gnus@gmail.com

    Design... the right way.


    Hello All:


    I am new to C and I have a program design question. Not only am I trying
    to learn C but I'm also trying to pick up good habits. And I'm cocerned
    with doing things the right and avoiding picking up bad habits.

    The program I'm working on uses popen to read some pre-formatted output
    from another program. The output looks like this.

    line 0: persons_name
    line 1: persons_last_na me
    line 2: .....

    I then need to take each line assign it to a structure member. What
    would be the simplest approach to find the member field from the line
    loop count?

    Michael Rosset
  • Richard Heathfield

    #2
    Re: Design... the right way.

    mike.rosset+gnu s@gmail.com said:
    >
    Hello All:
    >
    >
    I am new to C and I have a program design question. Not only am I trying
    to learn C but I'm also trying to pick up good habits. And I'm cocerned
    with doing things the right and avoiding picking up bad habits.
    >
    The program I'm working on uses popen to read some pre-formatted output
    from another program. The output looks like this.
    >
    line 0: persons_name
    line 1: persons_last_na me
    line 2: .....
    >
    I then need to take each line assign it to a structure member. What
    would be the simplest approach to find the member field from the line
    loop count?
    Given these rules:
    1) you have at least one whole line in memory on each iteration of the loop
    2) there is a colon in every line
    3) the colon precedes the member field
    4) there is nothing but whitespace between the colon and the member field
    5) the member field contains no whitespace

    you can get the member field like this:

    char *fieldend = NULL;
    char *colon = strchr(line, ':');
    char *fieldstart = colon + 1;
    while(isspace(( unsigned char)*fieldstar t))
    {
    ++fieldstart;
    }
    fieldend = fieldstart + 1;
    while(*fieldend != '\0' && !isspace((unsig ned char)*fieldend) )
    {
    ++fieldend;
    }

    fieldend now points one byte beyond the member field. You can print the
    exact contents of the member field like this:

    printf("Field contents = [%.*s]\n", fieldend - fieldstart, fieldstart);

    or, given at least 1 + fieldend - fieldstart bytes, you can make a string
    out of it like this:

    memcpy(target, fieldstart, fieldend - fieldstart);
    target[fieldend - fieldstart] = '\0';

    If that solves your problem, great. If it only moves you a bit closer to
    it, what more do you need?

    --
    Richard Heathfield <http://www.cpax.org.uk >
    Email: -http://www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999

    Comment

    • Nick Keighley

      #3
      Re: Design... the right way.

      On 26 Jun, 04:03, mike.rosset+g.. .@gmail.com wrote:
      I am new to C and I have a program design question. Not only am I trying
      to learn C but I'm also trying to pick up good habits.
      good
      :-)
      And I'm cocerned
      with doing things the right [way] and avoiding picking up bad habits.
      >
      The program I'm working on uses popen
      popen() isn't actually standard C. It's standard Unix (Posix).
      But your question becomes a standard C question if we assume you're
      reading
      from a stream (eg. opened by fopen())
      to read some pre-formatted output
      from another program. The output looks like this.
      that is the *input* to your program looks like:
      line 0: persons_name
      line 1: persons_last_na me
      line 2: .....
      >
      I then need to take each line assign it to a structure member. What
      would be the simplest approach to find the member field from the line
      loop count?
      I'm not sure. What are the structure members called?
      When I read your question I thought persons_name
      indicated a name and the actual input looked like

      line 0: frodo
      line 1: baggins

      etc.

      So you might be doing something like

      void process_lines (struct Record *record)
      {
      char line [LARGEST_LINE];
      char field [LARGEST_FIELD];
      int line_count = 0;

      while (read_line(line ) == OK)
      {
      line_count++;
      get_field (field, line);

      switch (line_count)
      {
      1:
      strcpy (record->person_name, field);
      break;

      2:
      strcpy (record->persons_last_n ame, field);
      break;

      default:
      fprintf (stderr, "Dire Straits!\n");
      exit (EXIT_FAILURE);
      }
      }
      }

      which isn't exactly elegant...
      The error handling is weak, the program is very trusting of the input
      source.

      I'd do get_field() more like this (a different approach to
      RH's solution).

      int get_field (char *field, const char *line)
      {
      int line_count
      if (sscanf (line, "line %d: %s", &line_count, field) != 2)
      return PARSE_ERROR;

      return OK;
      }

      Could you explain your problem in more detail?


      --
      Nick Keighley

      /*
      - Note:
      - I wanted to put a check in getGuiExtract() , but it's a void
      method, inherited from the father of the father of the father of
      the
      [...]
      the father of the father of the father of the father of the
      father ...

      So I can't modify its interface.
      */
      [cry for help found in source code]

      Comment

      • mike.rosset+gnus@gmail.com

        #4
        Re: Design... the right way.

        pete <pfiland@mindsp ring.comwrites:
        >
        #include <stdlib.h>
        #include <stdio.h>
        #include <string.h>
        >
        #define MAX_FIELDS 19
        #define PATH_MAX 10
        >
        enum pkg_vars {
        pkgname,
        pkgver
        };
        >
        int main(void)
        /*
        ** non prototype declarations
        ** is an obsolescent feature of the language
        */
        {
        int lines = 0;
        char package[MAX_FIELDS][PATH_MAX];
        /*
        ** A two dimensional array of char
        */
        FILE *input = fopen("./test.sh", "r");
        char line[PATH_MAX + 1];
        >
        if(input == NULL) {
        perror("Error: running parser");
        /*
        ** Nothing to fclose here
        */
        exit(EXIT_FAILU RE);
        }
        while(fgets(lin e, PATH_MAX, input)) {
        line[strlen(line) - 1 ] = '\0';
        if(lines < MAX_FIELDS) {
        strcpy(package[lines], line);
        }
        lines++;
        }
        printf("name = %s\n", package[pkgname]);
        printf("pkgver = %s\n", package[pkgver]);
        printf("total = %d\n", lines);
        /*
        ** A portable text stream, ends in a newline character.
        */
        fclose(input);
        return 0;
        }

        Pete, thanks for your response. Thank you for for your suggestions, all
        of them make sense. I have a couple of questionsi. When you say "non
        prototype declarations" you mean I should declare void as a parmater, it
        not to be assumed.

        Also I'm not sure what you mean by a portable stream should end in a
        newline. Does that mean I should'nt remove it from line or I should copy
        the line then remove it?

        Mike Rosset

        Comment

        • Mike Wahler

          #5
          Re: Design... the right way.


          <mike.rosset+gn us@gmail.comwro te in message
          news:87ej6ki1l7 .fsf@gmail.com. ..
          pete <pfiland@mindsp ring.comwrites:
          >
          >>
          >#include <stdlib.h>
          >#include <stdio.h>
          >#include <string.h>
          >>
          >#define MAX_FIELDS 19
          >#define PATH_MAX 10
          >>
          >enum pkg_vars {
          >pkgname,
          >pkgver
          >};
          >>
          >int main(void)
          >/*
          >** non prototype declarations
          >** is an obsolescent feature of the language
          >*/
          >{
          >int lines = 0;
          >char package[MAX_FIELDS][PATH_MAX];
          >/*
          >** A two dimensional array of char
          >*/
          >FILE *input = fopen("./test.sh", "r");
          >char line[PATH_MAX + 1];
          >>
          >if(input == NULL) {
          >perror("Erro r: running parser");
          >/*
          >** Nothing to fclose here
          >*/
          >exit(EXIT_FAIL URE);
          >}
          >while(fgets(li ne, PATH_MAX, input)) {
          >line[strlen(line) - 1 ] = '\0';
          >if(lines < MAX_FIELDS) {
          >strcpy(packa ge[lines], line);
          >}
          >lines++;
          >}
          >printf("name = %s\n", package[pkgname]);
          >printf("pkgv er = %s\n", package[pkgver]);
          >printf("tota l = %d\n", lines);
          >/*
          >** A portable text stream, ends in a newline character.
          >*/
          >fclose(input );
          >return 0;
          >}
          >
          >
          Pete, thanks for your response. Thank you for for your suggestions, all
          of them make sense. I have a couple of questionsi. When you say "non
          prototype declarations" you mean I should declare void as a parmater, it
          not to be assumed.
          int f(); /* declaration; does not specify parameters */
          /* in C, an empty parameter list means 'not specified' */

          int f(int a, char b); /* declaration; also a prototype (specifies
          /* arguments)

          int f(void); /* declaration/prototype: specific about arguments */
          /* (in this case there are none */
          >
          Also I'm not sure what you mean by a portable stream should end in a
          newline. Does that mean I should'nt remove it from line or I should copy
          the line then remove it?
          You can remove and put it back all you like, but what he's
          saying is that the very last character in the stream should
          be a newline ('\n').

          -Mike


          Comment

          • David Thompson

            #6
            Re: Design... the right way.

            On Thu, 26 Jun 2008 15:27:48 GMT, "Bartc" <bc@freeuk.comw rote:
            >
            <mike.rosset+gn us@gmail.comwro te in message
            news:873an0i8ul .fsf@gmail.com. ..
            The data format looks more like this

            Frodo
            Baggins
            Hobbit
            >
            I vaguely remember Bilbo Baggins, so are these first names or last names?
            >
            <OT highly summarizedFrodo is indeed (fictionally) the first name of
            Bilbo's honorary nephew and heir, who thus becomes the 'ring-bearer'
            to take the One Ring to Mount Doom to be destroyed, through (nearly
            all of) the _Lord of the Rings_ trilogy. I can imagine how you might
            have ignored the books -- not forgive, just imagine <G-- but totally
            missing three _huge_ Hollywood movies is quite an accomplishment. </>
            /* popen? *waves hand* yes its fopen, continue on your way.*/
            FILE *input = popen("./test.sh", "r");
            >
            I'm not familar with popen, from the docs it doesn't seem appropriate. Try
            fopen().
            >
            OP previously said he wants this program to parse _the output of
            running a script namely test.sh_ so it's very appropriate. But OT.
            (But the issues of parsing and storing are mostly the same whether the
            input comes from a running script or a plain file, and hence ontopic.
            The only obvious exception would be if you wanted to rewind or
            otherwise reposition in the input, which fails for a pipe; but then in
            Standard C it may fail even for a 'real' file -- if any such.)

            - formerly david.thompson1 || achar(64) || worldnet.att.ne t

            Comment

            Working...