mirror of https://github.com/KLayout/klayout.git
Equipped strmclip with the new command line parser
Plus: added repeated arguments (in addition to the array arguments that have been there before).
This commit is contained in:
parent
e54cadef99
commit
681c255e50
|
|
@ -229,20 +229,25 @@ void GenericReaderOptions::set_dbu (double dbu)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GenericReaderOptions::configure (db::LoadLayoutOptions &load_options)
|
GenericReaderOptions::configure (db::LoadLayoutOptions &load_options) const
|
||||||
{
|
{
|
||||||
m_common_reader_options.layer_map = m_layer_map;
|
db::CommonReaderOptions common_reader_options = m_common_reader_options;
|
||||||
m_common_reader_options.create_other_layers = m_create_other_layers;
|
common_reader_options.layer_map = m_layer_map;
|
||||||
m_dxf_reader_options.layer_map = m_layer_map;
|
common_reader_options.create_other_layers = m_create_other_layers;
|
||||||
m_dxf_reader_options.create_other_layers = m_create_other_layers;
|
|
||||||
m_cif_reader_options.layer_map = m_layer_map;
|
|
||||||
m_cif_reader_options.create_other_layers = m_create_other_layers;
|
|
||||||
|
|
||||||
load_options.set_options (m_common_reader_options);
|
db::DXFReaderOptions dxf_reader_options = m_dxf_reader_options;
|
||||||
|
dxf_reader_options.layer_map = m_layer_map;
|
||||||
|
dxf_reader_options.create_other_layers = m_create_other_layers;
|
||||||
|
|
||||||
|
db::CIFReaderOptions cif_reader_options = m_cif_reader_options;
|
||||||
|
cif_reader_options.layer_map = m_layer_map;
|
||||||
|
cif_reader_options.create_other_layers = m_create_other_layers;
|
||||||
|
|
||||||
|
load_options.set_options (common_reader_options);
|
||||||
load_options.set_options (m_gds2_reader_options);
|
load_options.set_options (m_gds2_reader_options);
|
||||||
load_options.set_options (m_oasis_reader_options);
|
load_options.set_options (m_oasis_reader_options);
|
||||||
load_options.set_options (m_cif_reader_options);
|
load_options.set_options (cif_reader_options);
|
||||||
load_options.set_options (m_dxf_reader_options);
|
load_options.set_options (dxf_reader_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Configures the reader options object with the options stored in this object
|
* @brief Configures the reader options object with the options stored in this object
|
||||||
*/
|
*/
|
||||||
void configure (db::LoadLayoutOptions &load_options);
|
void configure (db::LoadLayoutOptions &load_options) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the option prefix for the short option name
|
* @brief Sets the option prefix for the short option name
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin
|
||||||
"given factor."
|
"given factor."
|
||||||
);
|
);
|
||||||
|
|
||||||
if (format == gds2_format_name || format == gds2text_format_name || format == oasis_format_name) {
|
if (format.empty () || format == gds2_format_name || format == gds2text_format_name || format == oasis_format_name) {
|
||||||
cmd << tl::arg (group +
|
cmd << tl::arg (group +
|
||||||
"-od|--dbu-out=dbu", &m_dbu, "Uses the specified database unit",
|
"-od|--dbu-out=dbu", &m_dbu, "Uses the specified database unit",
|
||||||
"Specifies the database unit to save the layout in. The database unit is given "
|
"Specifies the database unit to save the layout in. The database unit is given "
|
||||||
|
|
@ -68,7 +68,7 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin
|
||||||
"If given, empty cells won't be written. See --keep-instances for more options."
|
"If given, empty cells won't be written. See --keep-instances for more options."
|
||||||
);
|
);
|
||||||
|
|
||||||
if (format == gds2_format_name || format == gds2text_format_name) {
|
if (format.empty () || format == gds2_format_name || format == gds2text_format_name) {
|
||||||
cmd << tl::arg (group +
|
cmd << tl::arg (group +
|
||||||
"#--keep-instances", &m_keep_instances, "Keeps instances of dropped cells",
|
"#--keep-instances", &m_keep_instances, "Keeps instances of dropped cells",
|
||||||
"If given, instances of dropped cell's won't be removed. Hence, ghost cells are "
|
"If given, instances of dropped cell's won't be removed. Hence, ghost cells are "
|
||||||
|
|
@ -79,7 +79,7 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format == gds2_format_name || format == gds2text_format_name || format == oasis_format_name) {
|
if (format.empty () || format == gds2_format_name || format == gds2text_format_name || format == oasis_format_name) {
|
||||||
cmd << tl::arg (group +
|
cmd << tl::arg (group +
|
||||||
"#--write-context-info", &m_write_context_info, "Writes context information",
|
"#--write-context-info", &m_write_context_info, "Writes context information",
|
||||||
"Include context information for PCell instances and other information in a format-specific "
|
"Include context information for PCell instances and other information in a format-specific "
|
||||||
|
|
@ -289,7 +289,7 @@ static void get_selected_cells (tl::Extractor &ex, const db::Layout &layout, std
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GenericWriterOptions::configure (db::SaveLayoutOptions &save_options, const db::Layout &layout)
|
GenericWriterOptions::configure (db::SaveLayoutOptions &save_options, const db::Layout &layout) const
|
||||||
{
|
{
|
||||||
save_options.set_scale_factor (m_scale_factor);
|
save_options.set_scale_factor (m_scale_factor);
|
||||||
save_options.set_dbu (m_dbu);
|
save_options.set_dbu (m_dbu);
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ public:
|
||||||
* The format string gives a hint about the target format. Certain options will be
|
* The format string gives a hint about the target format. Certain options will be
|
||||||
* suppressed if they are known to be unavailable for the given format.
|
* suppressed if they are known to be unavailable for the given format.
|
||||||
*/
|
*/
|
||||||
void add_options (tl::CommandLineOptions &cmd, const std::string &format);
|
void add_options (tl::CommandLineOptions &cmd, const std::string &format = std::string ());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds the generic options to the command line parser object for the GDS2 format
|
* @brief Adds the generic options to the command line parser object for the GDS2 format
|
||||||
|
|
@ -100,7 +100,7 @@ public:
|
||||||
* @brief Configures the writer options object with the options stored in this object
|
* @brief Configures the writer options object with the options stored in this object
|
||||||
* The layout is required in order to derive the cell and layer ID's.
|
* The layout is required in order to derive the cell and layer ID's.
|
||||||
*/
|
*/
|
||||||
void configure (db::SaveLayoutOptions &save_options, const db::Layout &layout);
|
void configure (db::SaveLayoutOptions &save_options, const db::Layout &layout) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double m_scale_factor;
|
double m_scale_factor;
|
||||||
|
|
|
||||||
|
|
@ -20,42 +20,62 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "bdInit.h"
|
||||||
|
#include "bdReaderOptions.h"
|
||||||
|
#include "bdWriterOptions.h"
|
||||||
#include "dbClip.h"
|
#include "dbClip.h"
|
||||||
#include "dbLayout.h"
|
#include "dbLayout.h"
|
||||||
#include "dbGDS2Writer.h"
|
#include "dbGDS2Writer.h"
|
||||||
#include "dbOASISWriter.h"
|
#include "dbOASISWriter.h"
|
||||||
#include "dbReader.h"
|
#include "dbReader.h"
|
||||||
#include "tlLog.h"
|
#include "tlLog.h"
|
||||||
|
#include "tlCommandLineParser.h"
|
||||||
|
|
||||||
|
|
||||||
struct ClipData
|
struct ClipData
|
||||||
{
|
{
|
||||||
ClipData ()
|
ClipData ()
|
||||||
: file_in (), file_out (), clip_layer (),
|
: file_in (), file_out (), clip_layer ()
|
||||||
oasis (false), gzip (false)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
bd::GenericReaderOptions reader_options;
|
||||||
|
bd::GenericWriterOptions writer_options;
|
||||||
std::string file_in;
|
std::string file_in;
|
||||||
std::string file_out;
|
std::string file_out;
|
||||||
db::LayerProperties clip_layer;
|
db::LayerProperties clip_layer;
|
||||||
bool oasis;
|
|
||||||
bool gzip;
|
|
||||||
std::vector <db::DBox> clip_boxes;
|
std::vector <db::DBox> clip_boxes;
|
||||||
std::string result;
|
std::string result;
|
||||||
std::string top;
|
std::string top;
|
||||||
|
|
||||||
|
void add_box (const std::string &spec)
|
||||||
|
{
|
||||||
|
tl::Extractor ex (spec.c_str ());
|
||||||
|
double l = 0.0, b = 0.0, r = 0.0, t = 0.0;
|
||||||
|
ex >> l >> "," >> b >> "," >> r >> "," >> t >> tl::Extractor::end ();
|
||||||
|
clip_boxes.push_back (db::DBox (l, b, r, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_clip_layer (const std::string &spec)
|
||||||
|
{
|
||||||
|
tl::Extractor ex (spec.c_str ());
|
||||||
|
clip_layer = db::LayerProperties ();
|
||||||
|
clip_layer.read (ex);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void clip (const ClipData &data)
|
void clip (const ClipData &data)
|
||||||
{
|
{
|
||||||
db::Manager m;
|
db::Layout layout;
|
||||||
db::Layout layout (&m);
|
db::Layout target_layout;
|
||||||
db::Layout target_layout (&m);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
db::LoadLayoutOptions load_options;
|
||||||
|
data.reader_options.configure (load_options);
|
||||||
|
|
||||||
tl::InputStream stream (data.file_in);
|
tl::InputStream stream (data.file_in);
|
||||||
db::Reader reader (stream);
|
db::Reader reader (stream);
|
||||||
reader.read (layout);
|
reader.read (layout, load_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the layers in the target layout as well
|
// create the layers in the target layout as well
|
||||||
|
|
@ -135,123 +155,61 @@ void clip (const ClipData &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the layout
|
// write the layout
|
||||||
tl::OutputStreamBase *out_file = 0;
|
|
||||||
try {
|
|
||||||
|
|
||||||
tl::OutputStream stream (data.file_out, data.gzip ? tl::OutputStream::OM_Zlib : tl::OutputStream::OM_Plain);
|
db::SaveLayoutOptions save_options;
|
||||||
|
save_options.set_format_from_filename (data.file_out);
|
||||||
|
data.writer_options.configure (save_options, target_layout);
|
||||||
|
|
||||||
if (data.oasis) {
|
tl::OutputStream stream (data.file_out);
|
||||||
db::OASISWriter writer;
|
db::Writer writer (save_options);
|
||||||
writer.write (target_layout, stream, db::SaveLayoutOptions ());
|
writer.write (target_layout, stream);
|
||||||
} else {
|
|
||||||
db::GDS2Writer writer;
|
|
||||||
writer.write (target_layout, stream, db::SaveLayoutOptions ());
|
|
||||||
}
|
|
||||||
|
|
||||||
delete out_file;
|
|
||||||
|
|
||||||
} catch (...) {
|
|
||||||
if (out_file) {
|
|
||||||
delete out_file;
|
|
||||||
}
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_syntax ()
|
BD_MAIN_FUNC
|
||||||
{
|
{
|
||||||
printf ("Syntax: strmclip [<options>] <infile> <outfile>\n");
|
ClipData data;
|
||||||
printf ("\n");
|
|
||||||
printf ("Options are:\n");
|
|
||||||
printf (" -l 'l/d' take clip regions from layer l, datatype d\n");
|
|
||||||
printf (" -o produce oasis output\n");
|
|
||||||
printf (" -g produce gds output\n");
|
|
||||||
printf (" -z gzip output\n");
|
|
||||||
printf (" -t 'cell' use this cell from input (default: determine top cell automatically)\n");
|
|
||||||
printf (" -x 'name' use this cell as top cell in output\n");
|
|
||||||
printf (" -r 'l,b,r,t' explicitly specify a clip rectangle (can be present multiple times)\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
bd::init ();
|
||||||
main (int argc, char *argv [])
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
|
|
||||||
ClipData data;
|
tl::CommandLineOptions cmd;
|
||||||
|
data.reader_options.add_options (cmd);
|
||||||
|
data.writer_options.add_options (cmd);
|
||||||
|
|
||||||
for (int n = 1; n < argc; ++n) {
|
cmd << tl::arg ("input", &data.file_in, "The input file",
|
||||||
|
"The input file can be any supported format. It can be gzip compressed and will "
|
||||||
|
"be uncompressed automatically in this case."
|
||||||
|
)
|
||||||
|
<< tl::arg ("output", &data.file_out, "The output file",
|
||||||
|
"The output format is determined from the suffix of the file. If the suffix indicates "
|
||||||
|
"gzip compression, the file will be compressed on output. Examples for recognized suffixes are "
|
||||||
|
"\".oas\", \".gds.gz\", \".dxf\" or \"gds2\"."
|
||||||
|
)
|
||||||
|
<< tl::arg ("-l|--clip-layer=spec", &data, &ClipData::set_clip_layer, "Specifies a layer to take the clip regions from",
|
||||||
|
"If this option is given, the clip rectangles are taken from the given layer."
|
||||||
|
"The layer specification is of the \"layer/datatype\" form or a plain layer name if named layers "
|
||||||
|
"are available."
|
||||||
|
)
|
||||||
|
<< tl::arg ("-t|--top-in=cellname", &data.top, "Specifies the top cell for input",
|
||||||
|
"If this option is given, it specifies the cell to use as top cell from the input."
|
||||||
|
)
|
||||||
|
<< tl::arg ("-x|--top-out=cellname", &data.result, "Specifies the top cell for output",
|
||||||
|
"If given, this name will be used as the top cell name in the output file. "
|
||||||
|
"By default the output's top cell will be \"CLIPPED_\" plus the input's top cell name."
|
||||||
|
)
|
||||||
|
<< tl::arg ("*-r|--clip-box=l,b,r,t", &data, &ClipData::add_box, "Specifies a clip box",
|
||||||
|
"This option specifies the box to clip in micrometer units. The box is given "
|
||||||
|
"by left, bottom, right and top coordinates. This option can be used multiple times "
|
||||||
|
"to produce a clip covering more than one rectangle."
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
if (std::string (argv [n]) == "-h") {
|
cmd.brief ("This program will produce clips from an input layout and writes them to another layout");
|
||||||
print_syntax ();
|
|
||||||
return 0;
|
|
||||||
} else if (std::string (argv [n]) == "-o") {
|
|
||||||
data.oasis = true;
|
|
||||||
} else if (std::string (argv [n]) == "-g") {
|
|
||||||
data.oasis = false;
|
|
||||||
} else if (std::string (argv [n]) == "-z") {
|
|
||||||
data.gzip = true;
|
|
||||||
} else if (std::string (argv [n]) == "-x") {
|
|
||||||
if (n < argc + 1) {
|
|
||||||
++n;
|
|
||||||
data.result = argv [n];
|
|
||||||
}
|
|
||||||
} else if (std::string (argv [n]) == "-t") {
|
|
||||||
if (n < argc + 1) {
|
|
||||||
++n;
|
|
||||||
data.top = argv [n];
|
|
||||||
}
|
|
||||||
} else if (std::string (argv [n]) == "-r") {
|
|
||||||
if (n < argc + 1) {
|
|
||||||
++n;
|
|
||||||
tl::Extractor ex (argv [n]);
|
|
||||||
double l = 0.0, b = 0.0, r = 0.0, t = 0.0;
|
|
||||||
ex.read (l); ex.expect (",");
|
|
||||||
ex.read (b); ex.expect (",");
|
|
||||||
ex.read (r); ex.expect (",");
|
|
||||||
ex.read (t); ex.expect_end ();
|
|
||||||
data.clip_boxes.push_back (db::DBox (l, b, r, t));
|
|
||||||
}
|
|
||||||
} else if (std::string (argv [n]) == "-l") {
|
|
||||||
if (n < argc + 1) {
|
|
||||||
++n;
|
|
||||||
tl::Extractor ex (argv[n]);
|
|
||||||
db::LayerProperties lp;
|
|
||||||
lp.read (ex);
|
|
||||||
data.clip_layer = lp;
|
|
||||||
}
|
|
||||||
} else if (argv [n][0] == '-') {
|
|
||||||
print_syntax ();
|
|
||||||
throw tl::Exception ("Unknown option: " + std::string (argv [n]));
|
|
||||||
} else if (data.file_in.empty ()) {
|
|
||||||
data.file_in = argv [n];
|
|
||||||
} else if (data.file_out.empty ()) {
|
|
||||||
data.file_out = argv [n];
|
|
||||||
} else {
|
|
||||||
print_syntax ();
|
|
||||||
throw tl::Exception ("Superfluous command element: " + std::string (argv [n]));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
cmd.parse (argc, argv);
|
||||||
|
|
||||||
if (data.file_in.empty () || data.file_out.empty ()) {
|
clip (data);
|
||||||
print_syntax ();
|
|
||||||
throw tl::Exception ("Input or output file name missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
clip (data);
|
|
||||||
|
|
||||||
} catch (std::exception &ex) {
|
|
||||||
tl::error << ex.what ();
|
|
||||||
return 1;
|
|
||||||
} catch (tl::Exception &ex) {
|
|
||||||
tl::error << ex.msg ();
|
|
||||||
return 1;
|
|
||||||
} catch (...) {
|
|
||||||
tl::error << "unspecific error";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BD_MAIN
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace tl
|
||||||
// ArgBase implementation
|
// ArgBase implementation
|
||||||
|
|
||||||
ArgBase::ParsedOption::ParsedOption (const std::string &option)
|
ArgBase::ParsedOption::ParsedOption (const std::string &option)
|
||||||
: optional (false), inverted (false), advanced (false), non_advanced (false)
|
: optional (false), inverted (false), advanced (false), non_advanced (false), repeated (false)
|
||||||
{
|
{
|
||||||
tl::Extractor ex (option.c_str ());
|
tl::Extractor ex (option.c_str ());
|
||||||
|
|
||||||
|
|
@ -42,6 +42,12 @@ ArgBase::ParsedOption::ParsedOption (const std::string &option)
|
||||||
advanced = true;
|
advanced = true;
|
||||||
} else if (ex.test ("/")) {
|
} else if (ex.test ("/")) {
|
||||||
non_advanced = true;
|
non_advanced = true;
|
||||||
|
} else if (ex.test ("*")) {
|
||||||
|
repeated = true;
|
||||||
|
} else if (ex.test ("!")) {
|
||||||
|
inverted = true;
|
||||||
|
} else if (ex.test ("?")) {
|
||||||
|
optional = true;
|
||||||
} else if (ex.test ("[")) {
|
} else if (ex.test ("[")) {
|
||||||
const char *t = ex.get ();
|
const char *t = ex.get ();
|
||||||
while (! ex.at_end () && *ex != ']') {
|
while (! ex.at_end () && *ex != ']') {
|
||||||
|
|
@ -55,10 +61,6 @@ ArgBase::ParsedOption::ParsedOption (const std::string &option)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ex.test ("!")) {
|
|
||||||
inverted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! ex.at_end ()) {
|
while (! ex.at_end ()) {
|
||||||
if (ex.test ("--")) {
|
if (ex.test ("--")) {
|
||||||
optional = true;
|
optional = true;
|
||||||
|
|
@ -73,7 +75,6 @@ ArgBase::ParsedOption::ParsedOption (const std::string &option)
|
||||||
ex.read_word (name);
|
ex.read_word (name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
optional = ex.test ("?");
|
|
||||||
ex.read_word (name);
|
ex.read_word (name);
|
||||||
}
|
}
|
||||||
ex.test("|");
|
ex.test("|");
|
||||||
|
|
@ -523,13 +524,20 @@ CommandLineOptions::parse (int argc, char *argv[])
|
||||||
throw tl::Exception (tl::to_string (QObject::tr ("Unknown command line component %1 - no further plain argument expected (use -h for help)").arg (tl::to_qstring (arg_as_utf8))));
|
throw tl::Exception (tl::to_string (QObject::tr ("Unknown command line component %1 - no further plain argument expected (use -h for help)").arg (tl::to_qstring (arg_as_utf8))));
|
||||||
}
|
}
|
||||||
|
|
||||||
arg = *next_plain_arg++;
|
arg = *next_plain_arg;
|
||||||
|
if (! arg->option ().repeated) {
|
||||||
|
++next_plain_arg;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg->wants_value ()) {
|
if (! arg->is_option ()) {
|
||||||
|
|
||||||
if (! arg->is_option () || ex.test ("=")) {
|
arg->take_value (ex);
|
||||||
|
|
||||||
|
} else if (arg->wants_value ()) {
|
||||||
|
|
||||||
|
if (ex.test ("=")) {
|
||||||
arg->take_value (ex);
|
arg->take_value (ex);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -557,7 +565,7 @@ CommandLineOptions::parse (int argc, char *argv[])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exection the action if there is one
|
// Execute the action if there is one
|
||||||
arg->action (this);
|
arg->action (this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public:
|
||||||
*/
|
*/
|
||||||
ParsedOption (const std::string &option);
|
ParsedOption (const std::string &option);
|
||||||
|
|
||||||
bool optional, inverted, advanced, non_advanced;
|
bool optional, inverted, advanced, non_advanced, repeated;
|
||||||
std::string long_option, short_option, name;
|
std::string long_option, short_option, name;
|
||||||
std::string group;
|
std::string group;
|
||||||
};
|
};
|
||||||
|
|
@ -80,7 +80,11 @@ public:
|
||||||
* "-o|--long-option=value" - A short/long option with a value
|
* "-o|--long-option=value" - A short/long option with a value
|
||||||
* "[group]..." - List the option under this group (group = group title)
|
* "[group]..." - List the option under this group (group = group title)
|
||||||
* "#..." - Advanced option - listed with --help-all only
|
* "#..." - Advanced option - listed with --help-all only
|
||||||
* "/..." - Non-ddvanced option - listed with -h|--help only
|
* "/..." - Non-advanced option - listed with -h|--help only
|
||||||
|
* "*..." - Multiple occurances allowed - values needs to be
|
||||||
|
* an array and values are accumulated. Without *, the
|
||||||
|
* value string is evaluated to a comma-separated list.
|
||||||
|
* "*" means one occurance at least unless combined with "?".
|
||||||
*/
|
*/
|
||||||
ArgBase (const std::string &option, const std::string &brief_doc, const std::string &long_doc);
|
ArgBase (const std::string &option, const std::string &brief_doc, const std::string &long_doc);
|
||||||
|
|
||||||
|
|
@ -187,6 +191,11 @@ inline void extract (tl::Extractor &ex, std::string &t, bool for_list = false)
|
||||||
ex.read (t, ",");
|
ex.read (t, ",");
|
||||||
} else {
|
} else {
|
||||||
t = ex.get ();
|
t = ex.get ();
|
||||||
|
// TODO: there should be a tl::Extractor method either to
|
||||||
|
// read all remaining text or to move the pointer to the end.
|
||||||
|
while (! ex.at_end ()) {
|
||||||
|
++ex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,12 +203,14 @@ inline void extract (tl::Extractor &ex, std::string &t, bool for_list = false)
|
||||||
* @brief A specialization for a list of any type (vector)
|
* @brief A specialization for a list of any type (vector)
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void extract (tl::Extractor &ex, std::vector<T> &t, bool /*for_list*/ = false)
|
inline void extract (tl::Extractor &ex, std::vector<T> &t, bool for_list = false)
|
||||||
{
|
{
|
||||||
while (! ex.at_end ()) {
|
while (! ex.at_end ()) {
|
||||||
t.push_back (T ());
|
t.push_back (T ());
|
||||||
extract (ex, t.back (), true);
|
extract (ex, t.back (), for_list);
|
||||||
ex.test (",");
|
if (for_list) {
|
||||||
|
ex.test (",");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,7 +287,7 @@ public:
|
||||||
|
|
||||||
virtual void take_value (tl::Extractor &ex)
|
virtual void take_value (tl::Extractor &ex)
|
||||||
{
|
{
|
||||||
extract (ex, *mp_value);
|
extract (ex, *mp_value, !option ().repeated);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void mark_present (bool inverted)
|
virtual void mark_present (bool inverted)
|
||||||
|
|
@ -316,7 +327,7 @@ public:
|
||||||
{
|
{
|
||||||
typedef typename type_without_const_ref<T>::inner_type inner_type;
|
typedef typename type_without_const_ref<T>::inner_type inner_type;
|
||||||
inner_type t = inner_type ();
|
inner_type t = inner_type ();
|
||||||
extract (ex, t);
|
extract (ex, t, !option ().repeated);
|
||||||
(mp_object->*mp_setter) (t);
|
(mp_object->*mp_setter) (t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,7 @@ TEST(2)
|
||||||
EXPECT_EQ (v.f, "bar");
|
EXPECT_EQ (v.f, "bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Array arguments
|
||||||
TEST(3)
|
TEST(3)
|
||||||
{
|
{
|
||||||
std::vector<std::string> a;
|
std::vector<std::string> a;
|
||||||
|
|
@ -318,3 +319,78 @@ TEST(3)
|
||||||
EXPECT_EQ (b[0], -13);
|
EXPECT_EQ (b[0], -13);
|
||||||
EXPECT_EQ (b[1], 21);
|
EXPECT_EQ (b[1], 21);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repeated array arguments
|
||||||
|
TEST(4)
|
||||||
|
{
|
||||||
|
std::vector<std::string> a;
|
||||||
|
std::vector<int> b;
|
||||||
|
|
||||||
|
tl::CommandLineOptions cmd;
|
||||||
|
cmd << tl::arg ("*-a|--along", &a, "")
|
||||||
|
<< tl::arg ("*-b|--blong", &b, "");
|
||||||
|
|
||||||
|
{
|
||||||
|
char *argv[] = { "x", "-a", "r,u,v" };
|
||||||
|
cmd.parse (sizeof (argv) / sizeof (argv[0]), argv);
|
||||||
|
}
|
||||||
|
EXPECT_EQ (int (a.size ()), 1);
|
||||||
|
EXPECT_EQ (a[0], "r,u,v");
|
||||||
|
EXPECT_EQ (b.empty (), true);
|
||||||
|
|
||||||
|
a.clear ();
|
||||||
|
b.clear ();
|
||||||
|
{
|
||||||
|
char *argv[] = { "x", "-b", "1", "-a=r", "-a", "u", "--along=v", "--blong=2" };
|
||||||
|
cmd.parse (sizeof (argv) / sizeof (argv[0]), argv);
|
||||||
|
}
|
||||||
|
EXPECT_EQ (int (a.size ()), 3);
|
||||||
|
EXPECT_EQ (int (b.size ()), 2);
|
||||||
|
EXPECT_EQ (a[0], "r");
|
||||||
|
EXPECT_EQ (a[1], "u");
|
||||||
|
EXPECT_EQ (a[2], "v");
|
||||||
|
EXPECT_EQ (b[0], 1);
|
||||||
|
EXPECT_EQ (b[1], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeated and non-repeated plain arguments
|
||||||
|
TEST(5)
|
||||||
|
{
|
||||||
|
std::string a;
|
||||||
|
std::vector<std::string> b;
|
||||||
|
std::vector<std::string> c;
|
||||||
|
|
||||||
|
tl::CommandLineOptions cmd;
|
||||||
|
cmd << tl::arg ("a", &a, "")
|
||||||
|
<< tl::arg ("b", &b, "")
|
||||||
|
<< tl::arg ("?*c", &c, "");
|
||||||
|
|
||||||
|
{
|
||||||
|
char *argv[] = { "x", "y", "r,u,v" };
|
||||||
|
cmd.parse (sizeof (argv) / sizeof (argv[0]), argv);
|
||||||
|
}
|
||||||
|
EXPECT_EQ (int (b.size ()), 3);
|
||||||
|
EXPECT_EQ (int (c.size ()), 0);
|
||||||
|
EXPECT_EQ (a, "y");
|
||||||
|
EXPECT_EQ (b[0], "r");
|
||||||
|
EXPECT_EQ (b[1], "u");
|
||||||
|
EXPECT_EQ (b[2], "v");
|
||||||
|
|
||||||
|
a.clear ();
|
||||||
|
b.clear ();
|
||||||
|
c.clear ();
|
||||||
|
|
||||||
|
{
|
||||||
|
char *argv[] = { "x", "y", "r,u,v", "a,b", "c", "d" };
|
||||||
|
cmd.parse (sizeof (argv) / sizeof (argv[0]), argv);
|
||||||
|
}
|
||||||
|
EXPECT_EQ (int (b.size ()), 3);
|
||||||
|
EXPECT_EQ (int (c.size ()), 3);
|
||||||
|
EXPECT_EQ (a, "y");
|
||||||
|
EXPECT_EQ (b[0], "r");
|
||||||
|
EXPECT_EQ (b[1], "u");
|
||||||
|
EXPECT_EQ (b[2], "v");
|
||||||
|
EXPECT_EQ (c[0], "a,b");
|
||||||
|
EXPECT_EQ (c[1], "c");
|
||||||
|
EXPECT_EQ (c[2], "d");
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue