Thread: getopt - portable way to treat a single dash as stdin filename

  1. #1
    Registered User
    Join Date
    Dec 2011
    Posts
    22

    getopt - portable way to treat a single dash as stdin filename

    I am writing a program that takes several parameters on the command line and a filename as the last parameter. If the filename is a single dash - `-' I want my program to read from stdin. Otherwise, I want to read from specified file. I want this program to be portable.

    However, this doesn't work with getopt:

    Code:
    while ((c = getopt (argc, argv, "ab-:")) != -1)
             switch (c)
               {
               case 'a':
                 aflag = 1;
                 break;
               case 'b':
                 bflag = 1;
                 break;
               case '-':
                 cvalue = optarg;
             printf("%s\n", cvalue);
    
    $ ./main  -"stuff"
    Unknown option `-s'.
    $ ./main  - "stuff"
    No output in second case. I came up with this:

    Code:
    while ((c = getopt (argc, argv, "ab-:")) != -1)
             switch (c)
               {
               case 'a':
                 aflag = 1;
                 break;
               case 'b':
                 bflag = 1;
                 break;
    }
    [...]
    printf("last is: %s\n", argv[argc - 1]);
    /* after getopt loop is finished, I will use strcmp to check if last argument is `-' and read from stdin, or if it's not and read from file */
    Is this a good idea?

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    The example from the manual (here: Example of Getopt - The GNU C Library) uses - as the last example to show that getopt won't process a single hyphen. Note that this is why you have the variable optind, to go through those arguments.

  3. #3
    Registered User
    Join Date
    Dec 2011
    Posts
    22
    Cool, I will use argv[optind] instead of argv[argc - 1]. Would you make any changes to my code, is this a good approach to this problem in general?

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    I don't really know your setup, but unless you've got something really interesting I would just have a FILE* object that always gets read from, and something like
    Code:
    FILE *data = NULL;
    //in the getopt
        case 'f': data = fopen(optarg, "r"); //assuming you can specify the file with an option; also don't skimp on error checking like I am
    //afterwards in the post-processing
        if (strcmp(argv[optind], "-")==0)
            data = stdin;
    //at the very end
        if (!data)
            data = fopen(default_filename, "r");
    EDIT: Upon rereading the original, I see that the filename is supposed to be the last argument, so never mind case 'f' then. I also meant to ask originally: if we're using GNU extensions (getopt) how portable are you expecting this to be?
    Last edited by tabstop; 12-15-2013 at 04:27 PM.

  5. #5
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    freopen is useful for reassigning the standard streams, if that's useful to you.
    Code:
    if (!freopen(filename, "r", stdin)) {
        ; // failed
    }
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  6. #6
    Registered User
    Join Date
    Dec 2011
    Posts
    22
    Quote Originally Posted by tabstop View Post
    I also meant to ask originally: if we're using GNU extensions (getopt) how portable are you expecting this to be?
    When I say portable, I want it to run on Linux and BSD and on ARM machines. getopt is a part of glibc and EGLIBC or uclibc are used on ARM computers very often. Is there getopt in them? I am afraid it may not be the case. So what's the most portable way to implement getopt functionality? Probably rolling your own function. I don't like reinventing the wheel and I am sure that I would make it worse that people who have faced this problem before. Do you have something to recommend?

    EDIT:

    I found that getopt itself actually *is* a part of C library but its implementation may differ. From http://en.wikipedia.org/wiki/Getopt

    getopt is a C library function used to parse command-line options.
    [...]
    getopt is a system dependent function. The implementation of getopt in GNU C Library does permute the contents of the argument vector as it scans, so that eventually all the non-option arguments are at the end. On the contrary, the implementation of getopt in BSD C Library does not permute the argument vector and returns -1 if it encounters a non-option argument.
    Only getopt_long is GNU extension.
    Last edited by incorrect; 12-15-2013 at 04:56 PM.

  7. #7
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    It's a part of the GNU C library, not the standard C library (won't find it in Microsoft's C library for instance). Having said that, it is part of the POSIX standard, and the source code tree at the uClibc website shows that there is a file called "getopt.c" so you are probably okay there.

  8. #8
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    If you want portability I recommend APR, as it provides the same kind of functionality. Here is an article with an example posted:

    libapr(apache portable runtime) programming tutorial: command line options

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Newbie Question - fflush(stdin) & fpurge(stdin) on Mac and PC
    By tvsinesperanto in forum C Programming
    Replies: 34
    Last Post: 03-11-2006, 12:13 PM
  2. How do you treat you computer?
    By FearOfTheDark in forum A Brief History of Cprogramming.com
    Replies: 47
    Last Post: 01-14-2003, 07:15 AM
  3. Hard Drive: A tricky treat
    By RoD in forum Tech Board
    Replies: 16
    Last Post: 10-28-2002, 02:24 PM
  4. getch() ... w/ Dash of UNIX
    By ginoitalo in forum C Programming
    Replies: 0
    Last Post: 12-23-2001, 10:15 PM

Tags for this Thread