• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OpenLightingProject / ola / 23384901691

21 Mar 2026 05:30PM UTC coverage: 45.055% (-0.7%) from 45.72%
23384901691

Pull #1855

github

web-flow
Merge 41df99d06 into 704337b09
Pull Request #1855: Update Debian Package Services and Config Directory

8554 of 19814 branches covered (43.17%)

0 of 6 new or added lines in 4 files covered. (0.0%)

324 existing lines in 56 files now uncovered.

22100 of 49051 relevant lines covered (45.06%)

48.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

44.34
/common/base/Flags.cpp
1
/*
2
 * This library is free software; you can redistribute it and/or
3
 * modify it under the terms of the GNU Lesser General Public
4
 * License as published by the Free Software Foundation; either
5
 * version 2.1 of the License, or (at your option) any later version.
6
 *
7
 * This library is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10
 * Lesser General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU Lesser General Public
13
 * License along with this library; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
 *
16
 * Flags.cpp
17
 * Handle command line flags.
18
 * Copyright (C) 2013 Simon Newton
19
 */
20

21
/**
22
 * @addtogroup flags
23
 * @{
24
 * @file common/base/Flags.cpp
25
 * @}
26
 */
27
#include <time.h>
28

29
#include <algorithm>
30
#include <iostream>
31
#include <string>
32
#include <vector>
33

34
#include "ola/base/Array.h"
35
#include "ola/base/Flags.h"
36
#include "ola/base/SysExits.h"
37
#include "ola/base/Version.h"
38
#include "ola/file/Util.h"
39
#include "ola/stl/STLUtils.h"
40

41
/**
42
 * @private
43
 * @brief Define the help flag
44
 */
45
DEFINE_s_default_bool(help, h, false, "Display the help message");
46
DEFINE_s_default_bool(version, v, false, "Display version information");
47
DEFINE_default_bool(gen_manpage, false, "Generate a man page snippet");
48

