aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/getopt/small/last_getopt_parser.h
blob: 6b5c8cbb9794a368b0f2c99973684462cf59b0cc (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
143
144
145
146
147
148
149
150
151
152
153
154
#pragma once

#include "last_getopt_opts.h"

#include <library/cpp/colorizer/fwd.h>

#include <util/generic/hash_set.h>
#include <util/generic/list.h>

namespace NLastGetopt {
    /** 
* NLastGetopt::TOptsParser is an implementation of parsing
* argv/argv into TOptsParseResult by rules of TOpts.
*
* The class allows to make complicated handlers.
* Note, that if PERMUTE mode is on, then data, pointed by argv can be changed.
*/
    class TOptsParser { 
        enum EIsOpt { 
            EIO_NONE,  //is not an option name 
            EIO_SDASH, //single-dashed ('-c') option name 
            EIO_DDASH, //double-dashed ("--opt") option name 
            EIO_PLUS,  //plus prefix ("+opt") option name 
        }; 

    public:                 // TODO: make private 
        const TOpts* Opts_; //rules of parsing 

        // argc/argv pair 
        size_t Argc_; 
        const char** Argv_; 

    private: 
        //the storage of last unkown options. TODO: can be moved to local-method scope 
        TCopyPtr<TOpt> TempCurrentOpt_; 

    public: 
        //storage of argv[0] 
        TString ProgramName_; 

        //state of parsing: 

        size_t Pos_; // current element withing argv 
        size_t Sop_; // current char within arg 
        bool Stopped_; 
        bool GotMinusMinus_; //true if "--" have been seen in argv 

    protected: 
        const TOpt* CurrentOpt_;  // ptr on the last meeted option 
        TStringBuf CurrentValue_; // the value of the last met argument (corresponding to CurrentOpt_) 

    private: 
        typedef THashSet<const TOpt*> TdOptSet; 
        TdOptSet OptsSeen_; //the set of options that have been met during parsing 

        TList<const TOpt*> OptsDefault_; 

    private: 
        void Init(const TOpts* options, int argc, const char* argv[]); 
        void Init(const TOpts* options, int argc, char* argv[]); 

        bool CommitEndOfOptions(size_t pos); 
        bool Commit(const TOpt* currentOption, const TStringBuf& currentValue, size_t pos, size_t sop); 

        bool ParseShortOptArg(size_t pos); 
        bool ParseOptArg(size_t pos); 
        bool ParseOptParam(const TOpt* opt, size_t pos); 
        bool ParseUnknownShortOptWithinArg(size_t pos, size_t sop); 
        bool ParseShortOptWithinArg(size_t pos, size_t sop); 
        bool ParseWithPermutation(); 

        bool DoNext(); 
        void Finish(); 

        EIsOpt IsOpt(const TStringBuf& arg) const; 

        void Swap(TOptsParser& that); 

    public: 
        TOptsParser(const TOpts* options, int argc, const char* argv[]) { 
            Init(options, argc, argv); 
        } 

        TOptsParser(const TOpts* options, int argc, char* argv[]) { 
            Init(options, argc, argv); 
        } 

        /// fetch next argument, false if no more arguments left 
        bool Next(); 

        bool Seen(const TOpt* opt) const {
            return OptsSeen_.contains(opt);
        }

        bool Seen(TStringBuf name) const {
            if (auto opt = Opts_->FindLongOption(name)) {
                return Seen(opt);
            } else {
                return false;
            }
        }

        bool Seen(char name) const {
            if (auto opt = Opts_->FindCharOption(name)) {
                return Seen(opt);
            } else {
                return false;
            }
        }

        const TOpt* CurOpt() const { 
            return CurrentOpt_; 
        } 

        const char* CurVal() const { 
            return CurrentValue_.data(); 
        } 

        const TStringBuf& CurValStr() const { 
            return CurrentValue_; 
        } 

        TStringBuf CurValOrOpt() const { 
            TStringBuf val(CurValStr()); 
            if (!val.IsInited() && CurOpt()->HasOptionalValue()) 
                val = CurOpt()->GetOptionalValue(); 
            return val; 
        } 

        TStringBuf CurValOrDef(bool useDef = true) const { 
            TStringBuf val(CurValOrOpt()); 
            if (!val.IsInited() && useDef && CurOpt()->HasDefaultValue()) 
                val = CurOpt()->GetDefaultValue(); 
            return val; 
        } 

        // true if this option was actually specified by the user 
        bool IsExplicit() const { 
            return nullptr == CurrentOpt_ || !OptsSeen_.empty(); 
        } 

        bool CurrentIs(const TString& name) const { 
            return CurOpt()->NameIs(name); 
        } 

        const TString& ProgramName() const { 
            return ProgramName_; 
        } 

        void PrintUsage(IOutputStream& os = Cout) const; 

        void PrintUsage(IOutputStream& os, const NColorizer::TColors& colors) const; 
    }; 
} //namespace NLastGetopt