]> git.ipfire.org Git - thirdparty/squid.git/blob - src/CommandLine.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / CommandLine.cc
1 /*
2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #include "squid.h"
10
11 #include "CommandLine.h"
12 #include "sbuf/SBuf.h"
13
14 static void
15 ResetGetopt(const bool allowStderrWarnings)
16 {
17 opterr = allowStderrWarnings;
18 // Resetting optind to zero instead of conventional '1' has an
19 // advantage, since it also resets getopt(3) global state.
20 // getopt(3) always skips argv[0], even if optind is zero
21 optind = 0;
22 }
23
24 CommandLine::CommandLine(int argC, char *argV[], const char *shortRules, const RawLongOption *longRules):
25 argv_(),
26 shortOptions_(shortRules ? xstrdup(shortRules) : ""),
27 longOptions_()
28 {
29 assert(argC > 0); // C++ main() requirement that makes our arg0() safe
30 assert(shortRules);
31
32 /* copy argV items */
33 argv_.reserve(argC+1);
34 for (int i = 0; i < argC; ++i)
35 argv_.push_back(xstrdup(argV[i]));
36 argv_.push_back(nullptr); // POSIX argv "must be terminated by a null pointer"
37
38 /* copy grammar rules for the long options */
39 if (longRules) {
40 for (auto longOption = longRules; longOption->name; ++longOption)
41 longOptions_.emplace_back(*longOption);
42 longOptions_.emplace_back();
43 }
44 }
45
46 CommandLine::CommandLine(const CommandLine &them):
47 CommandLine(them.argc(), them.argv(), them.shortOptions_, them.longOptions())
48 {
49 }
50
51 CommandLine &
52 CommandLine::operator =(const CommandLine &them)
53 {
54 // cannot just swap(*this, them): std::swap(T,T) may call this assignment op
55 CommandLine tmp(them);
56 std::swap(argv_, tmp.argv_);
57 std::swap(shortOptions_, tmp.shortOptions_);
58 std::swap(longOptions_, tmp.longOptions_);
59 return *this;
60 }
61
62 CommandLine::~CommandLine()
63 {
64 for (auto arg: argv_)
65 xfree(arg);
66
67 xfree(shortOptions_);
68 }
69
70 bool
71 CommandLine::hasOption(const int optIdToFind, const char **optValue) const
72 {
73 ResetGetopt(false); // avoid duped warnings; forEachOption() will complain
74 int optId = 0;
75 while (nextOption(optId)) {
76 if (optId == optIdToFind) {
77 if (optValue) {
78 // do not need to copy the optarg string because it is a pointer into the original
79 // argv array (https://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html)
80 *optValue = optarg;
81 }
82 return true;
83 }
84 }
85 return false;
86 }
87
88 void
89 CommandLine::forEachOption(Visitor visitor) const
90 {
91 ResetGetopt(true);
92 int optId = 0;
93 while (nextOption(optId))
94 visitor(optId, optarg);
95 }
96
97 /// extracts the next option (if any)
98 /// \returns whether the option was extracted
99 /// throws on unknown option or missing required argument
100 bool
101 CommandLine::nextOption(int &optId) const
102 {
103 optId = getopt_long(argc(), argv(), shortOptions_, longOptions(), nullptr);
104 if ((optId == ':' && shortOptions_[0] == ':') || optId == '?') {
105 assert(optind > 0 && static_cast<unsigned int>(optind) < argv_.size());
106 SBuf errMsg;
107 errMsg.Printf("'%s': %s", argv_[optind - 1], optId == '?' ?
108 "unrecognized option or missing required argument" : "missing required argument");
109 throw TexcHere(errMsg);
110 }
111 return optId != -1;
112 }
113
114 void
115 CommandLine::resetArg0(const char *programName)
116 {
117 assert(programName);
118 xfree(argv_[0]);
119 argv_[0] = xstrdup(programName);
120 }
121
122 void
123 CommandLine::pushFrontOption(const char *name, const char *value)
124 {
125 assert(name);
126 argv_.insert(argv_.begin() + 1, xstrdup(name));
127 if (value)
128 argv_.insert(argv_.begin() + 2, xstrdup(value));
129 }
130
131 LongOption::LongOption() :
132 option({nullptr, 0, nullptr, 0})
133 {
134 }
135
136 LongOption::LongOption(const RawLongOption &opt) :
137 option({nullptr, 0, nullptr, 0})
138 {
139 copy(opt);
140 }
141
142 LongOption::LongOption(const LongOption &opt):
143 LongOption(static_cast<const RawLongOption &>(opt))
144 {
145 }
146
147 LongOption::~LongOption()
148 {
149 xfree(name);
150 }
151
152 LongOption &
153 LongOption::operator =(const LongOption &opt)
154 {
155 if (this != &opt)
156 copy(static_cast<const RawLongOption &>(opt));
157 return *this;
158 }
159
160 void
161 LongOption::copy(const RawLongOption &opt)
162 {
163 xfree(name);
164 name = opt.name ? xstrdup(opt.name) : nullptr;
165 has_arg = opt.has_arg;
166 flag = opt.flag;
167 val = opt.val;
168 }
169