49
namespace ola {
50

51
/**
52
 * @addtogroup flags
53
 * @{
54
 */
55

56
using std::cerr;
57
using std::cout;
58
using std::endl;
59
using std::string;
60
using std::vector;
61

62
/**
63
 * The prefix used on inverted bool flags
64
 * @examplepara
65
 *   @code
66
 *   DEFINE_s_default_bool(noMaster, d, false, "Dummy flag to show NO_PREFIX")
67
 *   @endcode
68
 *
69
 *   Then if you called your application with that flag:
70
 *   @code
71
 *   bash$myapplication -d
72
 *   @endcode
73
 *   Then the noMaster flag would be true.
74
 */
75
const char Flag<bool>::NO_PREFIX[] = "no-";
76

77
void SetHelpString(const string &first_line, const string &description) {
97✔
78
  GetRegistry()->SetFirstLine(first_line);
97✔
79
  GetRegistry()->SetDescription(description);
97✔
80
}
97✔
81

82
void DisplayUsage() {
×
83
  GetRegistry()->DisplayUsage();
×
84
}
×
85

86
void DisplayUsageAndExit() {
×
87
  GetRegistry()->DisplayUsage();
×
88
  exit(ola::EXIT_USAGE);
×
89
}
90

91
void DisplayVersion() {
×
92
  GetRegistry()->DisplayVersion();
×
93
}
×
94

95
void GenManPage() {
×
96
  GetRegistry()->GenManPage();
×
97
}
×
98

99
void ParseFlags(int *argc, char **argv) {
104✔
100
  GetRegistry()->ParseFlags(argc, argv);
104✔
101
}
104✔
102

103
/**
104
 * @}
105
 * @cond HIDDEN_SYMBOLS
106
 */
107

108
static FlagRegistry *registry = NULL;
109

110
/*
111
 * Registered as an atexit function by the FlagRegistry constructor.
112
 */
113
void DeleteFlagRegistry() {
97✔
114
  FlagRegistry *old_registry = registry;
97✔
115
  registry = NULL;
97✔
116
  delete old_registry;
97✔
117
}
97✔
118

119
/*
120
 * Change the input to s/_/-/g
121
 */
122
void BaseFlag::ReplaceUnderscoreWithHyphen(char *input) {
108✔
123
  for (char *c = input; *c; c++) {
1,478✔
124
    if (*c == '_')
1,370✔
125
      *c = '-';
115✔
126
  }
127
}
108✔
128

129
/*
130
 * Convert a flag name to the canonical representation.
131
 */
132
const char *BaseFlag::NewCanonicalName(const char *name) {
772✔
133
  unsigned int total_size = strlen(name) + 1;
772✔
134
  char *output = new char[total_size];
772✔
135
  char *o = output;
772✔
136
  for (const char *i = name; *i; i++, o++) {
8,370✔
137
    if (*i == '_')
7,598✔
138
      *o = '-';
419✔
139
    else
140
      *o = *i;
7,179✔
141
  }
142
  output[total_size - 1] = 0;
772✔
143
  return output;
772✔
144
}
145

146
/**
147
 * @private
148
 * Get the global FlagRegistry object.
149
 */
150
FlagRegistry *GetRegistry() {
1,178✔
151
  if (!registry) {
1,178✔
152
    registry = new FlagRegistry();
97✔
153
    atexit(DeleteFlagRegistry);
97✔
154
  }
155
  return registry;
1,178✔
156
}
157

158
/**
159
 * Register a flag.
160
 */
161
void FlagRegistry::RegisterFlag(FlagInterface *flag) {
880✔
162
  STLInsertOrDie(&m_long_opts, flag->name(), flag);
880✔
163
  if (flag->short_opt()) {
880✔
164
    STLInsertOrDie(&m_short_opts, flag->short_opt(), flag);
347✔
165
  }
166
}
880✔
167

168
/**
169
 * @brief Parse the command line flags. This re-arranges argv so that only the
170
 * non-flag options remain.
171
 */
172
void FlagRegistry::ParseFlags(int *argc, char **argv) {
104✔
173
  const string long_option_prefix("--");
104✔
174
  const string short_option_prefix("-");
104✔
175

176
  m_argv0 = argv[0];
104✔
177

178
  int c;
104✔
179
  int option_index = 0;
104✔
180
  const string short_opts = GetShortOptsString();
104✔
181
  FlagMap flags;
104✔
182
  const struct option *long_options = GetLongOpts(&flags);
104✔
183

184
  optind = 0;  // reset each time
104✔
185
  while (1) {
140✔
186
    c = getopt_long(*argc, argv, short_opts.c_str(),
280✔
187
                    long_options, &option_index);
188

189
    if (c == -1) {
140✔
190
      break;
191
    } else if (c == '?') {
36✔
192
      exit(EXIT_USAGE);
×
193
    }
194

195

196
    FlagInterface *flag = STLFindOrNull(flags, c);
36✔
197
    if (!flag) {
36✔
198
      cerr << "Missing flag " << c << endl;
140✔
199
    } else {
200
      if (flag->has_arg()) {
36✔
201
        if (!flag->SetValue(optarg)) {
24✔
202
          cerr << "Invalid arg value " << optarg << " for flag "
×
203
               << flag->name() << endl;
×
204
          exit(EXIT_USAGE);
×
205
        }
206
      } else {
207
        if (!flag->SetValue("1")) {
12✔
208
          cerr << "Failed to set value of 1 for flag " << flag->name() << endl;
×
209
          exit(EXIT_USAGE);
×
210
        }
211
      }
212
    }
213
  }
214

215
  if (FLAGS_help) {
104✔
216
    DisplayUsage();
×
217
    exit(EXIT_OK);
×
218
  }
219

220
  if (FLAGS_version) {
104✔
221
    DisplayVersion();
×
222
    exit(EXIT_OK);
×
223
  }
224

225
  if (FLAGS_gen_manpage) {
104✔
226
    GenManPage();
×
227
    exit(EXIT_OK);
×
228
  }
229

230
  delete[] long_options;
104✔
231

232
  // Remove flags so only non-flag arguments remain.
233
  for (int i = 0; i < *argc - optind; i++) {
113✔
234
    argv[1 + i] = argv[optind + i];
9✔
235
  }
236
  *argc = 1 + *argc - optind;
104✔
237
}
104✔
238

239

240
void FlagRegistry::SetFirstLine(const string &first_line) {
97✔
241
  m_first_line = first_line;
97✔
242
}
97✔
243

244

245
void FlagRegistry::SetDescription(const string &description) {
97✔
246
  m_description = description;
97✔
247
}
97✔
248

249
/*
250
 * @brief Print the usage text to stdout
251
 */
252
void FlagRegistry::DisplayUsage() {
×
253
  cout << "Usage: " << m_argv0 << " " << m_first_line << endl << endl;
×
254
  if (!m_description.empty()) {
×
255
    cout << m_description << endl << endl;
×
256
  }
257

258
  // - comes before a-z which means flags without long options appear first. To
259
  // avoid this we keep two lists.
260
  vector<string> short_flag_lines, long_flag_lines;
×
261
  LongOpts::const_iterator iter = m_long_opts.begin();
×
262
  for (; iter != m_long_opts.end(); ++iter) {
×
263
    std::ostringstream str;
×
264
    const FlagInterface *flag = iter->second;
×
265
    if (flag->name() == FLAGS_gen_manpage.name()) {
×
266
      continue;
×
267
    }
268

269
    str << "  ";
×
270
    if (flag->short_opt()) {
×
271
      str << "-" << flag->short_opt() << ", ";
×
272
    }
273
    str << "--" << flag->name();
×
274

275
    if (flag->has_arg()) {
×
276
      str << " <" << flag->arg_type() << ">";
×
277
    }
278
    str << endl << "    " << iter->second->help() << endl;
×
279
    if (flag->short_opt())
×
280
      short_flag_lines.push_back(str.str());
×
281
    else
282
      long_flag_lines.push_back(str.str());
×
283
  }
×
284

285
  PrintFlags(&short_flag_lines);
×
286
  PrintFlags(&long_flag_lines);
×
287
}
×
288

289
/*
290
 * @brief Print the version text to stdout
291
 */
292
void FlagRegistry::DisplayVersion() {
×
293
  cout << "OLA " << m_argv0 << " version: " << ola::base::Version::GetVersion()
×
NEW
294
       << ", build: " << ola::base::Version::GetBuildName()
×
295
       << endl;
×
296
}
×
297

298
void FlagRegistry::GenManPage() {
×
299
  char date_str[100];
×
300
  time_t curtime;
×
301
  curtime = time(NULL);
×
302
  struct tm loctime;
×
303
#ifdef _WIN32
304
  loctime = *gmtime(&curtime);  // NOLINT(runtime/threadsafe_fn)
305
#else
306
  gmtime_r(&curtime, &loctime);
×
307
#endif  // _WIN32
308
  strftime(date_str, arraysize(date_str), "%B %Y", &loctime);
×
309

310
  string exe_name = ola::file::FilenameFromPathOrPath(m_argv0);
×
311

312
  if (0 != exe_name.compare(m_argv0)) {
×
313
    // Strip lt- off the start if present, in case we're generating the man
314
    // page from a libtool wrapper script for the exe
315
    ola::StripPrefix(&exe_name, "lt-");
×
316
  }
317

318
  // Convert newlines to a suitable format for man pages
319
  string man_description = m_description;
×
320
  ReplaceAll(&man_description, "\n", "\n.PP\n");
×
321

322
  // Guess at a single line synopsis, match ". " so we don't get standards
323
  string synopsis = "";
×
324
  std::size_t pos = man_description.find(". ");
×
325
  if (pos != string::npos) {
×
326
    synopsis = man_description.substr(0, pos + 1);
×
327
  } else {
328
    synopsis = man_description;
×
329
  }
330

331
  cout << ".TH " << exe_name << " 1 \"" << date_str << "\"" << endl;
×
332
  cout << ".SH NAME" << endl;
×
333
  cout << exe_name << " \\- " << synopsis << endl;
×
334
  cout << ".SH SYNOPSIS" << endl;
×
335
  cout << ".B " << exe_name << endl;
×
336
  cout << m_first_line << endl;
×
337
  cout << ".SH DESCRIPTION" << endl;
×
338
  cout << ".B " << exe_name << endl;
×
339
  cout << man_description << endl;
×
340
  cout << ".SH OPTIONS" << endl;
×
341

342
  // - comes before a-z which means flags without long options appear first. To
343
  // avoid this we keep two lists.
344
  vector<OptionPair> short_flag_lines, long_flag_lines;
×
345
  LongOpts::const_iterator iter = m_long_opts.begin();
×
346
  for (; iter != m_long_opts.end(); ++iter) {
×
347
    const FlagInterface *flag = iter->second;
×
348
    if (flag->name() == FLAGS_gen_manpage.name()) {
×
349
      continue;
×
350
    }
351

352
    std::ostringstream str;
×
353
    if (flag->short_opt()) {
×
354
      str << "-" << flag->short_opt() << ", ";
×
355
    }
356
    str << "--" << flag->name();
×
357

358
    if (flag->has_arg()) {
×
359
      str << " <" << flag->arg_type() << ">";
×
360
    }
361
    if (flag->short_opt()) {
×
362
      if (flag->name() == FLAGS_version.name()) {
×
363
        std::ostringstream help_str;
×
364
        help_str << "Print\n.B " << exe_name << "\nversion information.";
×
365
        short_flag_lines.push_back(
×
366
            OptionPair(str.str(), help_str.str()));
×
367
      } else {
×
368
        short_flag_lines.push_back(
×
369
            OptionPair(str.str(), iter->second->help()));
×
370
      }
371
    } else {
372
      long_flag_lines.push_back(
×
373
          OptionPair(str.str(), iter->second->help()));
×
374
    }
375
  }
×
376

377
  PrintManPageFlags(&short_flag_lines);
×
378
  PrintManPageFlags(&long_flag_lines);
×
379
}
×
380

381
/**
382
 * @brief Generate the short opts string for getopt. See `man 3 getopt` for the
383
 * format.
384
 */
385
string FlagRegistry::GetShortOptsString() const {
104✔
386
  string short_opts;
104✔
387
  ShortOpts::const_iterator iter = m_short_opts.begin();
104✔
388
  for (; iter != m_short_opts.end(); ++iter) {
549✔
389
    char short_opt = iter->second->short_opt();
445✔
390
    if (!short_opt)
445✔
391
      continue;
×
392

393
    short_opts.push_back(iter->second->short_opt());
445✔
394
    if (iter->second->has_arg()) {
445✔
395
      short_opts.push_back(':');
221✔
396
    }
397
  }
398
  return short_opts;
104✔
399
}
×
400

401
/**
402
 * @brief Allocate & populate the array of option structs for the call to
403
 * getopt_long. The caller is responsible for deleting the array.
404
 *
405
 * The flag_map is populated with the option identifier (int) to FlagInterface*
406
 * mappings. The ownership of the pointers to FlagInterfaces is not transferred
407
 * to the caller.
408
 */
409
struct option *FlagRegistry::GetLongOpts(FlagMap *flag_map) {
104✔
410
  unsigned int flag_count = m_long_opts.size() + 1;
104✔
411
  struct option *long_options = new struct option[flag_count];
104✔
412
  memset(long_options, 0, sizeof(struct option) * flag_count);
104✔
413

414
  LongOpts::iterator iter = m_long_opts.begin();
104✔
415
  struct option *opt = long_options;
104✔
416
  int flag_counter = 256;
104✔
417
  for (; iter != m_long_opts.end(); ++iter) {
1,194✔
418
    FlagInterface *flag = iter->second;
1,090✔
419
    opt->name = flag->name();
1,090✔
420
    opt->has_arg = flag->has_arg() ? required_argument : no_argument;
1,090✔
421
    opt->flag = 0;
1,090✔
422
    int flag_option = flag->short_opt() ? flag->short_opt() : flag_counter++;
1,090✔
423
    opt->val = flag_option;
1,090✔
424
    flag_map->insert(FlagMap::value_type(flag_option, flag));
1,090✔
425
    opt++;
1,090✔
426
  }
427
  return long_options;
104✔
428
}
429

430

431
/**
432
 * @brief Given a vector of flags lines, sort them and print to stdout.
433
 */
434
void FlagRegistry::PrintFlags(vector<string> *lines) {
×
435
  std::sort(lines->begin(), lines->end());
×
436
  vector<string>::const_iterator iter = lines->begin();
×
437
  for (; iter != lines->end(); ++iter)
×
438
    cout << *iter;
×
439
}
×
440

441
void FlagRegistry::PrintManPageFlags(vector<OptionPair> *lines) {
×
442
  std::sort(lines->begin(), lines->end());
×
443
  vector<OptionPair>::const_iterator iter = lines->begin();
×
444
  for (; iter != lines->end(); ++iter) {
×
445
    cout << ".IP \"" << iter->first << "\"" << endl;
×
446
    cout << iter->second << endl;
×
447
  }
448
}
×
449
/**
450
 * @endcond
451
 * End Hidden Symbols
452
 */
453
}  // namespace ola
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc