-1

I'm trying to use getopt in order to run two different functions depending on the arguments given.

int main(int argc, char **argv) {
    int i;
    int identify;
        while ((identify = getopt(argc, argv, "c:")) != -1) {
            switch (identify) {
                case 'c':
                    for (i = 2; i < argc; i++) {
                        readerC(argv[i]);
                    }
                default:
                    for (i = 2; i < argc; i++) {
                        reader(argv[i]);
                    }
            }
        }
    return(0);
}

The purpose is that, if the command included "-c", then it would run the "readerC" function. If there were no arguments passed, then it would read the "reader" function.

I've revised the above function multiple times, but I can't seem to be able to run the "reader" function when running the command with no arguments (there is no output). Previously, putting in -c would run the readerC command as required, but after messing around with it, it now runs the readerC function followed by the reader function.

I tried changing "default:" to "case ':'" and "case '?'" but that hasn't worked either. Any help would be greatly appreciated :)

2 Answers2

2

You forgot to add break statements. Without a break, control simply falls through to the next case. Here is the code with break statements inserted into the relevant places:

while ((identify = getopt(argc, argv, "c:")) != -1) {
    for (i = 2; i < argc; i++) {
        switch (identify) {
            case 'c':
                for (i = 2; i < argc; i++) {
                    readerC(argv[i]);
                }
                break;
            default:
                for (i = 2; i < argc; i++) {
                    reader(argv[i]);
                }
                break; /* not really needed but for completeness */
        }
    }
}

Also, it seems like you are using the same i for all nested loops. Are you sure that's what you want? You might also want to have a look at the optarg variable which points to the argument corresponding to the currently parsed option.

Maybe also read about how getopt works again because it seems like you haven't quite understood it. These loops you wrote are somewhat strange.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • That seems to fix it so -c only prints the first one, but how do I get it to run reader if there are none? The loops are strange due to me trying to fix it multiple times, I've been working on this function for a long while now. – Andrew Raleigh Feb 18 '16 at 17:49
  • The `for` loop shouldn't be where it is. The code needs to parse the options (`-c` or not) first, then process the non-option arguments. There should be a `while` loop for processing the options, and a `for` loop for processing the non-option arguments. – Jonathan Leffler Feb 18 '16 at 18:00
  • @AndrewRaleigh Set a flag if `-c` has been supplied. Call `reader()` if the flag has not been set. – fuz Feb 18 '16 at 18:10
0

The sequence for a main() program handling options is often:

  • Initialization
  • Option parsing
  • Do the real work

You should process the options with getopt(), then process the file arguments. You also need to include break in your switch statement as C does not break automatically between cases.

Hence, you might end up with:

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

static void reader(const char *file);
static void readerC(const char *file);

int main(int argc, char **argv)
{
    void (*function)(const char *arg) = reader;
    int opt;
    while ((opt = getopt(argc, argv, "c")) != -1)
    {
        switch (opt)
        {
        case 'c':
            function = readerC;
            break;
        default:
            fprintf(stderr, "Unrecognized option %c\n", optopt);
            exit(1);
        }
    }

    if (optind == argc)
    {
        fprintf(stderr, "Usage: %s [-c] file ...\n", argv[0]);
        exit(1);
    }

    for (int i = optind; i < argc; i++)
    {
        (*function)(argv[i]);   // The old-fashioned way
        // function(argv[i]);   // The more modern way
    }

    return(0);
}

If you're not comfortable with function pointers yet, then you can use a flag instead:

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

static void reader(const char *file);
static void readerC(const char *file);

int main(int argc, char **argv)
{
    int cflag = 0;
    int opt;
    while ((opt = getopt(argc, argv, "c")) != -1)
    {
        switch (opt)
        {
        case 'c':
            cflag = 1;
            break;
        default:
            fprintf(stderr, "Unrecognized option %c\n", optopt);
            exit(1);
        }
    }

    if (optind == argc)
    {
        fprintf(stderr, "Usage: %s [-c] file ...\n", argv[0]);
        exit(1);
    }

    for (int i = optind; i < argc; i++)
    {
        if (cflag)
            readerC(argv[i]);
        else
            reader(argv[i]);
    }

    return(0);
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thank you very much, the flags are working well. Although when trying ./function -c singlefile.txt, I get "Usage: ./function [-c] fille..." error. I'm going to mess with it for a bit, but yours is the best answer. Thank you again :) – Andrew Raleigh Feb 18 '16 at 18:43
  • You can tell the code hadn't been past a compiler; there was a typo `consst` instead of `const`. I also put a `:` after the `c` in the option specification passed to `getopt()`. That caused the 'usage' error you found, because the `-c` used the file name as its option argument (though it ignored it), leaving you with no extra arguments to process. I've amended the code; I believe it should work now. Apologies for the mistakes. – Jonathan Leffler Feb 18 '16 at 20:19