Parsing options in the same way they are passed to main

Discussion in 'C Programming' started by Jeff Rodriguez, Dec 13, 2003.

  1. If main is prototyped as:
    int main(int argc, char *argv[]);

    You will end up with a bunch of arguments in *argv, and the number in argc. Now
    what I want to do is emulate that same action on a string. Say for example I have:

    char *command = "./blah --arg1 --arg2 123 -x --arg2=w00t"

    How do I acheive the same effect as in main()?


    Jeff
    Jeff Rodriguez, Dec 13, 2003
    #1
    1. Advertising

  2. Jeff Rodriguez

    Ben Pfaff Guest

    Jeff Rodriguez <> writes:

    > If main is prototyped as:
    > int main(int argc, char *argv[]);
    >
    > You will end up with a bunch of arguments in *argv, and the number in
    > argc. Now what I want to do is emulate that same action on a
    > string. Say for example I have:
    >
    > char *command = "./blah --arg1 --arg2 123 -x --arg2=w00t"
    >
    > How do I acheive the same effect as in main()?


    It depends on the operating system, shell, and other things. If
    all you want to do is to break apart the string into words at
    white space, I suggest you just write code to do it. It's not
    too hard.
    --
    "Given that computing power increases exponentially with time,
    algorithms with exponential or better O-notations
    are actually linear with a large constant."
    --Mike Lee
    Ben Pfaff, Dec 13, 2003
    #2
    1. Advertising

  3. Ben Pfaff wrote:

    > It depends on the operating system, shell, and other things. If
    > all you want to do is to break apart the string into words at
    > white space, I suggest you just write code to do it. It's not
    > too hard.


    Indeed: (crude code)
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>

    int main(int argc, char *argv[])
    {
    int i;
    char *string = NULL;
    char *str = NULL;
    int size = 0;

    for ( i = 1; i < argc; i++ )
    {
    if ( strlen(argv) > size )
    {
    if ( (string = realloc(string, (size + strlen(argv)) * 2)) == NULL )
    {
    perror("Could not allocate memory");
    exit(1);
    }
    }

    string = strcat(string, argv);
    string = strcat(string, " ");
    }

    printf("%s %s\n", argv[0], string);

    str = strtok(string, " \t\n");
    printf("%s\n", str);
    while ( (str = strtok(NULL, " \t\n")) != NULL )
    {
    printf("%s\n", str);
    }
    return 0;
    }

    However you run into problems like:
    ../a.out --search="Hello World!"

    I would prefer not to have to reinvent the wheel on this since main() already
    implements it! There must be /some/ way that it's a built-in function!

    Jeff
    Jeff Rodriguez, Dec 13, 2003
    #3
  4. Jeff Rodriguez

    Jack Klein Guest

    On Fri, 12 Dec 2003 22:02:24 -0700, Jeff Rodriguez
    <> wrote in comp.lang.c:

    > Ben Pfaff wrote:
    >
    > > It depends on the operating system, shell, and other things. If
    > > all you want to do is to break apart the string into words at
    > > white space, I suggest you just write code to do it. It's not
    > > too hard.

    >
    > Indeed: (crude code)
    > #include <stdio.h>
    > #include <string.h>
    > #include <unistd.h>


    The header above is both non-standard and unneeded in your program.

    > #include <stdlib.h>
    >
    > int main(int argc, char *argv[])
    > {
    > int i;
    > char *string = NULL;
    > char *str = NULL;
    > int size = 0;
    >
    > for ( i = 1; i < argc; i++ )
    > {
    > if ( strlen(argv) > size )
    > {
    > if ( (string = realloc(string, (size + strlen(argv)) * 2)) == NULL )
    > {
    > perror("Could not allocate memory");
    > exit(1);
    > }
    > }
    >
    > string = strcat(string, argv);


    This is quite likely to crash the first time, since the first block
    that realloc returns is uninitialized and there's no telling if it
    will contain a terminating '\0' at all, let alone in the first
    element.

    > string = strcat(string, " ");
    > }
    >
    > printf("%s %s\n", argv[0], string);
    >
    > str = strtok(string, " \t\n");
    > printf("%s\n", str);
    > while ( (str = strtok(NULL, " \t\n")) != NULL )
    > {
    > printf("%s\n", str);
    > }
    > return 0;
    > }
    >
    > However you run into problems like:
    > ./a.out --search="Hello World!"
    >
    > I would prefer not to have to reinvent the wheel on this since main() already
    > implements it! There must be /some/ way that it's a built-in function!
    >
    > Jeff


    No, main() does not already implement it. Either the host operating
    system or the implementation's start-up code does. There is no C
    standard library function to do so.

    If you want source code, try Google.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c /faq
    Jack Klein, Dec 13, 2003
    #4
  5. Jeff Rodriguez

    Ben Pfaff Guest

    Jeff Rodriguez <> writes:

    > I would prefer not to have to reinvent the wheel on this since main()
    > already implements it! There must be /some/ way that it's a built-in
    > function!


    main() doesn't implement this on any system I've used. For
    example, under MS-DOS, the arguments are passed to the program as
    a single string, and the C library startup routine carves it up
    and passes it to main(). As another example, under UNIX-like
    systems, the shell does the parsing into arguments and the
    program receives them from the OS already in that form. In
    neither case is there an easy way for the program to access the
    functionality.
    --
    "I don't have C&V for that handy, but I've got Dan Pop."
    --E. Gibbons
    Ben Pfaff, Dec 13, 2003
    #5
  6. Jeff Rodriguez wrote:

    > if ( (string = realloc(string, (size + strlen(argv)) * 2)) ==
    > NULL )
    > {
    > perror("Could not allocate memory");
    > exit(1);
    > }


    Aside from a few other errors that have already been pointed out, I
    don't think you should be calling perror without first checking the
    value of errno. I don't know off the top if my head whether realloc is
    required to set errno, but my guess is that it is not. If it doesn't,
    you may end up getting something like this:

    Could not allocate memory: No error

    Or something even more confusing, if errno has previously been set by a
    different function.

    This is also a guaranteed memory leak if realloc fails. The correct way
    to use realloc is to store the result into a temporary pointer, and only
    assign it to the destination pointer if it is non-null.

    Finally, 1 is not a portable exit code. Consider using one of the
    portable codes: 0, EXIT_SUCCESS, or EXIT_FAILURE.

    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.
    Kevin Goodsell, Dec 13, 2003
    #6
  7. Kevin Goodsell wrote:
    > Jeff Rodriguez wrote:
    >
    >> if ( (string = realloc(string, (size + strlen(argv)) * 2)) ==
    >> NULL )
    >> {
    >> perror("Could not allocate memory");
    >> exit(1);
    >> }

    >
    >
    > Aside from a few other errors that have already been pointed out, I
    > don't think you should be calling perror without first checking the
    > value of errno. I don't know off the top if my head whether realloc is
    > required to set errno, but my guess is that it is not. If it doesn't,
    > you may end up getting something like this:
    >
    > Could not allocate memory: No error
    >
    > Or something even more confusing, if errno has previously been set by a
    > different function.
    >
    > This is also a guaranteed memory leak if realloc fails. The correct way
    > to use realloc is to store the result into a temporary pointer, and only
    > assign it to the destination pointer if it is non-null.
    >
    > Finally, 1 is not a portable exit code. Consider using one of the
    > portable codes: 0, EXIT_SUCCESS, or EXIT_FAILURE.
    >
    > -Kevin


    Not that I typically do the above (note how I said crude code), but how would
    this be a guaranteed memory leak? If realloc fails the program exits. I'm not
    sure I understand how that would cause a memory leak.

    Jeff
    Jeff Rodriguez, Dec 13, 2003
    #7
  8. Jeff Rodriguez

    CBFalconer Guest

    Jeff Rodriguez wrote:
    > Ben Pfaff wrote:
    >
    > > It depends on the operating system, shell, and other things. If
    > > all you want to do is to break apart the string into words at
    > > white space, I suggest you just write code to do it. It's not
    > > too hard.

    >
    > Indeed: (crude code)
    > #include <stdio.h>
    > #include <string.h>
    > #include <unistd.h>


    *** Non-existent standard include ***

    > #include <stdlib.h>
    >
    > int main(int argc, char *argv[])
    > {
    > int i;
    > char *string = NULL;


    *** Invading the systems name space. Use another id ***

    > char *str = NULL;
    > int size = 0;
    >
    > for ( i = 1; i < argc; i++ )
    > {
    > if ( strlen(argv) > size )
    > {
    > if ( (string = realloc(string, (size + strlen(argv)) * 2)) == NULL )


    *** Harmless in this context, but an evil habit ***
    Try something like:
    if (tmp = realloc(old, (size + strlen(argv)) *
    2))
    old = tmp;
    else {
    /* failure */
    }

    > {
    > perror("Could not allocate memory");
    > exit(1);
    > }
    > }



    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
    CBFalconer, Dec 13, 2003
    #8
  9. Jeff Rodriguez

    nrk Guest

    Jeff Rodriguez wrote:

    > If main is prototyped as:
    > int main(int argc, char *argv[]);
    >
    > You will end up with a bunch of arguments in *argv, and the number in
    > argc. Now what I want to do is emulate that same action on a string. Say
    > for example I have:
    >
    > char *command = "./blah --arg1 --arg2 123 -x --arg2=w00t"
    >
    > How do I acheive the same effect as in main()?
    >
    >
    > Jeff


    A simple hack is to use another C program that simply prints out its command
    line arguments to a known file. Then invoke said program with the system
    call:

    /* assume that our argv printer is called cmdline
    and is accessible through a "system" call */
    char *command = "./cmdline ./blah --arg1 --arg2 123 -x --arg2=w00t";

    system(command);

    /* now read the file produced by cmdline to get
    argv parsed version of command */

    -nrk.
    nrk, Dec 13, 2003
    #9
  10. Jeff Rodriguez

    nrk Guest

    nrk wrote:

    > Jeff Rodriguez wrote:
    >
    >> If main is prototyped as:
    >> int main(int argc, char *argv[]);
    >>
    >> You will end up with a bunch of arguments in *argv, and the number in
    >> argc. Now what I want to do is emulate that same action on a string. Say
    >> for example I have:
    >>
    >> char *command = "./blah --arg1 --arg2 123 -x --arg2=w00t"
    >>
    >> How do I acheive the same effect as in main()?
    >>
    >>
    >> Jeff

    >
    > A simple hack is to use another C program that simply prints out its
    > command line arguments to a known file. Then invoke said program with the
    > system call:
    >
    > /* assume that our argv printer is called cmdline
    > and is accessible through a "system" call */
    > char *command = "./cmdline ./blah --arg1 --arg2 123 -x
    > --arg2=w00t";
    >
    > system(command);
    >
    > /* now read the file produced by cmdline to get
    > argv parsed version of command */
    >
    > -nrk.


    Just in case you're wondering what an "argv printer" might look like :)

    #include <stdio.h>

    int main(int argc, char **argv) {
    while ( *argv ) {
    printf("%s\n", *argv);
    ++argv;
    }

    return 0;
    }

    If you want one that ignores argv[0]:

    #include <stdio.h>

    int main(int argc, char **argv) {
    if ( argc )
    while ( *++argv ) printf("%s\n", argv);

    return 0;
    }

    -nrk.
    nrk, Dec 13, 2003
    #10
  11. Jeff Rodriguez wrote:
    > Kevin Goodsell wrote:
    >
    >> Jeff Rodriguez wrote:
    >>
    >>> if ( (string = realloc(string, (size + strlen(argv)) * 2))
    >>> == NULL )
    >>> {

    >
    > Not that I typically do the above (note how I said crude code), but how
    > would this be a guaranteed memory leak? If realloc fails the program
    > exits. I'm not sure I understand how that would cause a memory leak.
    >


    Any time you fail to free memory that you've [m|c|re]alloc'ed, it is a
    memory leak. Using realloc in this manner guarantees that you will not
    be able to free the memory you've already allocated once realloc fails.

    Some people don't bother freeing memory when the program is exiting.
    This is not a very good idea. Some systems reclaim memory when a program
    exits, but not all.

    Also, what happens when the code is used in a different program, where
    exiting on an allocation failure isn't an option?

    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.
    Kevin Goodsell, Dec 13, 2003
    #11
  12. CBFalconer wrote:

    >> char *string = NULL;

    >
    >
    > *** Invading the systems name space. Use another id ***
    >
    >


    I could be wrong, but I think 'str' identifiers are reserved for use as
    external identifiers. Since this is local it might shadow an external
    declaration, but I don't think it will conflict.

    Of course, avoiding reserved identifiers completely (even where they are
    safe) is probably the best thing to do.

    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.
    Kevin Goodsell, Dec 13, 2003
    #12
  13. Kevin Goodsell <> wrote:
    >Some people don't bother freeing memory when the program is
    >exiting. This is not a very good idea. Some systems reclaim
    >memory when a program exits, but not all.


    Can you cite an example of a system where it makes any difference
    at all?

    --
    Floyd L. Davidson <http://web.newsguy.com/floyd_davidson>
    Ukpeagvik (Barrow, Alaska)
    Floyd Davidson, Dec 13, 2003
    #13
  14. Floyd Davidson wrote:
    > Kevin Goodsell <> wrote:
    >
    >>Some people don't bother freeing memory when the program is
    >>exiting. This is not a very good idea. Some systems reclaim
    >>memory when a program exits, but not all.

    >
    >
    > Can you cite an example of a system where it makes any difference
    > at all?
    >


    Sure. A TI-89 or TI-92+ calculator using TI-GCC. If you fail to free
    memory, you don't get it back until you reset the whole thing, wiping
    the entire memory.

    There are a lot of systems out there other than desktop systems.

    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.
    Kevin Goodsell, Dec 14, 2003
    #14
  15. Groovy hepcat Jeff Rodriguez was jivin' on Fri, 12 Dec 2003 20:36:37
    -0700 in comp.lang.c.
    Parsing options in the same way they are passed to main's a cool
    scene! Dig it!

    >If main is prototyped as:
    >int main(int argc, char *argv[]);
    >
    >You will end up with a bunch of arguments in *argv, and the number in argc. Now
    >what I want to do is emulate that same action on a string. Say for example I have:
    >
    >char *command = "./blah --arg1 --arg2 123 -x --arg2=w00t"
    >
    >How do I acheive the same effect as in main()?


    First of all, don't try to do this with a string literal; use an
    array.
    Use strtok() to get each token in turn, and add each (pointer
    returned from strtok()) to an array of pointers to char which has been
    dynamically allocated with realloc(), until (and including) strtok()
    returns a null pointer. For example:

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

    char **gettoks(char *s, int *num)
    {
    char **tok = NULL, **tmp;
    char *t;
    int n = 0;

    t = strtok(s, " \t\v\r\n");

    while(t)
    {
    n++;

    tmp = realloc(tok, n * sizeof *tmp);
    if(!tmp)
    {
    free(tok);
    return NULL;
    }
    tok = tmp;

    tok[n - 1] = t;

    t = strtok(NULL, " \t\v\r\n");
    }

    tmp = realloc(tok, (n + 1) * sizeof *tmp);
    if(!tmp)
    {
    free(tok);
    return NULL;
    }
    tok = tmp;

    tok[n] = NULL;

    *num = n;
    return tok;
    }

    int main(void)
    {
    char command[] = "./blah --arg1 --arg2 123 -x --arg2=w00t";
    char **argv;
    int argc, i;

    argv = gettoks(command, &argc);
    if(!argv)
    {
    fprintf(stderr, "Memory allocation error.\n");
    return EXIT_FAILURE;
    }

    printf("%d args found:\n", argc);

    for(i = 0; i < argc; i++)
    {
    printf("\t%d: \"%s\"\n", i, argv);
    }

    free(argv);
    return 0;
    }

    --

    Dig the even newer still, yet more improved, sig!

    http://alphalink.com.au/~phaywood/
    "Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker.
    I know it's not "technically correct" English; but since when was rock & roll "technically correct"?
    Peter Shaggy Haywood, Dec 17, 2003
    #15
  16. Jeff Rodriguez

    goose Guest

    CBFalconer <> wrote in message news:<>...

    <snipped>

    > > int main(int argc, char *argv[])
    > > {
    > > int i;
    > > char *string = NULL;

    >
    > *** Invading the systems name space. Use another id ***


    I dont think so; as it is local to main, its not a problem.
    otoh, it really *is* rather bad form.

    goose,
    goose, Dec 18, 2003
    #16
  17. Jeff Rodriguez

    goose Guest

    Jeff Rodriguez <> wrote in message news:<>...

    <snipped>

    > Not that I typically do the above (note how I said crude code), but how would
    > this be a guaranteed memory leak? If realloc fails the program exits. I'm not
    > sure I understand how that would cause a memory leak.
    >


    there are a few ways:
    1. the system it runs on may not guarantee that it cleans up after
    processes.
    2. the process that is currently running where realloc fails
    could have been a forked-type process, and the other party
    of the fork may have to end before the memory is released.
    since there is no guarantee that the other process *will*
    end, the memory is gone forever.
    3. the error code of 1 ("exit (1)") may be interpreted by the
    caller (OS) as "please restart from main without resetting
    anything": the only portable codes to use are EXIT_FAILURE
    and EXIT_SUCCESS.
    :)

    hth
    goose,
    goose, Dec 18, 2003
    #17
  18. On Sat, 13 Dec 2003 21:13:25 GMT, Kevin Goodsell
    <> wrote:

    > CBFalconer wrote:
    >
    > >> char *string = NULL;

    > >
    > >
    > > *** Invading the systems name space. Use another id ***
    > >
    > >

    >
    > I could be wrong, but I think 'str' identifiers are reserved for use as
    > external identifiers. Since this is local it might shadow an external
    > declaration, but I don't think it will conflict.
    >

    Standard library function names, plus the extension ranges beginning
    with mem str wcs is to, are reserved as external names always, and as
    file-scope identifiers *and macros* (unless #undef'ed) if the relevant
    header is #include'd, and in this case string.h was.

    That said, I would bet 'string' in particular will never be used, at
    least not for a function, partly because it describes a thing not an
    operation, and partly to avoid conflict with C++'s std::string.

    > Of course, avoiding reserved identifiers completely (even where they are
    > safe) is probably the best thing to do.
    >

    Concur.

    - David.Thompson1 at worldnet.att.net
    Dave Thompson, Dec 19, 2003
    #18
  19. (goose) writes:
    [...]
    > 3. the error code of 1 ("exit (1)") may be interpreted by the
    > caller (OS) as "please restart from main without resetting
    > anything": the only portable codes to use are EXIT_FAILURE
    > and EXIT_SUCCESS.


    And 0.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://www.sdsc.edu/~kst>
    Schroedinger does Shakespeare: "To be *and* not to be"
    (Note new e-mail address)
    Keith Thompson, Dec 20, 2003
    #19
    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. dee
    Replies:
    9
    Views:
    492
    Joseph Byrns
    Apr 15, 2005
  2. Asfand Yar Qazi
    Replies:
    4
    Views:
    382
    Asfand Yar Qazi
    Nov 12, 2004
  3. Anand
    Replies:
    2
    Views:
    886
    Anand
    Sep 11, 2003
  4. Replies:
    0
    Views:
    397
  5. soren625
    Replies:
    10
    Views:
    226
    Kevin Collins
    Dec 28, 2005
Loading...

Share This Page