coan  6.0.1
A C/C++ Configuration Analyzer
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
options.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2004, 2006 Symbian Software Ltd. *
3  * All rights reserved. *
4  * Copyright (C) 2007-2013 Mike Kinghan, imk@burroingroingjoing.com *
5  * All rights reserved. *
6  * *
7  * Contributed originally by Mike Kinghan, imk@burroingroingjoing.com *
8  * *
9  * Redistribution and use in source and binary forms, with or without *
10  * modification, are permitted provided that the following conditions *
11  * are met: *
12  * *
13  * Redistributions of source code must retain the above copyright *
14  * notice, this list of conditions and the following disclaimer. *
15  * *
16  * Redistributions in binary form must reproduce the above copyright *
17  * notice, this list of conditions and the following disclaimer in the *
18  * documentation and/or other materials provided with the distribution. *
19  * *
20  * Neither the name of Symbian Software Ltd. nor the names of its *
21  * contributors may be used to endorse or promote products derived from *
22  * this software without specific prior written permission. *
23  * *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
31  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED *
32  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,*
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
34  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
35  * DAMAGE. *
36  * *
37  **************************************************************************/
38 
43 #include "options.h"
44 #include "symbol.h"
45 #include "get_options.h"
46 #include "contradiction.h"
47 #include "diagnostic.h"
48 #include "io.h"
49 #include "dataset.h"
50 #include "line_despatch.h"
51 #include "help.h"
52 #include "version.h"
53 #include <fstream>
54 #include <iostream>
55 #include <iterator>
56 
57 using namespace std;
58 
59 struct cmd_option * options::_command_ = nullptr;
63 string options::_memfile_;
64 bool options::_got_opts_ = false;
65 bool options::_replace_ = false;
66 bool options::_list_locate_ = false;
67 bool options::_list_only_once_ = false;
69 bool options::_list_only_active_ = false ;
78 bool options::_complement_ = false;
79 bool options::_eval_wip_ = false;
80 bool options::_expand_references_ = false;
82 bool options::_selected_symbols_ = false;
86 bool options::_line_directives_ = false;
87 bool options::_plaintext_ = false;
88 bool options::_recurse_ = false;
89 bool options::_keepgoing_ = false;
90 bool options::_implicit_ = false;
91 bool options::_no_transients_ = false;
93 bool options::_parsing_file_ = false;
94 vector<string> options::_argfile_argv_;
96 unsigned options::_max_expansion_ = 4096;
97 
98 struct option options::long_options [] = {
99  { "file", required_argument, nullptr, OPT_FILE },
100  { "replace",no_argument, nullptr, OPT_REPLACE },
101  { "backup",required_argument,nullptr,OPT_BACKUP},
102  { "define", required_argument, nullptr, OPT_DEF },
103  { "undef", required_argument, nullptr, OPT_UNDEF },
104  { "conflict", required_argument, nullptr, OPT_CONFLICT },
105  { "gag", required_argument, nullptr, OPT_GAG },
106  { "verbose", no_argument, nullptr, OPT_VERBOSE },
107  { "complement", no_argument, nullptr, OPT_COMPLEMENT },
108  { "eval-wip", no_argument, nullptr, OPT_EVALWIP },
109  { "discard", required_argument, nullptr, OPT_DISCARD },
110  { "line", no_argument, nullptr, OPT_LINE },
111  { "pod", no_argument, nullptr, OPT_POD },
112  { "recurse", no_argument, nullptr, OPT_RECURSE },
113  { "filter", required_argument, nullptr, OPT_FILTER },
114  { "keepgoing", no_argument, nullptr, OPT_KEEPGOING },
115  { "ifs", no_argument, nullptr, OPT_IFS },
116  { "defs", no_argument, nullptr, OPT_DEFS },
117  { "undefs", no_argument, nullptr, OPT_UNDEFS },
118  { "includes", no_argument, nullptr, OPT_INCLUDES },
119  { "lns", no_argument, nullptr, OPT_LNS },
120  { "locate", no_argument, nullptr, OPT_LOCATE },
121  { "once-only", no_argument, nullptr, OPT_ONCE },
122  { "once-per-file", no_argument, nullptr, OPT_ONCE_PER_FILE },
123  { "system", no_argument, nullptr, OPT_SYSTEM },
124  { "local", no_argument, nullptr, OPT_LOCAL },
125  { "active", no_argument, nullptr, OPT_ACTIVE },
126  { "inactive", no_argument, nullptr, OPT_INACTIVE },
127  { "expand", no_argument, nullptr, OPT_EXPAND },
128  { "implicit", no_argument, nullptr, OPT_IMPLICIT },
129  { "explain", no_argument, nullptr, OPT_EXPLAIN },
130  { "no-transients", no_argument, nullptr, OPT_NO_TRANSIENTS },
131  { "dir", required_argument, nullptr, OPT_DIR },
132  { "prefix", required_argument, nullptr, OPT_PREFIX },
133  { "select", required_argument, nullptr, OPT_SELECT },
134  { "max-expansion", required_argument, nullptr, OPT_EXPAND_MAX },
135  { 0, 0, 0, 0 }
136 };
137 
138 char options::opts[(sizeof(long_options)/sizeof(struct option)) * 3];
139 
140 
141 struct cmd_option options::commands [] = {
142  { "help", CMD_HELP },
143  { "-h", CMD_HELP },
144  { "--help", CMD_HELP },
145  { "version", CMD_VERSION },
146  { "-v", CMD_VERSION },
147  { "--version", CMD_VERSION },
148  { "source", CMD_SOURCE },
149  { "symbols", CMD_SYMBOLS },
150  { "includes", CMD_INCLUDES },
151  { "defs", CMD_DEFS },
152  { "pragmas", CMD_PRAGMAS },
153  { "errors", CMD_ERRORS },
154  { "lines", CMD_LINES },
155  { "directives", CMD_DIRECTIVES },
156  { "spin", CMD_SPIN },
157  { 0, 0 }
158 };
159 
160 int const options::source_cmd_exclusions[] = {
161  OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, OPT_LOCATE,
162  OPT_ONCE, OPT_SYSTEM, OPT_LOCAL, OPT_ACTIVE, OPT_INACTIVE,
163  OPT_EXPAND, OPT_PREFIX, OPT_EXPLAIN, OPT_SELECT, OPT_LNS,
164  OPT_ONCE_PER_FILE,0
165 };
166 
167 int const options::symbols_cmd_exclusions[] = {
168  OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_SYSTEM,
169  OPT_LOCAL, OPT_BACKUP, OPT_COMPLEMENT, OPT_DIR, OPT_PREFIX, 0
170 };
171 
172 int const options::includes_cmd_exclusions[] = {
173  OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP,
174  OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, OPT_COMPLEMENT,
175  OPT_EXPAND, OPT_DIR, OPT_PREFIX, OPT_EXPLAIN, OPT_SELECT,
176  OPT_LNS, 0
177 };
178 
180  OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP,
181  OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, OPT_COMPLEMENT,
182  OPT_EXPAND, OPT_DIR, OPT_PREFIX, OPT_EXPLAIN, OPT_SELECT,
183  OPT_LNS, 0
184 };
185 
186 int const options::defs_cmd_exclusions[] = {
187  OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP,
188  OPT_SYSTEM, OPT_LOCAL, OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES,
189  OPT_COMPLEMENT, OPT_EXPAND, OPT_DIR, OPT_PREFIX, OPT_EXPLAIN,
190  OPT_SELECT, OPT_LNS, 0
191 };
192 
193 int const options::pragmas_cmd_exclusions[] = {
194  OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP,
195  OPT_SYSTEM, OPT_LOCAL, OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES,
196  OPT_COMPLEMENT, OPT_EXPAND, OPT_DIR, OPT_PREFIX, OPT_EXPLAIN,
197  OPT_SELECT, OPT_LNS, 0
198 };
199 
200 int const options::errors_cmd_exclusions[] = {
201  OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP,
202  OPT_SYSTEM, OPT_LOCAL, OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES,
203  OPT_COMPLEMENT, OPT_EXPAND, OPT_DIR, OPT_PREFIX, OPT_EXPLAIN,
204  OPT_SELECT, OPT_LNS, 0
205 };
206 
207 int const options::lines_cmd_exclusions[] = {
208  OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP,
209  OPT_SYSTEM, OPT_LOCAL, OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES,
210  OPT_COMPLEMENT, OPT_EXPAND, OPT_DIR, OPT_PREFIX, OPT_EXPLAIN,
211  OPT_SELECT, OPT_LNS, 0
212 };
213 
214 int const options::spin_cmd_exclusions[] = {
215  OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, OPT_LOCATE,
216  OPT_ONCE, OPT_SYSTEM, OPT_LOCAL, OPT_ACTIVE, OPT_INACTIVE,
217  OPT_BACKUP, OPT_EXPAND, OPT_EXPLAIN, OPT_SELECT, OPT_LNS,
218  OPT_ONCE_PER_FILE, 0
219 };
220 
221 struct exclusion_list const options::cmd_exclusion_lists[] = {
222  /* Dummy 0th element*/
223  { 0, nullptr },
224  /* Exclusion list for the help command*/
225  { CMD_HELP, nullptr },
226  /* Exclusion list the version command*/
227  { CMD_VERSION, nullptr },
228  /* Exclusion list the code command*/
229  { CMD_SOURCE, source_cmd_exclusions},
230  /* Exclusion list for the symbols command*/
231  { CMD_SYMBOLS, symbols_cmd_exclusions },
232  /* Exclusion list for the includes command*/
233  { CMD_INCLUDES, includes_cmd_exclusions },
234  /* Exclusion list for the defs command*/
235  { CMD_DEFS, defs_cmd_exclusions },
236  /* Exclusion list for the pragmas command*/
237  { CMD_PRAGMAS, pragmas_cmd_exclusions },
238  /* Exclusion list for the lines command*/
239  { CMD_LINES, lines_cmd_exclusions },
240  /* Exclusion list for the pragmas command*/
241  { CMD_ERRORS, errors_cmd_exclusions },
242  /* Exclusion list for the directives command*/
243  { CMD_DIRECTIVES, directives_cmd_exclusions },
244  { 0, nullptr }
245 };
246 
248 {
249  return command_code(_command_->cmd_code);
250 }
251 
253 {
254  struct option * longopt = long_options;
255  char *opts_str = opts;
256  for ( ; longopt->name; ++longopt, ++opts_str) {
257  *opts_str = longopt->val;
258  switch(longopt->has_arg) {
259  case no_argument:
260  break;
261  case optional_argument:
262  ++opts_str;
263  *opts_str = ':';
264  /* Yes, fall through */
265  case required_argument:
266  ++opts_str;
267  *opts_str = ':';
268  break;
269  default:
270  assert(0);
271  }
272  }
273 }
274 
275 void options::config_diagnostics(string const & arg)
276 {
277  severity mask = severity::none;
278  if (_diagnostic_filter_ < 0 && arg != "verbose") {
280  warn << "Can't mix --verbose with --gag.'--gag " << arg << " ignored";
281  cerr << warn.text() << '\n';
282  return;
283  }
284  if (arg == "progress") {
285  mask = severity::progress;
286  } else if (arg == "info") {
287  mask = severity::info;
288  } else if (arg == "warning") {
289  mask = severity::warning;
290  } else if (arg == "error") {
291  mask = severity::error;
292  } else if (arg == "abort") {
293  mask = severity::abend;
294  } else if (arg == "summary") {
295  mask = severity::summary;
296  } else if (arg == "verbose") {
297  if (_diagnostic_filter_ > 0) {
299  "Can't mix --verbose with --gag. '--verbose' ignored" << emit();
300  return;
301  } else if (_diagnostic_filter_ < 0) {
302  info_duplicate_mask() << "'--verbose' already seen" << emit();
303  return;
304  }
305  _diagnostic_filter_ = -1;
306  return;
307  } else {
308  error_usage() << "Invalid argument for --gag: \""
309  << arg << '\"' << emit();
310  }
311  if (int(mask) & _diagnostic_filter_) {
312  info_duplicate_mask() << "'--gag " << arg << "' already seen" << emit();
313  }
314  _diagnostic_filter_ |= int(mask);
315  if (mask == severity::info) {
316  config_diagnostics("progress");
317  } else if (mask == severity::warning) {
318  config_diagnostics("info");
319  } else if (mask == severity::error) {
320  config_diagnostics("warning");
321  } else if (mask == severity::abend) {
322  config_diagnostics("error");
323  }
324 }
325 
327 {
328  if (!_diagnostic_filter_) {
329  /* Default diagnostic masking to no progress
330  messages, no infos, no summaries*/
331  config_diagnostics("info");
332  config_diagnostics("summary");
333  } else if (_diagnostic_filter_ == -1) {
334  /* --verbose was temporarily set as -1 to block later
335  --gag options. Can now reset as 0*/
336  _diagnostic_filter_ = 0;
337  }
338 }
339 
340 void options::error_invalid_opt(cmd_option const *cmd, int bad_opt)
341 {
342  char const *cmdname = cmd->name;
343  char const *optname = get_long_opt_name(long_options,bad_opt);
344  assert(optname);
345  error_usage() << '\"' << optname << '\"'
346  << " is an invalid or ambiguous option for command \""
347  << cmdname << '\"' << emit();
348 }
349 
350 void options::add_files(string const & path)
351 {
353  if (obj_type == fs::OBJ_NONE) {
354  abend_no_file() <<
355  "No such file or directory as \"" << path << '\"' << emit();
356  } else if (fs::is_file(obj_type)) {
357  dataset::add(path);
358  } else if (fs::is_dir(obj_type)) {
359  if (!_recurse_ && !io::spin()) {
361  "--recurse not specified. Ignoring directory \"" << path <<
362  '\"' << emit();
363  } else {
364  if (io::spin()) {
365  static path_t spin_dir_path(io::spin_dir());
366  path_t new_path(path);
367  path_t prefix = path_t::common_prefix(new_path,spin_dir_path);
368  if (prefix == spin_dir_path || prefix == new_path) {
369  abend_invalid_spin_dir() << "The spin directory "
370  "cannot include or be included by or identical with "
371  "any input directory" << emit();
372  }
373  }
374  dataset::add(path);
375  }
376  } else if (fs::is_slink(obj_type)) {
377  warning_broken_symlink() << "Broken symbolic link \"" << path <<
378  "\" ignored" << emit();
379  }
380 }
381 
382 void options::parse_command_args(int argc, char *argv[])
383 {
384  int options = argc;
385  int opt, save_ind, long_index;
386  if (!opts[0]) {
387  make_opts_list();
388  }
389  for ( optind = 0;
390  (opt = getopt_long(argc,argv,opts,long_options,&long_index))
391  != -1; ) {
392  if (!opts_are_compatible(_command_->cmd_code,
393  opt,cmd_exclusion_lists,true)) {
394  error_invalid_opt(_command_,opt);
395  }
396  switch (opt) {
397  case OPT_FILE: /* Read further options from file*/
398  save_ind = optind;
399  /* Remember where we have parsed up to*/
400  _parsing_file_ = true;
401  parse_file(optarg); /* Parse file*/
402  _parsing_file_ = false;
403  optind = save_ind; /* Restore position*/
404  break;
405  case OPT_CONFLICT: { /* Policy for contradictions*/
407  string option_arg(optarg);
408  if (option_arg.length() > 1) {
409  if (option_arg == "delete") {
410  conflict_policy = CONTRADICTION_DELETE;
411  } else if (option_arg == "comment") {
412  conflict_policy = CONTRADICTION_COMMENT;
413  } else if (option_arg == "error") {
414  conflict_policy = CONTRADICTION_ERROR;
415  } else {
416  error_usage() << "Invalid argument for --conflict: \""
417  << option_arg << '\"' << emit();
418  }
419  } else {
420  switch(option_arg[0]) {
421  case 'd':
422  conflict_policy = CONTRADICTION_DELETE;
423  break;
424  case 'c':
425  conflict_policy = CONTRADICTION_COMMENT;
426  break;
427  case 'e':
428  conflict_policy = CONTRADICTION_ERROR;
429  break;
430  default:
431  error_usage() << "Invalid argument for -x: \""
432  << option_arg[0] << '\"' << emit();
433  }
434  }
436  }
437  break;
438  case OPT_GAG: {
439  string option_arg(optarg);
440  if (option_arg.length() == 1) {
441  switch(option_arg[0]) {
442  case 'p':
443  option_arg = "progress";
444  break;
445  case 'i':
446  option_arg = "info";
447  break;
448  case 'w':
449  option_arg = "warning";
450  break;
451  case 'e':
452  option_arg = "error";
453  break;
454  case 'a':
455  option_arg = "abend";
456  break;
457  case 's':
458  option_arg = "summary";
459  break;
460  default:
461  assert(false);
462  }
463  }
464  config_diagnostics(option_arg);
465  }
466  break;
467  case OPT_VERBOSE:
468  config_diagnostics("verbose");
469  break;
470  case OPT_DEF: { /* define a symbol*/
471  string s(optarg);
472  chewer<string> chew(false,s);
473  symbol::locator sloc(chew);
474  sloc->digest_global_define(chew);
475  }
476  break;
477  case OPT_UNDEF: { /* undef a symbol*/
478  string s(optarg);
479  chewer<string> chew(false,s);
480  symbol::locator sloc(chew);
481  sloc->digest_global_undef(chew);
482  }
483  break;
484  case OPT_COMPLEMENT: /* treat -D as -U and vice versa*/
485  _complement_ = true;
486  break;
487  case OPT_REPLACE:
488  _replace_ = true;
489  break;
490  case OPT_BACKUP:
491  _backup_suffix_ = optarg;
492  break;
493  case OPT_EVALWIP:
494  _eval_wip_ = true;
495  break;
496  case OPT_DISCARD: { /* policy for discarding lines on output*/
497  string option_arg(optarg);
498  if (option_arg.length() > 1) {
499  if (option_arg == "drop") {
500  _discard_policy_ = DISCARD_DROP;
501  } else if (option_arg == "blank") {
502  _discard_policy_ = DISCARD_BLANK;
503  } else if (option_arg == "comment") {
504  _discard_policy_ = DISCARD_COMMENT;
505  } else {
506  error_usage() << "Invalid argument for --discard: \""
507  << optarg << '\"' << emit();
508  }
509  } else {
510  switch(option_arg[0]) {
511  case 'd':
512  _discard_policy_ = DISCARD_DROP;
513  break;
514  case 'b':
515  _discard_policy_ = DISCARD_BLANK;
516  break;
517  case 'c':
518  _discard_policy_ = DISCARD_COMMENT;
519  break;
520  default:
521  error_usage() << "Invalid argument for -k: \""
522  << *optarg << '\"' << emit();
523  }
524  }
525  }
526  break;
527  case OPT_LINE:
528  _line_directives_ = true;
529  break;
530  case OPT_LOCATE:
531  _list_locate_ = true;
532  break;
533  case OPT_ACTIVE:
534  _list_only_active_ = true;
535  break;
536  case OPT_INACTIVE:
537  _list_only_inactive_ = true;
538  break;
539  case OPT_EXPAND:
540  _expand_references_ = true;
541  break;
542  case OPT_ONCE:
543  _list_only_once_ = true;
544  break;
545  case OPT_ONCE_PER_FILE:
546  _list_once_per_file_ = true;
547  break;
548  case OPT_IFS:
549  _list_symbols_in_ifs_ = true;
550  break;
551  case OPT_DEFS:
552  _list_symbols_in_defs_ = true;
553  break;
554  case OPT_UNDEFS:
555  _list_symbols_in_undefs_ = true;
556  break;
557  case OPT_INCLUDES:
558  _list_symbols_in_includes_ = true;
559  break;
560  case OPT_LNS:
561  _list_symbols_in_lines_ = true;
562  break;
563  case OPT_SYSTEM:
564  _list_system_includes_ = true;
565  break;
566  case OPT_LOCAL:
567  _list_local_includes_ = true;
568  break;
569  case OPT_POD: /* don't parse quotes or comments*/
570  _plaintext_ = true;
571  break;
572  case OPT_RECURSE: /* recurse into directories*/
573  _recurse_ = true;
574  if (_command_->cmd_code == CMD_SOURCE ||
575  _command_->cmd_code == CMD_SPIN) {
576  _replace_ = true;
577  }
578  break;
579  case OPT_FILTER: /* Filter input by file extensions*/
581  break;
582  case OPT_KEEPGOING: /* Continue to process subsequent in
583  put files after errors*/
584  _keepgoing_ = true;
585  break;
586  case OPT_IMPLICIT: /* Implicitly --undef any unconfigured symbol */
587  _implicit_ = true;
588  break;
589  case OPT_NO_TRANSIENTS: /* Disallow transient symbol configurations
590  for in-source #defines and #undefs */
591  _no_transients_ = true;
592  warning_no_transients_used() << "The --no-transients option "
593  << "prohibits coan from taking account of the effects of "
594  << "in-source #define and #undef directives. "
595  << "Use at your own risk." << emit();
596  break;
597  case OPT_DIR: /* Specify the spin directory */
599  break;
600  case OPT_PREFIX:
601  /* Specify the path prefix assumed to match the spin directory */
603  break;
604  case OPT_EXPLAIN:
605  /* Specify whether the progressive expansion of symbol
606  references is to be reported. Implies --expand
607  */
608  _expand_references_ = _explain_references_ = true;
609  break;
610  case OPT_SELECT:
611  /* Specify a list of symbols to be reported.
612  */
614  _selected_symbols_ = true;
615  break;
616  case OPT_EXPAND_MAX: {
617  /* Specify the limit size for reported macro expansions
618  */
619  char *endp;
620  _max_expansion_ = strtoul(optarg,&endp,10);
621  if (*endp && (*endp == 'K' || *endp == 'k')) {
622  _max_expansion_ *= 1024;
623  ++endp;
624  }
625  if (*endp) {
626  error_usage() << "Invalid argument for --max-expansion: \""
627  << optarg << '\"' << emit();
628  }
629  }
630  break;
631  default:
632  error_usage() <<
633  "Invalid or ambiguous option: \"" << argv[optind - 1] << '\"'
634  << emit();
635  }
636  }
637  if (!_parsing_file_) {
638  _got_opts_ = true;
639  finalise_diagnostics();
640  if (!progress_gagged()) {
642  msg << "Args: ";
643  for (int i = 0; i < options; ++i) {
644  msg << argv[i] << ' ';
645  }
646  msg << emit();
647  }
648  if (_command_->cmd_code == CMD_SOURCE ||
649  _command_->cmd_code == CMD_SPIN) {
650  if (! options::implicit() &&
652  warning_no_syms() <<
653  "You have not --define-ed or --undef-ed any symbols. "
654  "Only in-source #define/#undef directives will have "
655  "any effects" << emit();
656  }
657  }
658  }
659  if (argc) {
660  progress_building_tree() << "Building input tree" << emit();
661  }
662  argc -= optind;
663  argv += optind;
664  for ( ; argc; --argc,++argv,++_cmd_line_files_) {
665  add_files(*argv);
666  }
667 }
668 
669 void options::parse_file(string const & argsfile)
670 {
671  std::vector<char *> arg_addrs;
672  if (_argfile_argv_.size()) {
673  error_multiple_argfiles() << "--file can only be used once" << emit();
674  }
675  ifstream in(argsfile.c_str());
676  if (!in.good()) {
677  abend_cant_open_input() << "Can't open " <<
678  argsfile << " for reading" << emit();
679 
680  }
681  _argfile_argv_.push_back(_prog_name_);
682  copy(istream_iterator<string>(in),
683  istream_iterator<string>(),
684  back_inserter<vector<string> >(_argfile_argv_));
685  in.close();
686  vector<string>::iterator iter = _argfile_argv_.begin();
687  vector<string>::iterator end = _argfile_argv_.end();
688  for( ; iter != end; ++iter ) {
689  arg_addrs.push_back(const_cast<char *>(iter->c_str()));
690  }
691  parse_command_args(int(arg_addrs.size()),&arg_addrs[0]);
692 }
693 
694 void options::parse_executable(char **argv)
695 {
696  _exec_path_ = string(*argv);
697  size_t last_slash = _exec_path_.find_last_of(PATH_DELIM);
698  if (last_slash == string::npos) {
699  _prog_name_ = _exec_path_;
700  } else {
701  _prog_name_ = _exec_path_.substr(last_slash + 1);
702  }
703 }
704 
705 void options::parse(int argc, char *argv[])
706 {
708  cmd_option const *cmd = get_command_option(argc,argv,commands);
709  if (cmd) {
710  switch(cmd->cmd_code) {
711  case CMD_HELP:
712  help();
713  break;
714  case CMD_VERSION:
715  version();
716  break;
717  default:
718  _command_ = const_cast<cmd_option *>(cmd);
719  argc -= 1;
720  argv += 1;
721  parse_command_args(argc,argv);
722  }
723  } else if (argc < 2) {
724  error_usage() << "No coan command given" << emit();
725  } else {
726  error_usage() << '\"' << argv[1]
727  << "\" is not a coan command" << emit();
728  }
729 }
730 
732 {
733  int cmd_code = _command_->cmd_code;
734  bool input_is_stdin = false;
735 
736  if (_list_only_active_ && _list_only_inactive_) {
737  error_usage() << "--active is inconsistent with --inactive" << emit();
738  }
739  if (_list_only_once_ && _list_once_per_file_) {
740  error_usage()
741  << "--once-only is inconsistent with --once-per-file" << emit();
742  }
743  if (_line_directives_ && _discard_policy_ != DISCARD_DROP) {
744  error_usage() << "--line is inconsistent with --discard blank|comment"
745  << emit();
746  }
747  if (_cmd_line_files_ == 0) {
748  /* No input files on command line*/
749  if (!_replace_) {
750  /* Without --replace, stdin is the input file*/
751  input_is_stdin = true;
752  } else {
753  /* With --replace, stdin supplies input filenames*/
754  string infile(io::read_filename());
755  for ( ; infile.length(); infile = io::read_filename()) {
756  (void)add_files(infile);
757  }
758  }
759  }
760  if (dataset::files() == 0 && !input_is_stdin) {
762  "Nothing to do. No input files selected." << emit();
763  }
764  if (cmd_code == CMD_SOURCE && !input_is_stdin &&
765  dataset::files() > 1 && !_replace_) {
767  "The \"source\" command needs --replace to process multiple files"
768  << emit();
769  }
770  if (cmd_code == CMD_SYMBOLS) {
771  if (!_list_symbols_in_ifs_ &&
772  !_list_symbols_in_defs_ &&
773  !_list_symbols_in_undefs_ &&
774  !_list_symbols_in_includes_) {
775  /* No restriction on listed symbols implies list all*/
776  _list_symbols_in_ifs_ = _list_symbols_in_defs_ =
777  _list_symbols_in_undefs_ = _list_symbols_in_includes_ = true;
778  }
779  }
780  if (cmd_code == CMD_INCLUDES) {
781  if (!_list_system_includes_ && !_list_local_includes_) {
782  /* No restriction on listed #includes implies list all*/
783  _list_system_includes_ = _list_local_includes_ = true;
784  }
785  }
787  dataset::files() << " files to process" << emit();
788 
789 }
790 
792 {
793  return (_diagnostic_filter_ & int(severity::progress)) != 0;
794 }
795 
796 bool options::diagnostic_gagged(unsigned reason)
797 {
798  return options::_got_opts_ && reason &&
800  (((reason >> 8) & options::_diagnostic_filter_) != 0);
801 }
802 
803 /* EOF*/
progress_msg< 4 > progress_file_tracker
Report total input files found.
Definition: diagnostic.h:580
The directives command.
Definition: options.h:82
The option cannot have an argument.
Definition: get_options.h:87
static bool implicit()
Do we implicitly --undef all unconfigured symbols?
Definition: options.h:195
static bool _list_only_once_
Do we report only the first occurrence of listed items?
Definition: options.h:434
The version command.
Definition: options.h:74
error_msg< 7 > error_one_file_only
Definition: diagnostic.h:736
template struct warning_msg<Id> generically encapsulates a warning diagnostic.
Definition: diagnostic.h:473
static int const includes_cmd_exclusions[]
Excluded options for the includes command.
Definition: options.h:321
A fatal error disgnostic.
static int const errors_cmd_exclusions[]
Excluded options for the errors command.
Definition: options.h:333
abend_msg< 14 > abend_invalid_spin_dir
Report that a spin directory includes, is included by or is same as an input directory.
Definition: diagnostic.h:814
An informational diagnostic.
int val
Value to be returned or stored by getopt_long().
Definition: get_options.h:82
static std::string _backup_suffix_
Suffix for backup files.
Definition: options.h:426
static void add(std::string const &path)
Add files to the dataset.
Definition: dataset.cpp:144
The symbols command.
Definition: options.h:76
The symbol is globally configured by a commandline option.
static bool _list_only_inactive_
Do list items only from dropped lines?
Definition: options.h:440
Blank discarded lines.
Definition: options.h:52
info_msg< 1 > info_duplicate_mask
Report a duplicate diagnostic selection option.
Definition: diagnostic.h:584
static bool _list_local_includes_
Do we list local #include directives?
Definition: options.h:454
discard_policy
Symbolic constants denoting policies for discarding lines.
Definition: options.h:50
The line command.
Definition: options.h:81
Manages coan's commandline arguments.
Definition: options.cpp:98
void version()
Write version information about the program on cout.
static bool _list_only_active_
Do we list items only from kept lines?
Definition: options.h:438
struct symbol::locator encapsulates a symbol table entry.
Definition: symbol.h:79
static void parse(int argc, char *argv[])
Parse the commandline.
Definition: options.cpp:705
static bool _selected_symbols_
Is symbol reporting restricted to a selected set?
Definition: options.h:482
A warning diagnostic.
static void error_invalid_opt(struct cmd_option const *cmd, int bad_opt)
Raise a usage error when an option is invalid for the active command.
Definition: options.cpp:340
static int const lines_cmd_exclusions[]
Excluded options for the lines command.
Definition: options.h:336
error_msg< 9 > error_usage
Report that the commandline is syntactically invalid.
Definition: diagnostic.h:740
unsigned obj_type_t
Abstract type of filesystem object types.
Definition: filesys.h:61
static int const source_cmd_exclusions[]
Excluded options for the source command.
Definition: options.h:315
warning_msg< 13 > warning_verbose_only
Report the --verbose option is mixed with the --gag option.
Definition: diagnostic.h:673
bool is_file(obj_type_t type)
Say whether an object type is a file.
Definition: filesys.h:67
bool is_dir(obj_type_t type)
Say whether an object type is a directory.
Definition: filesys.h:76
static int _cmd_line_files_
The number of input files/dirs specified on the commandline.
Definition: options.h:493
static unsigned _max_expansion_
Limit size for reported macro expansions.
Definition: options.h:484
The help command.
Definition: options.h:73
static command_code get_command()
Get the operative coan command code.
Definition: options.cpp:247
const char * get_long_opt_name(struct option const *longopts, int opt)
Look up the long name of the an option in an array of struct option.
static bool _recurse_
Recurse into directories?
Definition: options.h:470
The defs command.
Definition: options.h:78
static std::string _memfile_
Read whole ARGFILE into this storage.
Definition: options.h:491
static int const spin_cmd_exclusions[]
Excluded options for the spin command.
Definition: options.h:339
Comment out a contradicted directive.
Definition: options.h:66
static int const pragmas_cmd_exclusions[]
Excluded options for the pragmas command.
Definition: options.h:330
static int const symbols_cmd_exclusions[]
Excluded options for the symbols command.
Definition: options.h:318
static bool _got_opts_
Have we got all commandline options?
Definition: options.h:428
int optind
Index of option parsed by getopt_long()
Definition: get_options.cpp:47
int getopt_long(int argc, char *argv[], const char *optstr, const struct option *longopts, int *longind)
Parse commandline options.
Definition: get_options.cpp:97
static void parse_file(std::string const &argsfile)
Parse commandline options from a file.
Definition: options.cpp:669
static size_t count()
Get the number of symbols in the symbol table.
Definition: symbol.h:386
static void set_selection(char const *optarg)
abend_msg< 7 > abend_no_file
Report can't identify file or directory.
Definition: diagnostic.h:798
static void parse_command_args(int argc, char *argv[])
Parse the options to the active coan command.
Definition: options.cpp:382
const char * name
The name of the option.
Definition: get_options.h:96
A progress diagnostic.
static void finish()
Analyse the class global state after parsing the commandline.
Definition: options.cpp:731
static bool _implicit_
Do we implicitly --undef all unconfigured symbols?
Definition: options.h:474
Info structure for an option for getopt_long().
Definition: get_options.h:57
static std::string const & spin_dir()
Get the name of operative spin directory.
Definition: io.h:135
bool opts_are_compatible(int opt_excluder, int opt_excluded, struct exclusion_list const *exclusions, bool indexed)
Say whether options are compatible with respect to specified incompatibilities.
Definition: get_options.cpp:67
severity
Enumerated constants representing the severities of diagnostics.
Definition: diagnostic.h:51
The errors command.
Definition: options.h:80
static std::string read_filename()
Read the name of a source file from stdin.
Definition: io.cpp:78
static void finalise_diagnostics()
Configure the final state of diagnostic output filtering.
Definition: options.cpp:326
static bool _expand_references_
Do we report the expansions of symbol references?
Definition: options.h:462
static void set_spin_prefix(char const *optarg)
Set a path prefix (of input files) that will be assumed to match the name of the spin directory...
Definition: io.cpp:232
static bool _no_transients_
Definition: options.h:478
#define PATH_DELIM
defined(_WIN32) && defined(_WIN64)
Definition: platform.h:78
template struct progress_msg<Id>` generically encapsulates a progress diagnostic. ...
Definition: diagnostic.h:435
static char opts[]
Array in which we will assemble the shortopts arguments for getopts_long()
Definition: options.h:309
static bool _eval_wip_
Do we evaluate constants in truth-functional contexts or treat them as unknowns?
Definition: options.h:460
const char * name
The name of the option.
Definition: get_options.h:59
Delete a contradicted directive.
Definition: options.h:64
static void set_filter(std::string extensions)
Specify the filtering of files in the dataset.
Definition: dataset.h:113
The pragmas command.
Definition: options.h:79
int cmd_code
Value to be returned if the command is matched.
Definition: get_options.h:98
Drop discarded lines.
Definition: options.h:51
static void top()
Reinitialize the class static state.
The option must have an argument.
Definition: get_options.h:88
static bool _keepgoing_
Continue to process input files after errors.
Definition: options.h:472
The tag class is inserted in a diagnostic_base to tell it to emit itself.
Definition: diagnostic.h:77
abend_msg< 2 > abend_cant_open_input
Report cannot open an input file.
Definition: diagnostic.h:786
static unsigned files()
Get the number of files in the dataset.
Definition: dataset.h:135
contradiction_policy
Symbolic constants denoting policies for handling contradictions.
Definition: options.h:62
static void config_diagnostics(std::string const &arg)
Configure diagnostic output.
Definition: options.cpp:275
warning_msg< 15 > warning_dir_ignored
Report directory name ignored on input when --recurse not not specified.
Definition: diagnostic.h:679
static path common_prefix(path const &lhs, path const &rhs)
Get the common initial prefix of two paths.
Definition: path.h:356
static bool _list_system_includes_
Do we list system #include directives?
Definition: options.h:452
static bool progress_gagged()
Say whether progress messages are suppressed.
Definition: options.cpp:791
static bool _list_locate_
Do we report file and line numbers for listed items?
Definition: options.h:432
static int const defs_cmd_exclusions[]
Excluded options for the defs command.
Definition: options.h:327
static bool _explain_references_
Do we report the derivation of symbol resolutions?
Definition: options.h:480
Comment discarded lines.
Definition: options.h:53
static std::vector< std::string > _argfile_argv_
Array of options read from --file ARGFILE
Definition: options.h:489
static discard_policy _discard_policy_
Policy for discarding lines.
Definition: options.h:464
An error diagnostic.
The includes command.
Definition: options.h:77
`template struct chewer<CharSeq> is a cursor-like type that is associated with a character-sequence t...
Definition: chew.h:248
error_msg< 6 > error_nothing_to_do
Report that the commandline does not specify anything to do.
Definition: diagnostic.h:732
std::string text() const
Get the text of the diagnostic.
Definition: diagnostic.h:153
Info structure for a command option for get_command()
Definition: get_options.h:94
A summary diagnostic.
void digest_global_define(chewer< std::string > &chew)
Analyse and handle a -D option for this symbol.
warning_msg< 30 > warning_no_transients_used
Report that the unsafe --no-transients option is used.
Definition: diagnostic.h:711
static bool spin()
Say whether there is any spin directory.
Definition: io.h:140
static bool diagnostic_gagged(unsigned reason)
Say whether a diagnostic reason code is gagged.
Definition: options.cpp:796
static std::string _exec_path_
argv[0]
Definition: options.h:422
static bool _list_symbols_in_lines_
Do we list symbols in #line directives?
Definition: options.h:450
static void set_contradiction_policy(contradiction_policy p)
Set the operative contradiction policy.
Definition: contradiction.h:76
bool is_slink(obj_type_t type)
Say whether an object type is a symbolic link.
Definition: filesys.h:85
Encapsulates a filesystem path.
Definition: path.h:59
static bool _plaintext_
Are we to omit parsing for comments?
Definition: options.h:468
static bool _complement_
Are to output lines instead of dropping tem and vice versa?
Definition: options.h:456
Replace a contradicted directive with an #error
Definition: options.h:68
void help()
Write brief command usage information to cout.
Definition: help.cpp:50
the spin command
Definition: options.h:83
command_code
Sequential symbolic constants for coan commands.
Definition: options.h:72
static void set_spin_dir(char const *optarg)
Set the directory in which to output a spin.
Definition: io.cpp:227
static void parse_executable(char **argv)
Parse the full and short names of the executable.
Definition: options.cpp:694
cmd_option const * get_command_option(int argc, char *argv[], cmd_option const *commands)
Look for a command option at the start of commandline arguments.
Definition: get_options.cpp:52
static bool _list_symbols_in_ifs_
Do we list symbols in `#if/else/endif directives?
Definition: options.h:442
error_msg< 11 > error_multiple_argfiles
Report that the --file option occurs more than once.
Definition: diagnostic.h:744
static bool _list_symbols_in_undefs_
Do we list symbols in #undef directives?
Definition: options.h:446
obj_type_t obj_type(std::string const &name)
Get the type of the object putatively designated by a filename.
static void add_files(std::string const &path)
Add files to the input dataset.
Definition: options.cpp:350
int has_arg
Can the option take an argument? One of:
Definition: get_options.h:66
static int _diagnostic_filter_
Bitmask of diagnostic filters.
Definition: options.h:486
static void make_opts_list()
Assemble the shortopts arguments for getopts_long().
Definition: options.cpp:252
static bool _list_symbols_in_defs_
Do we list symbols in #define directives?
Definition: options.h:444
static struct cmd_option * _command_
Pointer to the details of the operative coan command.
Definition: options.h:420
Structure representing a set of options that are excluded by another option.
Definition: get_options.h:104
static bool _parsing_file_
Are we parsing an argsfile ?
Definition: options.h:496
char * optarg
Argument to an option parsed by getopt_long()
Definition: get_options.cpp:49
warning_msg< 29 > warning_broken_symlink
Report that input file is a broken symbolic link.
Definition: diagnostic.h:709
warning_msg< 28 > warning_no_syms
Report that the commandline does not specify any --define or --undef
Definition: diagnostic.h:707
static bool _list_once_per_file_
Do we report only the first occurrence per file of listed items?
Definition: options.h:436
static bool _line_directives_
Do we output #line directives?
Definition: options.h:466
static std::string _prog_name_
Filename element of exec_path
Definition: options.h:424
static int const directives_cmd_exclusions[]
Excluded options for the directives command.
Definition: options.h:324
void digest_global_undef(chewer< std::string > &chew)
Analyse and handle a -U option for this symbol.
progress_msg< 2 > progress_building_tree
Peport building the input tree.
Definition: diagnostic.h:576
No such object.
Definition: filesys.h:51
The option may or may not have an argument.
Definition: get_options.h:89
No severity.
The source command.
Definition: options.h:75
static bool _replace_
Do we replace input files with output files?
Definition: options.h:430
static bool _list_symbols_in_includes_
Do we list symbols in #include directives?
Definition: options.h:448