aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/getopt/small/opt.h
blob: 6bd81e62cb0188a6e42ba9f6451d555ce85e9a00 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#pragma once

#include "last_getopt.h"

#include <util/generic/ptr.h>
#include <util/generic/noncopyable.h>

// implementation of Opt class using last getopt

/*
 short-options syntax:

 opt-letter ::=
     [^: ]

 opt-string ::=
     '+'|'-'?({opt-letter}':'{0,2})*

 example: "AbCx:y:z::"
    {A,b,C} options without argument
    {x,y}   options with argument
    {z} option  with optional argument

 1. shortopts begins with '-'   :=> RETURN_IN_ORDER
    == non-option forces getopt to return 1 and to place non-option into optarg

 2. shortopts begins with '+'   :=> REQUIRE_ORDER
    GetEnv(_POSIX_OPTION_ORDER) :=> REQUIRE_ORDER
    == 1st non-option forces getopt to return EOF

 3. default            :=> PERMUTE
    == exchange options with non-options and place all options first

 4. '--' command line argument forces getopt to stop parsing and to return EOF
     in any case

  long options should begin by '+' sign
  or when (_getopt_long_only = 1) by '-' sign

  struct option {
   char *name : option name
   int has_arg: 0 | 1 | 2 = without | with | optional argument
   int *flag  : if (flag != 0) then getopt returns 0 and stores val into *flag
   int val    : if (flag == 0) then getopt returns val
  }

  Example:

  struct option my_opts[] = {
    { "delete", 0, &deletion_flag, DEL }, -- returns 0, deletion_flag := DEL
    { "add",    1,       NULL, 'a' }, -- returns 'a', argument in optarg
    { NULL }
  }
*/

#define OPT_RETURN_IN_ORDER "-"
#define OPT_REQUIRE_ORDER "+"
#define OPT_DONT_STORE_ARG ((void*)0)

class Opt : TNonCopyable {
public:
    enum HasArg { WithoutArg,
                  WithArg,
                  PossibleArg };

    struct Ion {
        const char* name;
        HasArg has_arg;
        int* flag;
        int val;
    };

private:
    THolder<NLastGetopt::TOpts> Opts_;
    THolder<NLastGetopt::TOptsParser> OptsParser_;
    const Ion* Ions_;
    bool GotError_;

    void Init(int argc, char* argv[], const char* optString, const Ion* longOptions = nullptr, bool longOnly = false, bool isOpen = false);

public:
    Opt(int argc, char* argv[], const char* optString, const Ion* longOptions = nullptr, bool longOnly = false, bool isOpen = false);
    Opt(int argc, const char* argv[], const char* optString, const Ion* longOptions = nullptr, bool longOnly = false, bool isOpen = false);

    // Get() means next
    int Get();
    int Get(int* longOptionIndex);
    int operator()() {
        return Get();
    }

    const char* GetArg() const {
        return Arg;
    }

    TVector<TString> GetFreeArgs() const {
        return NLastGetopt::TOptsParseResult(&*Opts_, GetArgC(), GetArgV()).GetFreeArgs(); 
    } 
 
    // obsolete, use GetArg() instead
    char* Arg; /* option argument if any or NULL */

    int Ind;  /* command line index */
    bool Err; /* flag to print error messages */

    int GetArgC() const;
    const char** GetArgV() const;

    void DummyHelp(IOutputStream& os = Cerr);
};

// call before getopt. returns non-negative int, removing it from arguments (not found: -1)
// Example: returns 11 for "progname -11abc", -1 for "progname -a11"
int opt_get_number(int& argc, char* argv[]);

#define OPTION_HANDLING_PROLOG                \
    {                                         \
        int optlet;                           \
        while (EOF != (optlet = opt.Get())) { \
            switch (optlet) {
#define OPTION_HANDLING_PROLOG_ANON(S)        \
    {                                         \
        Opt opt(argc, argv, (S));             \
        int optlet;                           \
        while (EOF != (optlet = opt.Get())) { \
            switch (optlet) {
#define OPTION_HANDLE_BEGIN(opt) case opt: {
#define OPTION_HANDLE_END \
    }                     \
    break;

#define OPTION_HANDLE(opt, handle) \
    OPTION_HANDLE_BEGIN(opt)       \
    handle;                        \
    OPTION_HANDLE_END

#define OPTION_HANDLING_EPILOG                   \
    default:                                     \
        ythrow yexception() << "unknown optlet"; \
        }                                        \
        }                                        \
        }