libutil++  1.9.3
 All Classes Functions Variables
CommandLine.cpp
1 /*
2 ** libutil++
3 ** $Id: CommandLine.cpp 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: CommandLine.cpp 1653 2016-02-28 19:54:59Z sella $";
10 
11 #include "CommandLine.h"
12 #include "CommandLineOption.h"
13 
14 #include <unistd.h>
15 #include <getopt.h>
16 #include <stdio.h>
17 
18 #include <exception>
19 #include <string>
20 #include <vector>
21 #include <list>
22 #include <map>
23 
24 using namespace sella::util;
25 
26 CommandLine::CommandLine(int argc, char **argv) throw () :
27  argc(argc),
28  argv(argv),
29 
30  option(),
31  argument(),
32 
33  width(0)
34 { }
35 
36 CommandLine::CommandLine(const CommandLine &copy) throw () :
37  argc(copy.argc),
38  argv(copy.argv),
39 
40  option(copy.option),
41  argument(copy.argument),
42 
43  width(copy.width)
44 { }
45 
46 CommandLine::~CommandLine() throw () {
47  this->option.clear();
48  this->argument.clear();
49 }
50 
51 CommandLine &sella::util::CommandLine::operator=(const CommandLine &other) throw () {
52  if (this != &other) {
53  this->argc = other.argc;
54  this->argv = other.argv;
55 
56  this->option = other.option;
57  this->argument = other.argument;
58 
59  this->width = other.width;
60  }
61 
62  return *this;
63 }
64 
65 void CommandLine::add(char opt, const std::string &option, const std::string &usage, const std::string &label, const std::string &value) throw () {
66  this->add(CommandLineOption(opt, option, usage, label, value));
67 }
68 
69 void CommandLine::add(char opt, const std::string &option, const std::string &usage, const std::string &label, long value, long min, long max) throw () {
70  char buf[31];
71  std::string v;
72 
73  if (min != MINLONG &&value < min) {
74  value = min;
75  } else if (max != MINLONG &&value > max) {
76  value = max;
77  }
78 
79  snprintf(buf, sizeof(buf), "%lu", value);
80  v = buf;
81 
82  this->add(CommandLineOption(opt, option, usage, label, v));
83 }
84 
85 void CommandLine::add(const CommandLineOption &option) throw () {
86  if (this->width < option.getTags().size()) {
87  this->width = option.getTags().size();
88  }
89 
90  this->option.push_back(option);
91 }
92 
93 void CommandLine::add(const std::string &argument, const std::string &usage) throw () {
94  if (this->width < (argument.size() + 4)) {
95  this->width = argument.size() + 4;
96  }
97 
98  this->argument.push_back(std::pair<std::string, std::string>(argument, usage));
99 }
100 
101 void CommandLine::usage(FILE *stream, int result) const throw () {
102  std::string left;
103  left.resize(this->width, ' ');
104 
105  /* Print the usage summary header. */
106  if (this->option.size() > 0) {
107  fprintf(stream, "\nUSAGE: %s [OPTIONS]", this->argv[0]);
108  } else {
109  fprintf(stream, "\nUSAGE: %s", this->argv[0]);
110  }
111 
112  for (auto iter = this->argument.cbegin(); iter != this->argument.cend(); iter++) {
113  fprintf(stream, " %s", iter->first.c_str());
114  }
115 
116  /* Print the argument usage detail. */
117  if (this->argument.size() > 0) {
118  fprintf(stream, "\n ARGUMENTS\n");
119  }
120 
121  for (auto iter = this->argument.cbegin(); iter != this->argument.cend(); iter++) {
122  std::string argument(iter->first);
123  argument.insert(0, 4, ' ');
124  argument.resize(this->width, ' ');
125 
126  fprintf(stream, "%s %s\n", argument.c_str(), iter->second.c_str());
127  }
128 
129  /* Print the option usage detail. */
130  if (this->option.size() > 0) {
131  fprintf(stream, "\n OPTIONS\n");
132  }
133 
134  for (auto iter = this->option.cbegin(); iter != this->option.cend(); iter++) {
135  std::string tags(iter->getTags());
136 
137  if (tags.size() > 0) {
138  tags.resize(this->width, ' ');
139 
140 #if 0
141  fprintf(stream, "%s %s\n", tags.c_str(), iter->getUsage().c_str());
142 
143  if (iter->getValue().size() > 0) {
144  fprintf(stream, "%s [DEFAULT: %s]\n", left.c_str(), iter->getValue().c_str());
145  }
146 #else
147  if (iter->getValue().size() > 0) {
148  fprintf(stream, "%s %s (default: %s)\n", tags.c_str(), iter->getUsage().c_str(), iter->getValue().c_str());
149  } else {
150  fprintf(stream, "%s %s\n", tags.c_str(), iter->getUsage().c_str());
151  }
152 #endif
153  } else {
154  fprintf(stream, "\n");
155  }
156  }
157 
158  fprintf(stream, "\n");
159 
160  /* Terminate execution. */
161  _exit(result);
162 }
163 
164 std::map<std::string, std::string> CommandLine::parse(FILE *stream) const throw () {
165  std::map<std::string, std::string> result;
166  std::map<char, std::string> lookup;
167 
168  std::vector<struct option> long_option;
169  std::string option;
170 
171  int index;
172  int c;
173 
174  /* Build the parsing structures. */
175  for (auto iter = this->option.cbegin(); iter != this->option.cend(); iter++) {
176  if (iter->getTags().size() > 0) {
177  long_option.push_back(this->build(iter->getOpt(), iter->getOption(), iter->getArgumented()));
178  option.append(this->tag(iter->getOpt(), iter->getArgumented()));
179 
180  if (iter->getValue().size() > 0) {
181  result[iter->getOption()] = iter->getValue();
182  }
183 
184  lookup[iter->getOpt()] = iter->getOption();
185  }
186  }
187 
188  long_option.push_back(this->build(0, std::string(), 0));
189 
190  /* Parse the command line options. */
191  while ((c = getopt_long(this->argc, this->argv, option.c_str(), &(long_option[0]), &index)) >= 0) {
192  if (lookup.find(c) != lookup.end()) {
193  if (optarg != 0) {
194  result[lookup[c]] = std::string(optarg);
195  } else {
196  result[lookup[c]] = std::string();
197  }
198  } else {
199  this->usage(stream, -1);
200  }
201  }
202 
203  /* Parse the command line aguments. */
204  if (argc != (optind + (int)(this->argument.size()))) {
205  this->usage(stream, -2);
206  } else {
207  for (auto iter = this->argument.cbegin(); iter != this->argument.cend(); iter++) {
208  result[iter->first] = argv[optind++];
209  }
210  }
211 
212  return std::map<std::string, std::string>(result);
213 }
214 
215 struct option CommandLine::build(char tag, const std::string &name, bool argument) const throw () {
216  struct option option = { (name.size() > 0) ? name.c_str() : NULL, (argument == true) ? 1 : 0, NULL, tag };
217 
218  return option;
219 }
220 
221 const std::string CommandLine::tag(char tag, bool argument) const throw () {
222  char buffer[4];
223 
224  if (((tag >= 'a') &&(tag <= 'z')) || ((tag >= 'A') &&(tag <= 'Z')) || ((tag >= '0') &&(tag <= '9'))) {
225  if (argument) {
226  snprintf(buffer, 4, "%c:", tag);
227  } else {
228  snprintf(buffer, 4, "%c", tag);
229  }
230  } else {
231  buffer[0] = 0;
232  }
233 
234  return std::string(buffer);
235 }
236 
237 /*
238 ** vim: noet ts=3 sw=3
239 */