📜 ⬆️ ⬇️

Parsing command line options on UNIX-like systems

Introduction


One of the important tasks of any program, be it console or graphical, is the interpretation of command line arguments . Formally, all the words in the command line (including the name of the command itself) broken by a separator (as a rule, this is a space and a tab) are called arguments, while quotation marks allow including separators in arguments.
Arguments can be divided into options and operands . Options change the behavior of the program or provide it with additional information. An option may have its own arguments, which are information necessary only for this option.

Posix


The POSIX standard describes the expected behavior of programs on UNIX-like systems. When writing a program, no one will force you to strictly follow the standard, however, this is a good idea, as this will make your users life easier. Here are the basic rules for command arguments:


Long options


GNU programs also use long options whose behavior is not described in POSIX; long options start with "-" The following conventions are also implemented for these options in GNU:


Where do the parameters in the program come from


as it is known, the main () function in C is defined as:
int main(int argc, char *argv[])
Here there are two parameters: argc determines the number of arguments on the command line, and argv stores an array of pointers to these arguments.
It should be noted that argv [0] is always the name of the command, and argv [argc] == NULL , these two facts may be useful in development.
')

Parsing options


In the 1980s, the Unix support team noticed that each Unix program uses its own method of parsing options. This prompted the development of the getopt () function to make it easier to write code that follows standard conventions.
The GNU getopt_long () function is compatible with getopt () , and also simplifies the parsing of long options.

getopt


Announcement:
#include <unistd.h>
int getopt(int argc, char *argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;

The argc and argv arguments are passed directly from the main () function, and optstring is a string of option characters. If any letter in the line is followed by a colon, then this option takes an argument.
To use getopt (), it is called again in a loop, until it returns -1 . Each time a valid option character is found, the function returns this character. If the option takes an argument, then the pointer to it is placed in the variable optarg .
The optind variable stores the current index in argv . When the opterr variable is not zero (the default is 0 ), getopt () itself displays messages in case of an invalid option or no argument. If opterr is zero, then if an error occurs, getopt () returns "?" or ":" , depending on whether an invalid option is found or the required argument of the option is omitted, the detected symbol will be found in the optopt variable.
It should be noted that the standard getopt () function stops as soon as it finds the first argument that does not begin with the “-” character, the GNU option scans the option line for the entire command line. The behavior of the GNU functions can be changed (but this is beyond the scope of the article).

sample program using getopt ()


Courtesy of iv_s

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. int main ( int argc, char ** argv) {
  5. if (argc == 1) { // if we run without arguments, display help
  6. printf ( "getopt test \ n" );
  7. printf ( "usage: \ n" );
  8. printf ( "opts -an -bm -os \ n" );
  9. printf ( "example: \ n" );
  10. printf ( "$ opts -a 323 -b 23 -o '-' \ n" );
  11. printf ( "323 - 23 = 300 \ n" );
  12. return 0;
  13. }
  14. char * opts = "a: b: o:" ; // available options, each takes an argument
  15. int a, b; // store numbers here
  16. char op; // and here is the operator
  17. int opt; // each next option gets here
  18. while ((opt = getopt (argc, argv, opts))! = -1) { // call getopt until it returns -1
  19. switch (opt) {
  20. case 'a' : // if the -a option, convert the string with the argument to a number
  21. a = atoi (optarg);
  22. break ;
  23. case 'b' : // for -b too
  24. b = atoi (optarg);
  25. break ;
  26. case 'o' : // in op save the statement
  27. op = optarg [0];
  28. break ;
  29. }
  30. }
  31. switch (op) {
  32. case '+' : // if opator + add, etc.
  33. printf ( "% d +% d =% d \ n" , a, b, a + b);
  34. break ;
  35. case '-' :
  36. printf ( "% d -% d =% d \ n" , a, b, a - b);
  37. break ;
  38. case '*' :
  39. printf ( "% d *% d =% d \ n" , a, b, a * b);
  40. break ;
  41. case '/' :
  42. printf ( "% d /% d =% d \ n" , a, b, a / b);
  43. break ;
  44. }
  45. return 0;
  46. }
* This source code was highlighted with Source Code Highlighter .


getopt_long ()


Announcement:
#include <getopt.h>

int getopt_long(int argc, char *argv[], const char *optstring, const struct option *longopts, int *longindex);

the first three arguments are the same as in getopt () , longopts is a pointer to an array of long options, longindex points to a variable in which the index of the detected long options is placed in longopts , if this may not be necessary NULL .

The option structure is defined as follows:
struct option
{
const char *name;
int has_arg;
int *flag;
int val;
}


name - the name of the option without preceding dashes;
has_arg - as the name implies, the variable describes whether the long option has an argument that can take three values:

flag - if this pointer is NULL , then getopt_long () returns the value of the val field, otherwise it returns 0 , and the variable pointed to by flag is filled with the value of val ;
val - usually contains some symbolic constant, if the long option is short, then this constant must be the same as the one that appears in the argument optstring .
It is important to note that the last element of the longopts array must be filled with zeros.

Sample program using getopt_long ()


Courtesy of shuffle

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <getopt.h>
  5. void usage ( char * name)
  6. {
  7. printf ( "usage:% s \ n \ \ th this message \ n \ \ tc [config file] \ n \ \ t - help this message \ n \ \ t - config = config_file \ n", name);
  8. return ;
  9. }
  10. int main ( int argc, char * argv [])
  11. {
  12. int c;
  13. while (1) {
  14. static struct option long_opt [] = {
  15. { "Help" , 0, 0, 'h' },
  16. { "Config" , 1, 0, 'c' },
  17. {0,0,0,0}
  18. };
  19. int optIdx;
  20. if ((c = getopt_long (argc, argv, "c: h" , long_opt, & optIdx)) == -1)
  21. break ;
  22. switch (c) {
  23. case 'h' :
  24. usage (argv [0]);
  25. return (-1);
  26. case 'c' :
  27. printf ( "option 'c' selected, filename:% s \ n" , optarg);
  28. return (1);
  29. default :
  30. usage (argv [0]);
  31. return (-1);
  32. }
  33. }
  34. return (0);
  35. }
* This source code was highlighted with Source Code Highlighter .


Conclusion


The article describes the basics of using the functions of parsing command line arguments on UNIX-like systems. This material can be more extensive, but any interested person is able to learn and learn all the subtleties on their own.

The article was prepared on the basis of the book by Arnold Robbins "Linux programming in examples" ISBN 5-9579-0059-1

Source: https://habr.com/ru/post/55665/


All Articles