1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "nel/misc/cmd_args.h"
37 _Version
= NL_VERSION
;
41 addArg("h", "help", "", "Display this help");
44 addArg("v", "version", "", "Display version of this program");
47 void CCmdArgs::addArg(const TArg
&arg
)
52 void CCmdArgs::addArg(const std::string
&shortName
, const std::string
&longName
, const std::string
&helpName
, const std::string
&helpDescription
, bool onlyOnce
)
55 arg
.shortName
= shortName
;
56 arg
.longName
= longName
;
57 arg
.helpName
= helpName
;
58 arg
.helpDescription
= helpDescription
;
59 arg
.onlyOnce
= onlyOnce
;
66 void CCmdArgs::addAdditionalArg(const std::string
&helpName
, const std::string
&helpDescription
, bool onlyOnce
, bool required
)
69 arg
.helpName
= helpName
;
70 arg
.helpDescription
= helpDescription
;
71 arg
.onlyOnce
= onlyOnce
;
73 arg
.required
= required
;
78 bool CCmdArgs::haveArg(const std::string
&argName
) const
80 // process each argument
81 for(uint i
= 0; i
< _Args
.size(); ++i
)
83 const TArg
&arg
= _Args
[i
];
85 // return true if long arg found
86 if (arg
.shortName
== argName
) return arg
.found
;
92 std::vector
<std::string
> CCmdArgs::getArg(const std::string
&argName
) const
94 // process each argument
95 for(uint i
= 0; i
< _Args
.size(); ++i
)
97 const TArg
&arg
= _Args
[i
];
99 // return values if short arg found
100 if (arg
.shortName
== argName
&& arg
.found
) return arg
.values
;
103 // return an empty vector
104 return std::vector
<std::string
>();
107 bool CCmdArgs::haveLongArg(const std::string
&argName
) const
109 // process each argument
110 for(uint i
= 0; i
< _Args
.size(); ++i
)
112 const TArg
&arg
= _Args
[i
];
114 // return true if long arg found
115 if (arg
.longName
== argName
) return arg
.found
;
121 std::vector
<std::string
> CCmdArgs::getLongArg(const std::string
&argName
) const
123 // process each argument
124 for(uint i
= 0; i
< _Args
.size(); ++i
)
126 const TArg
&arg
= _Args
[i
];
128 // return values if long arg found
129 if (arg
.longName
== argName
&& arg
.found
) return arg
.values
;
132 // return an empty vector
133 return std::vector
<std::string
>();
136 bool CCmdArgs::needAdditionalArg() const
138 // process each argument
139 for(uint i
= 0; i
< _Args
.size(); ++i
)
141 const TArg
&arg
= _Args
[i
];
143 // they don't have any short or long name, but need a name in help
144 if (arg
.shortName
.empty() && arg
.longName
.empty() && !arg
.helpName
.empty() && arg
.required
&& !arg
.found
)
151 bool CCmdArgs::haveAdditionalArg() const
153 // process each argument
154 for(uint i
= 0; i
< _Args
.size(); ++i
)
156 const TArg
&arg
= _Args
[i
];
158 // they don't have any short or long name, but need a name in help
159 if (arg
.shortName
.empty() && arg
.longName
.empty() && !arg
.helpName
.empty() && arg
.found
)
166 bool CCmdArgs::haveAdditionalArg(const std::string
&name
) const
168 // process each argument
169 for(uint i
= 0; i
< _Args
.size(); ++i
)
171 const TArg
&arg
= _Args
[i
];
173 // they don't have any short or long name, but need a name in help
174 if (arg
.shortName
.empty() && arg
.longName
.empty() && !arg
.helpName
.empty() && arg
.helpName
== name
&& arg
.found
)
181 std::vector
<std::string
> CCmdArgs::getAdditionalArg(const std::string
&name
) const
183 // process each argument
184 for(uint i
= 0; i
< _Args
.size(); ++i
)
186 const TArg
&arg
= _Args
[i
];
188 // they don't have any short or long name, but need a name in help
189 if (arg
.shortName
.empty() && arg
.longName
.empty() && !arg
.helpName
.empty() && arg
.helpName
== name
)
193 // return an empty vector
194 return std::vector
<std::string
>();
197 bool CCmdArgs::parse(const std::string
&args
)
199 std::vector
<std::string
> argv
;
203 uint len
= GetModuleFileNameW(NULL
, str
, 4096);
205 // first argument should be full path to executable
206 if (len
&& len
< 4096)
207 argv
.push_back(wideToUtf8(str
));
210 // convert string with arguments to array
211 explodeArguments(args
, argv
);
216 bool CCmdArgs::parse(int argc
, char **argv
)
218 // convert C strings to STL strings
219 std::vector
<std::string
> args
;
221 for(sint i
= 0; i
< argc
; ++i
)
224 // get rid of -psn_* arguments under OS X
225 if (strncmp(argv
[i
], "-psn_", 5) == 0) continue;
228 args
.push_back(argv
[i
]);
234 bool CCmdArgs::parse(const std::vector
<std::string
> &argv
)
237 if (argv
.empty()) return false;
239 // first argument is always the program name
240 _ProgramName
= CFile::getFilename(argv
.front());
241 _ProgramPath
= CPath::makePathAbsolute(CPath::standardizePath(CFile::getPath(argv
.front())), CPath::getCurrentPath(), true);
244 _StartupPath
= CPath::standardizePath(CPath::getCurrentPath());
246 // set process name for logs
247 CLog::setProcessName(_ProgramName
);
250 uint argc
= argv
.size();
252 // process each argument
253 for (uint i
= 1; i
< argc
; i
++)
255 std::string name
= argv
[i
];
258 // support / and - under Windows, arguments should be at least 2 characters
259 if (name
.size() > 1 && (name
[0] == '-' || name
[0] == '/'))
261 if (name
.size() > 1 && name
[0] == '-')
264 // it's a long name if using --
265 bool useLongName
= name
[0] == '-' && name
[1] == '-';
267 // extract argument name
268 name
= name
.substr(useLongName
? 2:1);
274 // look if using = to define value
275 std::string::size_type pos
= name
.find('=');
277 if (pos
!= std::string::npos
)
279 // value is second part, name the first one
280 value
= name
.substr(pos
+1);
281 name
= name
.substr(0, pos
);
284 else if (name
.length() > 1)
286 value
= name
.substr(1);
287 name
= name
.substr(0, 1);
292 // process each argument definition
293 for(uint j
= 0; j
< _Args
.size(); ++j
)
295 TArg
&arg
= _Args
[j
];
297 // only process arguments of the right type
298 if ((useLongName
&& name
!= arg
.longName
) || (!useLongName
&& name
!= arg
.shortName
)) continue;
300 // already get the only once argument
301 if (arg
.found
&& arg
.onlyOnce
)
303 // the last one is the only kept, so discard previous ones
308 found
= arg
.found
= true;
310 // another argument is required
311 if (!arg
.helpName
.empty())
313 // if the value hasn't be specified by =
314 if (value
.empty() && i
+1 < argc
)
316 // take next argument
320 // add argument value if not empty
323 arg
.values
.push_back(value
);
332 printf("Warning: Argument %s not recognized, skip it!\n", name
.c_str());
337 // process each argument definition
338 for(uint j
= 0, len
= _Args
.size(); j
< len
; ++j
)
340 TArg
&arg
= _Args
[j
];
342 // only process arguments that don't have a name
343 if (!arg
.shortName
.empty() || !arg
.longName
.empty()) continue;
345 // already get the only once argument
346 if (arg
.found
&& arg
.onlyOnce
) continue;
350 // in fact, if there are more than one required arguments, all arguments are added in first one to simplify
351 arg
.values
.push_back(name
);
359 if (haveLongArg("version"))
365 // process help if requested or if required arguments are missing
366 if (haveLongArg("help") || needAdditionalArg())
375 void CCmdArgs::displayHelp()
377 // display program name
378 printf("Usage: %s ", _ProgramName
.c_str());
380 // display optional parameters
381 for(uint i
= 0; i
< _Args
.size(); ++i
)
383 const TArg
&arg
= _Args
[i
];
385 // only short argument is displayed
386 if (!arg
.shortName
.empty())
388 printf("[-%s", arg
.shortName
.c_str());
390 // a parameter is required
391 if (!arg
.helpName
.empty())
393 printf("<%s>", arg
.helpName
.c_str());
400 // display required arguments
401 for(uint i
= 0; i
< _Args
.size(); ++i
)
403 const TArg
&arg
= _Args
[i
];
405 // they don't have any short or long name, but need a name in help
406 if (arg
.shortName
.empty() && arg
.longName
.empty() && !arg
.helpName
.empty())
408 printf(" %c%s", arg
.required
? '<':'[', arg
.helpName
.c_str());
410 // if support more than once argument
411 if (!arg
.onlyOnce
) printf("...");
413 printf("%c", arg
.required
? '>':']');
419 if (!_Description
.empty())
421 printf("\n%s\n", _Description
.c_str());
424 printf("\nWhere options are:\n");
426 // display details on each argument
427 for(uint i
= 0; i
< _Args
.size(); ++i
)
429 const TArg
&arg
= _Args
[i
];
431 // not an optional argument
432 if (arg
.shortName
.empty() && arg
.longName
.empty()) continue;
437 std::vector
<std::string
> syntaxes
;
439 // display short argument
440 if (!arg
.shortName
.empty())
442 // and it's required argument
443 if (!arg
.helpName
.empty())
445 syntaxes
.push_back(toString("-%s <%s>", arg
.shortName
.c_str(), arg
.helpName
.c_str()));
449 syntaxes
.push_back(toString("-%s", arg
.shortName
.c_str()));
453 // display long argument
454 if (!arg
.longName
.empty())
456 if (!arg
.helpName
.empty())
458 // display first syntax for long argument, --arg <value>
459 syntaxes
.push_back(toString("--%s <%s>", arg
.longName
.c_str(), arg
.helpName
.c_str()));
463 syntaxes
.push_back(toString("--%s", arg
.longName
.c_str()));
467 for(uint j
= 0; j
< syntaxes
.size(); ++j
)
471 printf("%s ", (j
== syntaxes
.size() - 1) ? " or":",");
474 printf("%s", syntaxes
[j
].c_str());
477 // display argument description
478 if (!arg
.helpDescription
.empty())
480 printf(" : %s", arg
.helpDescription
.c_str());
486 // process each argument
487 for(uint i
= 0; i
< _Args
.size(); ++i
)
489 const TArg
&arg
= _Args
[i
];
491 // only display required arguments
492 if (arg
.shortName
.empty() && arg
.longName
.empty() && !arg
.helpName
.empty() && !arg
.helpDescription
.empty())
494 printf(" %s : %s\n", arg
.helpName
.c_str(), arg
.helpDescription
.c_str());
499 void CCmdArgs::displayVersion()
501 // display a verbose version string
503 printf("%s %s (built on %s)\nCopyright (C) %s\n", _ProgramName
.c_str(), _Version
.c_str(), BUILD_DATE
, COPYRIGHT
);
507 }; // NAMESPACE NLMISC