7

I have a program that takes in optional arguments. The necessary arguments are a file and integers (1 or more). The optional arguments are a mix of strings and integers.

So a 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 the integers after trace_file into an array. I'm having trouble figuring out how to do this when the optional arguments are enabled, because another integer is on the command line. A push in the right direction would be greatly appreciated, because I cannot figure out how to do this.

EDIT: so far, all I have for parsing the arguments is this:

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 when no optional arguments are entered.

7
  • What does the code you've written so far look like? Commented Apr 28, 2015 at 3:19
  • It's kind of a lot to post. The program is for an assignment in school, where we are simulating address paging. So, the question im asking is really just a 'simple' part of my program Commented Apr 28, 2015 at 3:21
  • But what would you like to see? I really just want to know how I would get the integers that come after 'trace_file', regardless of how the user would input them on the command line (e.g. ./main trace_file 8 7 4 –n 3000000 –p page.txt) Commented Apr 28, 2015 at 3:22
  • See how to create an MCVE (How to create a Minimal, Complete, and Verifiable Example?) or SSCCE (Short, Self-Contained, Correct Example) — two names and links for the same basic idea. You should be able to reduce your code to that part of the main program which manages options and create a loop after the option handling code that prints the other arguments. You should be able to do it in about 30 lines, probably less. You could also search for similar questions here on SO; there are a number of them, I'm sure. Commented Apr 28, 2015 at 3:24
  • Just made an edit. Thanks for the responses. Commented Apr 28, 2015 at 3:27

4 Answers 4

5

I don't see any major problems if you use a reasonably POSIX-compliant version of getopt().

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

Example runs

$ ./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)
$
Sign up to request clarification or add additional context in comments.

2 Comments

Will this work the same way if the non-optional arguments were listed before the optional arguments? @JonathanLeffler
@Ybarra: it depends on the version of getopt() you use. POSIX requires options to appear before non-option arguments; so do BSD, Solaris, AIX and HP-UX, AFAICR. GNU getopt() and getopt_long() do not (unless you set the environment variable POSIXLY_CORRECT). I'm probably in a minority, but I don't like the GNU behaviour and don't often use it. In a previous job, I had POSIXLY_CORRECT set — and managed to break someone else's script that relied on it not being set. That's plain nasty (or careless) as far as I'm concerned.
0

I've given this a bit of thought and there is no simple way for getopt to return multiple arguments. I did wonder about defining "y::",but have dismissed this. Options are

1) have 2 options y and Y use one for each int and a boolean flag to catch the exception where y is defined, but Y isn't.

2) leave complex options like y out of the getopt cycle. Once getopt has processed options and shuffled arguments. Pre process these arguments to capture the -y operands and code in the process arguments to skip -y and it's operands

3) it's more usual across *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 string it points too needs to be parsed into the 2 tokens A and B from string A,B

Comments

0

If you can't use getopt() or some other function that does the hard work for you, then a possible strategy would be:

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

  • Write functions that deal with paired arguments (like "-n 300000" or "-p page.txt". Pass myargc and myargv into these functions by reference. Each such function returns the value associated with the argument (e.g., 300000 or page.txt) if it was found, or an invalid value (e.g., -1 or "") if it wasn't. And in either case, the function removes both items from myargv and decrements myargc by 2.

  • If you also have arguments that are just individual flags, write functions for those that return boolean indicating whether the flag was found, remove the flag from myargv, and decrements myargc by 1. (You could deal with trace_file this way, even if it's not optional. I'm assuming that trace_file is just a flag, and not related to the 8 that follows it.)

  • Call the functions for each of your optional arguments first. The stuff that's left in myargc and myargv after you've called them all should just be your required arguments, and you can process them as you normally would.

Comments

0

If you can't use getopt() or some other function that does the hard work for you, then a possible strategy would be:

Create new variables myargc, myargv, and copy argc and argv into them.

Write functions that deal with paired arguments (like "-n 300000" or "-p page.txt". Pass myargc and myargv into these functions by reference. Each such function returns the value associated with the argument (e.g., 300000 or page.txt) if it was found, or an invalid value (e.g., -1 or "") if it wasn't. And in either case, the function removes both items from myargv and decrements myargc by 2.

If you also have arguments that are just individual flags, write functions for those that return boolean indicating whether the flag was found, remove the flag from myargv, and decrements myargc by 1. (You could deal with trace_file this way, even if it's not optional. I'm assuming that trace_file is just a flag, and not related to the 8 that follows it.)

Call the functions for each of your optional arguments first.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.