cargvgetoptargc

getopt() in C not working correctly after if statement


I would like to implement a copy of the Linux head commmand. If the user types in ./cprogram head -(option here) I would like for the option to appear but for some reason my code never enters the options switch statement. For example the command line code ./cprogram head -n never enters the case 'n': statement. The code was working before the if statement to check if the argv[1] is "head".

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

int main(int argc, char **argv) {
    int b;
    int c;
    int nflag = 0;
    int Vflag = 0;
    int hflag = 0;
    int eflag = 0;
    int oflag = 0;
    char str[] = "head";
    if (strcmp(argv[1], str) == 0) {
        while ((c = getopt(argc, argv, "nVheo")) != -1) {
            switch (c) {
              case 'n':
                if (nflag||Vflag||hflag||eflag||oflag) {
                    printf("only one option\n");
                    exit(1);
                } else {
                    nflag++;
                    printf("n option\n");
                }
                break;
              case 'V':
                if (nflag||Vflag||hflag||eflag||oflag) {
                    printf("only one option\n");
                    exit(1);
                } else {
                    Vflag++;
                }
                break;
              case 'h':
                if (nflag||Vflag||hflag||eflag||oflag) {
                    printf("only one option\n");
                    exit(1);
                } else {
                    hflag++;
                }
                break;
              case 'e':
                if (nflag||Vflag||hflag||eflag||oflag) {
                    printf("only one option\n");
                    exit(1);
                } else {
                    eflag++;
                }
                break;
              case 'o':
                if (nflag||Vflag||hflag||eflag||oflag) {
                    printf("only one option\n");
                    exit(1);
                } else {
                    oflag++;
                }
                break;
              default:
                printf("invalid options\n");
                abort();
            }
        } 
    } else {
    }
}

I would greatly appreciate an expert eye to have a look and spot what I'm missing. Thanks in advance.


Solution

  • For getopt() to skip argv[1] and parse options from the next element, you should set optind before calling getopt():

    optind = 2;
    

    Also note that you should also check if argc > 1 before comparing argv[1] with "head".

    Here is a modified version:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    int main(int argc, char **argv) {
        int b;
        int c;
        int nflag = 0;
        int Vflag = 0;
        int hflag = 0;
        int eflag = 0;
        int oflag = 0;
        char str[] = "head";
    
        if (argc > 1 && strcmp(argv[1], str) == 0) {
            optind = 2;  // skip argv[1]
            while ((c = getopt(argc, argv, "nVheo")) != -1) {
                if (nflag | Vflag | hflag | eflag | oflag) {
                    fprintf(stderr, "only one option\n");
                    exit(1);
                }
                switch (c) {
                  case 'n':
                    nflag++;
                    printf("n option\n");
                    break;
                  case 'V':
                    Vflag++;
                    break;
                  case 'h':
                    hflag++;
                    break;
                  case 'e':
                    eflag++;
                    break;
                  case 'o':
                    oflag++;
                    break;
                  default:
                    fprintf(stderr, "invalid option `%c'\n", c);
                    abort();
                }
            } 
            /* perform head on files starting at argv[optind] */
        } else {
            /* test some other command */
        }
    }