How to efficiently parse command-line arguments in C

333 Views Asked by At

I have a program that needs to parse command line arguments and pass them to various functions to perform different tasks.

Some of the possible options and possible arguments are:

  • -a <source> <destination>
  • -b <filename>
  • -p --num <number>
  • -r --identical <source> <destination>
  • -g --alphabetical <destination>

As you can see the various options are quite diverse and are not limited to something simple such as -f <x> but instead it has various parameters and arguments also (for example -r).

I have looked into getopt_long/getopt but these do not completely satisfy the full range of my programs options. For example i cannot do -r --identical <source> <destination>.

So i have resorted to parsing myself:


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

int main(int argc, char *argv[])
{

     if (argc == 1)
     {
         fprintf(stderr,"no args");
         return -1;
     }

     if (argc == 4)
     {
        if (strncmp("-a", argv[1], 3) == 0)
        {
            a_function(argv[2], argv[3]);
        }
     }
     else if (argc == 3)
     {
          if (strncmp("-b", argv[1], 3) == 0)
          {
              another_func(argv[2]);
          }
     }


    return 0;
}

The program above relies on the number of arguments provided, my question is: is there a more effective/cleaner way to parse arguments (specifically the ones i defined above) since if i carry on, then my program will have a huge list of if statements, which doesnt look very clean at all. if there is a better and more effective way i would appreciate some help in implementing it.

2

There are 2 best solutions below

0
0___________ On

It is quite a complex task and I would suggest using a ready-made library.

  1. POSIX getopt https://www.gnu.org/software/libc/manual/html_node/Getopt.html or

  2. GNU argp https://www.gnu.org/software/libc/manual/html_node/Argp.html

1
J.K. Xu On

This library will do the task clean and well: https://github.com/XUJINKAI/cmdparser/

Basic example below, it also support nested sub-commands (like git), etc.

static cmdp_command_st cmdp = {
    .options = {
        {'i', "Int", "Input Int Option", CMDP_TYPE_INT4, &arg.i},
        {0},
    },
    .fn_process = callback,
};

int main(int argc, char **argv)
{
    return cmdp_run(argc - 1, argv + 1, &cmdp);
}