diff --git a/src/buddies/strm2cif/strm2cif.cc b/src/buddies/strm2cif/strm2cif.cc index 36f00f43e..32c9f1c77 100644 --- a/src/buddies/strm2cif/strm2cif.cc +++ b/src/buddies/strm2cif/strm2cif.cc @@ -31,23 +31,30 @@ int main (int argc, char *argv []) { + db::SaveLayoutOptions save_options; db::CIFWriterOptions cif_options; std::string infile, outfile; tl::CommandLineOptions cmd; - cmd << tl::arg("-od|--dummy-calls", &cif_options.dummy_calls, "Produces dummy calls", - "If this option is given, the writer will produce dummy cell calls on global level for all top cells" - ) - << tl::arg("-ob|--blank-separator", &cif_options.blank_separator, "Uses blanks as x/y separators", - "If this option is given, blank characters will be used to separate x and y values. " - "Otherwise comma characters will be used.\n" - "Use this option if your CIF consumer cannot read comma characters as x/y separators." - ) - << tl::arg("input", &infile, "The input file (any format, may be gzip compressed)") - << tl::arg("output", &outfile, "The output file") + cmd << tl::arg ("-od|--dummy-calls", &cif_options.dummy_calls, "Produces dummy calls", + "If this option is given, the writer will produce dummy cell calls on global level for all top cells" + ) + << tl::arg ("-ob|--blank-separator", &cif_options.blank_separator, "Uses blanks as x/y separators", + "If this option is given, blank characters will be used to separate x and y values. " + "Otherwise comma characters will be used.\n" + "Use this option if your CIF consumer cannot read comma characters as x/y separators." + ) + << tl::arg ("-os|--scale-factor=factor", &save_options, &db::SaveLayoutOptions::set_scale_factor, "Scales the layout upon writing", + "Specifies layout scaling. If given, the saved layout will be scaled by the " + "given factor." + ) + << tl::arg ("input", &infile, "The input file (any format, may be gzip compressed)") + << tl::arg ("output", &outfile, "The output file") ; + save_options.set_options (cif_options); + cmd.brief ("This program will convert the given file to a CIF file"); try { @@ -67,8 +74,6 @@ main (int argc, char *argv []) { tl::OutputStream stream (outfile); db::CIFWriter writer; - db::SaveLayoutOptions save_options; - save_options.set_options (cif_options); writer.write (layout, stream, save_options); } diff --git a/src/buddies/strm2gds/strm2gds.cc b/src/buddies/strm2gds/strm2gds.cc index e0c75c226..c2703897e 100644 --- a/src/buddies/strm2gds/strm2gds.cc +++ b/src/buddies/strm2gds/strm2gds.cc @@ -23,20 +23,86 @@ #include "dbLayout.h" #include "dbReader.h" #include "dbGDS2Writer.h" +#include "tlCommandLineParser.h" -int +int main (int argc, char *argv []) { - if (argc != 3) { - printf ("Syntax: strm2gds \n"); - return 1; - } + db::SaveLayoutOptions save_options; + db::GDS2WriterOptions gds2_options; + std::string infile, outfile; - std::string infile (argv[1]); - std::string outfile (argv[2]); + tl::CommandLineOptions cmd; + + cmd << tl::arg ("-ov|--max-vertex-count=count", &gds2_options.max_vertex_count, "Specify the maximum number of points per polygon", + "If this number is given, polygons are cut into smaller parts if they have more " + "than the specified number of points. If not given, the maximum number of points will be used. " + "This is 8190 unless --multi-xy-records is given." + ) + << tl::arg ("-om|--multi-xy-records", &gds2_options.multi_xy_records, "Allow unlimited number of points", + "If this option is given, multiple XY records will be written to accomodate an unlimited number " + "of points per polygon or path. However, such files may not be compatible with some consumers." + ) + << tl::arg ("-oz|--no-zero-length-paths", &gds2_options.no_zero_length_paths, "Don't allow zero-length paths", + "If this option is given, zero-length paths (such with one point) are not written." + ) + << tl::arg ("-on|--cellname-length=length", &gds2_options.max_cellname_length, "Limits cell names to the given length", + "If this option is given, long cell names will truncated if their length exceeds the given length." + ) + << tl::arg ("-ol|--libname=libname", &gds2_options.libname, "Uses the given library name", + "This option can specify the GDS2 LIBNAME for the output file. By default, the original LIBNAME is " + "written." + ) + << tl::arg ("-om|--user-units=unit", &gds2_options.user_units, "Specifies the user unit to use", + "Specifies the GDS2 user unit. By default micrometers are used for the user unit." + ) + << tl::arg ("!-ot|--no-timestamps", &gds2_options.write_timestamps, "Don't write timestamps", + "Writes a dummy time stamp instead of the actual time. With this option, GDS2 files become " + "bytewise indentical even if written at different times. This option is useful if binary " + "identity is important (i.e. in regression scenarios)." + ) + << tl::arg ("-op|--write-cell-properties", &gds2_options.write_cell_properties, "Write cell properties", + "This option enables a GDS2 extension that allows writing of cell properties to GDS2 files. " + "Consumers that don't support this feature, may not be able to read such a GDS2 files." + ) + << tl::arg ("-oq|--write-file-properties", &gds2_options.write_file_properties, "Write file properties", + "This option enables a GDS2 extension that allows writing of file properties to GDS2 files. " + "Consumers that don't support this feature, may not be able to read such a GDS2 files." + ) + << tl::arg ("-os|--scale-factor=factor", &save_options, &db::SaveLayoutOptions::set_scale_factor, "Scales the layout upon writing", + "Specifies layout scaling. If given, the saved layout will be scaled by the " + "given factor." + ) + << tl::arg ("-ou|--dbu=dbu", &save_options, &db::SaveLayoutOptions::set_dbu, "Uses the specified database unit", + "Specifies the database unit to save the layout in. The database unit is given " + "in micron units. By default, the original unit is used. The layout will not " + "change physically because internally, the coordinates are scaled to match the " + "new database unit." + ) + << tl::arg ("-ox|--drop-empty-cells", &save_options, &db::SaveLayoutOptions::set_dont_write_empty_cells, "Drops empty cells", + "If given, empty cells won't be written. See --keep-instances for more options." + ) + << tl::arg ("-ok|--keep-instances", &save_options, &db::SaveLayoutOptions::set_keep_instances, "Keeps instances of dropped cells", + "If given, instances of dropped cell's won't be removed. Hence, ghost cells are " + "produced. The resulting layout may not be readable by consumers that require " + "all instantiated cells to be present as actual cells." + ) + << tl::arg ("-oc|--write-context-info", &save_options, &db::SaveLayoutOptions::set_write_context_info, "Writes context information", + "Include context information for PCell instances and other information in a format-specific " + "way. The resulting layout may show unexpected features for other consumers." + ) + << tl::arg ("input", &infile, "The input file (any format, may be gzip compressed)") + << tl::arg ("output", &outfile, "The output file") + ; + + save_options.set_options (gds2_options); + + cmd.brief ("This program will convert the given file to a GDS2 file"); try { + cmd.parse (argc, argv); + db::Manager m; db::Layout layout (&m); db::LayerMap map; @@ -50,7 +116,7 @@ main (int argc, char *argv []) { tl::OutputStream stream (outfile); db::GDS2Writer writer; - writer.write (layout, stream, db::SaveLayoutOptions ()); + writer.write (layout, stream, save_options); } } catch (std::exception &ex) { diff --git a/src/tl/tlCommandLineParser.cc b/src/tl/tlCommandLineParser.cc index d401b936a..b4c05aff7 100644 --- a/src/tl/tlCommandLineParser.cc +++ b/src/tl/tlCommandLineParser.cc @@ -32,9 +32,14 @@ namespace tl // ArgBase implementation ArgBase::ParsedOption::ParsedOption (const std::string &option) - : optional (false) + : optional (false), inverted (false) { tl::Extractor ex (option.c_str ()); + + if (ex.test ("!")) { + inverted = true; + } + while (! ex.at_end ()) { if (ex.test ("--")) { optional = true; @@ -322,7 +327,7 @@ CommandLineOptions::parse (int argc, char *argv[]) if (ex.test ("=")) { arg->take_value (ex); } else { - arg->mark_present (); + arg->mark_present (arg->option ().inverted); } } diff --git a/src/tl/tlCommandLineParser.h b/src/tl/tlCommandLineParser.h index cad3d8bed..64cef66b3 100644 --- a/src/tl/tlCommandLineParser.h +++ b/src/tl/tlCommandLineParser.h @@ -54,7 +54,7 @@ public: */ ParsedOption (const std::string &option); - bool optional; + bool optional, inverted; std::string long_option, short_option, name; }; @@ -69,6 +69,7 @@ public: * "name" - A mandatory input parameter with name "name" * "?name" - An optional input parameter with name "name" * "-o" - A short option without a parameter (boolean) + * "!-o" - Sets the value to false if present * "-o=value" - A short option with a value named "value" * "--long-option" - A long option * "--long-option=value" - A long option with a value @@ -122,7 +123,7 @@ public: /** * @brief Marks an option to be present (for boolean options) */ - virtual void mark_present () + virtual void mark_present (bool) { // .. nothing yet .. } @@ -191,26 +192,26 @@ void extract (tl::Extractor &ex, std::vector &t, bool /*for_list*/ = false) * @brief A helper to mark "presence" */ template -void mark_presence (T &) +void mark_presence (T &, bool) { // .. the default implementation does nothing .. } -void mark_presence (bool &t) +void mark_presence (bool &t, bool invert) { - t = true; + t = !invert; } template -void mark_presence_setter (C *, void (C::*) (T)) +void mark_presence_setter (C *, void (C::*) (T), bool) { // .. the default implementation does nothing .. } template -void mark_presence_setter (C *c, void (C::*ptr) (bool)) +void mark_presence_setter (C *c, void (C::*ptr) (bool), bool invert) { - (c->*ptr) (true); + (c->*ptr) (!invert); } @@ -263,9 +264,9 @@ public: extract (ex, *mp_value); } - virtual void mark_present () + virtual void mark_present (bool inverted) { - mark_presence (*mp_value); + mark_presence (*mp_value, inverted); } virtual ArgBase *clone () const @@ -304,9 +305,9 @@ public: (mp_object->*mp_setter) (t); } - virtual void mark_present () + virtual void mark_present (bool inverted) { - mark_presence_setter (mp_object, mp_setter); + mark_presence_setter (mp_object, mp_setter, inverted); } virtual ArgBase *clone () const diff --git a/src/unit_tests/tlCommandLineParser.cc b/src/unit_tests/tlCommandLineParser.cc index 672a38c7d..c407e913e 100644 --- a/src/unit_tests/tlCommandLineParser.cc +++ b/src/unit_tests/tlCommandLineParser.cc @@ -37,6 +37,7 @@ TEST(1) cmd << tl::arg ("a", &a, "") << tl::arg ("?b", &b, "") << tl::arg ("-c", &c, "") + << tl::arg ("!-cc", &c, "") << tl::arg ("--dlong|-d", &d, "") << tl::arg ("--elong", &e, "") << tl::arg ("-f|--flong=value", &f, ""); @@ -64,6 +65,22 @@ TEST(1) EXPECT_EQ (b, 0); EXPECT_EQ (c, true); + b = 0; + c = true; + { + char *argv[] = { "x", "u", "-cc" }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + EXPECT_EQ (a, "u"); + EXPECT_EQ (b, 0); + EXPECT_EQ (c, false); + + { + char *argv[] = { "x", "u", "-c", "-cc" }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + EXPECT_EQ (c, false); + b = 0; c = false; { @@ -151,6 +168,7 @@ TEST(2) cmd << tl::arg ("a", &v, &Values::set_a, "") << tl::arg ("?b", &v, &Values::set_b, "") << tl::arg ("-c", &v, &Values::set_c, "") + << tl::arg ("!-cc", &v, &Values::set_c, "") << tl::arg ("--dlong|-d", &v, &Values::set_d, "") << tl::arg ("--elong", &v, &Values::set_e, "") << tl::arg ("-f|--flong=value", &v, &Values::set_f, ""); @@ -178,6 +196,22 @@ TEST(2) EXPECT_EQ (v.b, 0); EXPECT_EQ (v.c, true); + v.b = 0; + v.c = true; + { + char *argv[] = { "x", "u", "-cc" }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + EXPECT_EQ (v.a, "u"); + EXPECT_EQ (v.b, 0); + EXPECT_EQ (v.c, false); + + { + char *argv[] = { "x", "u", "-c", "-cc" }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + EXPECT_EQ (v.c, false); + v.b = 0; v.c = false; {