]> git.ipfire.org Git - thirdparty/squid.git/blame - src/CommandLine.cc
CI: Remove unnecessary test-functionality test wrappers (#1393)
[thirdparty/squid.git] / src / CommandLine.cc
CommitLineData
28bca1f7 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
28bca1f7
EB
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
14static void
15ResetGetopt(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
24CommandLine::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
46CommandLine::CommandLine(const CommandLine &them):
47 CommandLine(them.argc(), them.argv(), them.shortOptions_, them.longOptions())
48{
49}
50
51CommandLine &
52CommandLine::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
62CommandLine::~CommandLine()
63{
64 for (auto arg: argv_)
65 xfree(arg);
66
67 xfree(shortOptions_);
68}
69
70bool
71CommandLine::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
88void
89CommandLine::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
100bool
101CommandLine::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
114void
115CommandLine::resetArg0(const char *programName)
116{
117 assert(programName);
118 xfree(argv_[0]);
119 argv_[0] = xstrdup(programName);
120}
121
122void
123CommandLine::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
131LongOption::LongOption() :
132 option({nullptr, 0, nullptr, 0})
133{
134}
135
136LongOption::LongOption(const RawLongOption &opt) :
137 option({nullptr, 0, nullptr, 0})
138{
139 copy(opt);
140}
141
142LongOption::LongOption(const LongOption &opt):
143 LongOption(static_cast<const RawLongOption &>(opt))
144{
145}
146
147LongOption::~LongOption()
148{
149 xfree(name);
150}
151
152LongOption &
153LongOption::operator =(const LongOption &opt)
154{
155 if (this != &opt)
156 copy(static_cast<const RawLongOption &>(opt));
157 return *this;
158}
159
160void
161LongOption::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