0

I'm learning C, and got stuck doing cli parsing with <argp.h>. I want to specify path with -p, --path flags, so I did this:

#include "treesome.h"
#include <argp.h>
#include <stdio.h>

const char *argp_program_version =
    "treesome-build 0.2";


static char doc[] =
    "Treesome -- filesystem tree-like output\
\v Tree will show easy to eyeball directory structure";

static char args_doc[] = "";

static struct argp_option options[] = {
{0,0,0,0, "Output view" },
{"all", 'a', 0, 0, "produce verbose output with all the content"},
{"dereference", 'd', 0, 0, "dereferences soft links"},
{"path", 'p', 0, OPTION_ARG_OPTIONAL, "specify path for tree root"},
{ 0 }
};

struct arguments {
    int all, derefence, is_path;
    char *path;
};

static error_t parse_opts(int key, char *arg, struct argp_state *state) {
    struct arguments *arguments = state->input;

    switch (key) {
        case 'a':
            arguments->all = 1;
            break;
        case 'd':
            arguments->derefence = 1;
            break;
        case 'p':
            arguments->is_path = 1;
            break;
        case ARGP_KEY_ARG:
            if (state->arg_num == 0)
                break;
            if (arguments->is_path == 1)
                arguments->path = arg;
            break;
        default:
            return ARGP_ERR_UNKNOWN;
    }
    return 0;
};

static struct argp argp = {
options,
parse_opts,
args_doc,
doc
};

int main(int argc, char **argv) {
    struct arguments arguments;

    arguments.all = 0;
    arguments.derefence = 0;
    arguments.path = ".";

    argp_parse(&argp, argc, argv, 0, 0, &arguments);
    printf("Called with args: \n");
    printf("%d for all\n", arguments.all);
    printf("%d for dereference\n", arguments.derefence);
    printf("%s for path\n\n", arguments.path);
    return treesome(arguments.path);
};

and typing ./tree -p /home/floatfoo/ I got that path is always default. What might be a problem? I dont quite understand what for ARGP_KEY_ARG and ARGP_KEY_ARGS are used for

floatfoo
  • 83
  • 2
  • 8
  • 2
    Please post a full [MCVE]. Where is `#include ` and `main`? How is `argp` struct defined? `I got that path` How do you "get that" - what value do you print (do you print it?) and how? If you are using `argp.h`, are you calling `argp_parse`? How and where is `parse_opts` used? Is it used by argp at all? Where is the default for "path" defined and how is it used? Don't you want just `case 'p': arguments->path = arg`? – KamilCuk Oct 06 '22 at 07:25
  • @KamilCuk I've tried `case 'p': arguments->path = arg`. Just keep getting `Too many arguments` – floatfoo Oct 06 '22 at 07:34

1 Answers1

1

After removing treesome your option does not take an argument:

{"path", 'p', 0, OPTION_ARG_OPTIONAL, "specify path for tree root"},
             ^^^

./a.out --help
     -p, --path                 specify path for tree root

You have to take the option:

 {"path", 'p', "path", OPTION_ARG_OPTIONAL, "specify path for tree root"},

 ./a.out --help
     -p, --path[=path]          specify path for tree root

In which case only the long form takes the option.

./a.out -p smth      -> too many arguments
./a.out --path=smth  -> ok

Remove OPTION_ARG_OPTIONAL if you want -p to take arg. And also set your path and remove the KEY_ARG case. It's just:

static error_t parse_opts(int key, char *arg, struct argp_state *state) {
    struct arguments *arguments = state->input;

    switch (key) {
        case 'a':
            arguments->all = 1;
            break;
        case 'd':
            arguments->derefence = 1;
            break;
        case 'p':
            arguments->path = arg;
            break;
        default:
            return ARGP_ERR_UNKNOWN;
    }
    return 0;
};
KamilCuk
  • 120,984
  • 8
  • 59
  • 111