Programming in C

Commandline Arguments

Gerald Senarclens de Grancy

Purpose of Commandline Arguments

  • Allow the user to pass information to a program upon startup
    • Which input files should be processed
      gcc infile.c
    • Options can be defined
      ls -l -a -h
    • Possible subcommands
      apt install programname

Issues

  • String parsing is tedious
  • ISO C's getopt (unistd.h) has limited features (eg. no long options)
  • Many libraries offer differing feature sets
  • Argument parsing libraries are usually not trivial to use

Foundation of Argument Passing

In C, arguments have to be passed to main(.)

argc
argument count
argv
argument vector
int main(int argc, char** argv) {
  /* work with arguments */
  return 0;
}

Example: Echo Arguments Without Using a Library

#include <stdio.h>

int main(int argc, char **argv) {
  for (int i = 0; i < argc; ++i) {
    puts(argv[i]);
  }
  return 0;
}
Download echo.c

Example: Show a Simple Help Message

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

int main(int argc, char **argv) {
  for (int i = 1; i < argc; ++i) {
    if (strcmp("-h", argv[i]) == 0 ||
        strcmp("--help", argv[i]) == 0) {
      puts("Usage: ls [OPTION]... ");
      puts("-h, --help display this help and exit");
      exit(0);
    }
  }
  puts("To solve the world's problems, use the correct arguments");
  return 0;
}
Download help.c

POSIX Standard getopt

+
standardized
avaiable everywhere
-
no support for long options
lack of support for subcommands etc.
#include <stdio.h>
#include <unistd.h>  /* for getopt */
int main (int argc, char **argv) {
  int c;
  int aopt = 0, bopt = 0;  // flags
  char *copt = 0, *dopt = 0;  // option arguments
  while ((c = getopt(argc, argv, "abc:d:")) != -1) {
    switch (c) {
    case 'a':
      aopt = 1;
      break;
    case 'b':
      bopt = 1;
      break;
    case 'c':
      copt = optarg;
      break;
    case 'd':
      dopt = optarg;
      break;
    case '?':
      break;
    default:
      printf ("?? getopt returned character code 0%o ??\n", c);
    }
  }
  if (optind < argc) {
      printf ("non-option ARGV-elements: ");
      while (optind < argc) {
          printf ("%s ", argv[optind++]);
      }
      printf ("\n");
  }
  printf ("aopt: %d, bopt: %d, copt: %s, dopt: %s\n",
    aopt, bopt, copt, dopt);
  return 0;
}
Download posix_getopt.c

GNU getopt_long

#include <stdio.h>
#include <stdbool.h>
#include <getopt.h>  // getopt_long
int main(int argc, char **argv) {
  int c;
  bool has_a = false, has_b = false;  // flags
  int verbosity_level = 0;
  char *c_arg = 0, *d_arg = 0;  // option_arguments
  static struct option long_options[] = {
  /* NAME       ARGUMENT           FLAG  VAL (SHORTNAME) */
    {"add",     required_argument, NULL, 0},
    {"append",  no_argument,       NULL, 1000},
    {"delete",  required_argument, NULL, 0},
    {"verbose", no_argument,       NULL, 'v'},
    {"create",  required_argument, NULL, 'c'},
    {"file",    required_argument, NULL, 0},
    {NULL,      0,                 NULL, 0}
  };
  int option_index = 0;
  while ((c = getopt_long(argc, argv, "abc:d:vz",
          long_options, &option_index)) != -1) {
    switch (c) {
    case 0:
      printf ("option %s", long_options[option_index].name);
      if (optarg) {
        printf (" with arg %s", optarg);
      }
      printf ("\n");
      break;
    case 1000:  // append
      puts("`append` option was given");
      break;
    case 'a':
      has_a = true;
      break;
    case 'b':
      has_b = true;
      break;
    case 'c':
      c_arg = optarg;
      break;
    case 'd':
      d_arg = optarg;
      break;
    case 'v':
      ++verbosity_level;
    case '?':
      break;
    default:  // "catches" option 'z'
      printf ("?? getopt returned character code 0%o ??\n", c);
    }
  }
  if (optind < argc) {
    printf ("non-option ARGV-elements: ");
    while (optind < argc) {
      printf ("%s ", argv[optind++]);
    }
    printf ("\n");
  }
  printf ("a: %s, b: %s, c_arg: %s, d_arg: %s, verbosity-level: %d\n",
          has_a ? "true" : "false", has_b ? "true" : "false", c_arg, d_arg, verbosity_level);
  return 0;
}
Download gnu_getopt.c

Comprehensive Example(s)

Look at the source code of your favorite commanline programs...

This can be done via apt source $PACKAGE

eg. apt source htop

Or checkout a repository, eg. cvrptwms (uses GNU getopt)

Other Libraries

There are many libraries for argument parsing...

... select the one that suits your needs

argparse
https://github.com/cofyc/argparse
MIT License

Exercise

Write a C program that takes the following arguments

-h, --help
-a, --author
display your name and email address
--color {red,green,blue}
display a message in the given color

Questions
and feedback...