Parsing optional command line arguments in C

I have a program that accepts optional arguments. The required arguments are a file and integers (1 or more). Optional arguments are a combination of strings and integers.

Thus, the correct input on the command line could be:

./main trace_file 8 12 # (only necessary arguments) ./main –n 3000000 –p page.txt trace_file 8 7 4 # (with optional arguments) 

I need to get integers after trace_file into an array. I find it difficult to figure out how to do this when additional arguments are included, because another integer is on the command line. A push in the right direction would be very helpful, because I cannot figure out how to do this.

EDIT: So far, all I have to parse the arguments is the following:

 for(j=2, k=0; j<argc; j++, k++) { shift += atoi(argv[j]); shiftArr[k] = 32 - shift; bitMaskArr[k] = (int)(pow(2, atoi(argv[j])) - 1) << (shiftArr[k]); entryCnt[k] = (int)pow(2, atoi(argv[j])); } 

But this will only work if no additional arguments are entered.

+6
source share
3 answers

I do not see any serious problems if you use a version of getopt() that is acceptable for POSIX.

Source Code ( goo.c )

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> /* ./main trace_file 8 12 # (only necessary arguments) ./main –n 3000000 –p page.txt trace_file 8 7 4 # (with optional arguments) */ static void usage(const char *argv0) { fprintf(stderr, "Usage: %s [-n number][-p pagefile] trace n1 n2 ...\n", argv0); exit(EXIT_FAILURE); } int main(int argc, char **argv) { int number = 0; char *pagefile = "default.txt"; char *tracefile; int opt; while ((opt = getopt(argc, argv, "n:p:")) != -1) { switch (opt) { case 'p': pagefile = optarg; break; case 'n': number = atoi(optarg); break; default: usage(argv[0]); } } if (argc - optind < 3) { fprintf(stderr, "%s: too few arguments\n", argv[0]); usage(argv[0]); } tracefile = argv[optind++]; printf("Trace file: %s\n", tracefile); printf("Page file: %s\n", pagefile); printf("Multiplier: %d\n", number); for (int i = optind; i < argc; i++) printf("Processing number: %d (%s)\n", atoi(argv[i]), argv[i]); return 0; } 

Compilation

 $ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \ > -Wold-style-definition -Werror goo.c -o goo 

Execution example

 $ ./goo trace_file 8 12 Trace file: trace_file Page file: default.txt Multiplier: 0 Processing number: 8 (8) Processing number: 12 (12) $ ./goo -n 3000000 -p page.txt trace_file 8 7 4 Trace file: trace_file Page file: page.txt Multiplier: 3000000 Processing number: 8 (8) Processing number: 7 (7) Processing number: 4 (4) $ 
+4
source

I thought a little, and there is no easy way for getopt to return multiple arguments. I really wondered about the definition of "y ::", but rejected this. Options

1) have 2 options y and Y use one for each int and a boolean flag to catch an exception where y is defined but Y is not.

2) leave complex options like y from the getopt loop. Once getopt has processed the parameters and mixed up the arguments. Pre-process these arguments to capture -y operands and code in the process arguments to skip -y and its operands

3), it is more common for * nix commands to provide multiple values ​​as a single argument, which itself is a comma-separated list of values. You achieve this by adding "y:" to your getopt processing. The line that it indicates should also be parsed in 2 tokens A and B from line A, B

0
source

If you cannot use getopt () or any other function that does the hard work for you, then a possible strategy would be:

  • Create the new variables myargc, myargv and copy argc and argv in them.

  • Write functions that handle paired arguments (for example, "-n 300000" or "-p page.txt"). Pass myargc and myargv to these functions by reference. Each such function returns the value associated with the argument (for example, 300000 or page.txt) if it was found, or an invalid value (for example, -1 or "") if it is not. And in any case, the function removes both elements from myargv and reduces myargc by 2.

  • If you also have arguments that are only separate flags, write functions for those that return a boolean indicating whether the flag was found, remove the flag from myargv and reduce myargc by 1. (You can deal with trace_file this path, even if it is optional. I assume that trace_file is just a flag and not associated with the 8 that follows it.)

  • First call the functions for each of your optional arguments. The materials left in myargc and myargv after you called them should be your required arguments, and you can process them as usual.

0
source

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


All Articles