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.

Jordan Running
  • 102,619
  • 17
  • 182
  • 182
Ybarra
  • 175
  • 3
  • 12
  • What does the code you've written so far look like? – Jordan Running Apr 28 '15 at 03: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 – Ybarra Apr 28 '15 at 03: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) – Ybarra Apr 28 '15 at 03:22
  • See how to create an MCVE ([How to create a Minimal, Complete, and Verifiable Example?](http://stackoverflow.com/help/mcve)) or SSCCE ([Short, Self-Contained, Correct Example](http://sscce.org/)) — 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. – Jonathan Leffler Apr 28 '15 at 03:24
  • Just made an edit. Thanks for the responses. – Ybarra Apr 28 '15 at 03:27
  • See [Parsing command line arguments](http://stackoverflow.com/questions/9642732/) and [`getopt()` does not parse optional arguments to parameters](http://stackoverflow.com/questions/1052746/) and [Pass arguments into a C program from the command line](http://stackoverflow.com/questions/498320/), amongst others. – Jonathan Leffler Apr 28 '15 at 03:32
  • Thank you @JonathanLeffler , the last link helped a lot! – Ybarra Apr 28 '15 at 03:52

4 Answers4

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)
$
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Will this work the same way if the non-optional arguments were listed before the optional arguments? @JonathanLeffler – Ybarra Apr 28 '15 at 05:04
  • @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()`](http://www.gnu.org/software/libc/manual/html_node/Getopt.html) 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. – Jonathan Leffler Apr 28 '15 at 05:11
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

phil
  • 561
  • 3
  • 10
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.

Richard Schwartz
  • 14,463
  • 2
  • 23
  • 41
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.

Nav
  • 1