diff --git a/src/buddies/buddies.pro b/src/buddies/buddies.pro index 2dcaa2e9a..fe717b85f 100644 --- a/src/buddies/buddies.pro +++ b/src/buddies/buddies.pro @@ -1,24 +1,6 @@ TEMPLATE = subdirs +SUBDIRS = src unit_tests -SUBDIRS = \ - bd \ - strm2cif \ - strm2dxf \ - strm2gds \ - strm2gdstxt \ - strm2oas \ - strm2txt \ - strmclip \ - strmcmp \ - strmxor \ +unit_tests.depends += src -strm2cif.depends += bd -strm2dxf.depends += bd -strm2gds.depends += bd -strm2gdstxt.depends += bd -strm2oas.depends += bd -strm2txt.depends += bd -strmclip.depends += bd -strmcmp.depends += bd -strmxor.depends += bd diff --git a/src/buddies/mkbuddies.sh b/src/buddies/mkbuddies.sh deleted file mode 100644 index 86d4c265b..000000000 --- a/src/buddies/mkbuddies.sh +++ /dev/null @@ -1,18 +0,0 @@ - -for x in *.cc; do - xx=${x/.cc} - echo "" >$xx/$xx.pro - echo 'include($$PWD/../../klayout.pri)' >>$xx/$xx.pro - echo "" >>$xx/$xx.pro - echo "TEMPLATE = app" >>$xx/$xx.pro - echo "" >>$xx/$xx.pro - echo "TARGET = $xx" >>$xx/$xx.pro - echo 'DESTDIR = $$OUT_PWD/../..' >>$xx/$xx.pro - echo "" >> $xx/$xx.pro - echo "SOURCES = $x" >>$xx/$xx.pro - echo "" >> $xx/$xx.pro - echo "INCLUDEPATH += ../../tl ../../db ../../gsi" >> $xx/$xx.pro - echo "DEPENDPATH += ../../tl ../../db ../../gsi" >> $xx/$xx.pro - echo 'LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi' >> $xx/$xx.pro -done - diff --git a/src/buddies/bd/bd.pro b/src/buddies/src/bd/bd.pro similarity index 70% rename from src/buddies/bd/bd.pro rename to src/buddies/src/bd/bd.pro index a051b5505..25076cbf2 100644 --- a/src/buddies/bd/bd.pro +++ b/src/buddies/src/bd/bd.pro @@ -1,8 +1,8 @@ -DESTDIR = $$OUT_PWD/../.. +DESTDIR = $$OUT_PWD/../../.. TARGET = klayout_bd -include($$PWD/../../klayout.pri) +include($$PWD/../../../klayout.pri) DEFINES += MAKE_BD_LIBRARY @@ -31,7 +31,7 @@ HEADERS = \ RESOURCES = \ -INCLUDEPATH += ../../tl ../../db ../../gsi ../../version -DEPENDPATH += ../../tl ../../db ../../gsi ../../version +INCLUDEPATH += ../../../tl ../../../db ../../../gsi ../../../version +DEPENDPATH += ../../../tl ../../../db ../../../gsi ../../../version LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi diff --git a/src/buddies/bd/bdCommon.h b/src/buddies/src/bd/bdCommon.h similarity index 100% rename from src/buddies/bd/bdCommon.h rename to src/buddies/src/bd/bdCommon.h diff --git a/src/buddies/bd/bdConverterMain.cc b/src/buddies/src/bd/bdConverterMain.cc similarity index 100% rename from src/buddies/bd/bdConverterMain.cc rename to src/buddies/src/bd/bdConverterMain.cc diff --git a/src/buddies/bd/bdConverterMain.h b/src/buddies/src/bd/bdConverterMain.h similarity index 100% rename from src/buddies/bd/bdConverterMain.h rename to src/buddies/src/bd/bdConverterMain.h diff --git a/src/buddies/bd/bdInit.cc b/src/buddies/src/bd/bdInit.cc similarity index 100% rename from src/buddies/bd/bdInit.cc rename to src/buddies/src/bd/bdInit.cc diff --git a/src/buddies/bd/bdInit.h b/src/buddies/src/bd/bdInit.h similarity index 100% rename from src/buddies/bd/bdInit.h rename to src/buddies/src/bd/bdInit.h diff --git a/src/buddies/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc similarity index 100% rename from src/buddies/bd/bdReaderOptions.cc rename to src/buddies/src/bd/bdReaderOptions.cc diff --git a/src/buddies/bd/bdReaderOptions.h b/src/buddies/src/bd/bdReaderOptions.h similarity index 100% rename from src/buddies/bd/bdReaderOptions.h rename to src/buddies/src/bd/bdReaderOptions.h diff --git a/src/buddies/bd/bdWriterOptions.cc b/src/buddies/src/bd/bdWriterOptions.cc similarity index 93% rename from src/buddies/bd/bdWriterOptions.cc rename to src/buddies/src/bd/bdWriterOptions.cc index b8be30d07..0a97b2ebf 100644 --- a/src/buddies/bd/bdWriterOptions.cc +++ b/src/buddies/src/bd/bdWriterOptions.cc @@ -31,7 +31,7 @@ namespace bd GenericWriterOptions::GenericWriterOptions () : m_scale_factor (1.0), m_dbu (0.0), - m_dont_write_empty_cells (false), m_keep_instances (false), m_write_context_info (false) + m_dont_write_empty_cells (false), m_keep_instances (false), m_write_context_info (true) { // .. nothing yet .. } @@ -81,9 +81,11 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin if (format.empty () || format == gds2_format_name || format == gds2text_format_name || format == oasis_format_name) { cmd << tl::arg (group + - "#--write-context-info", &m_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." + "!#--no-context-info", &m_write_context_info, "Does not write context information", + "Context information is included to maintain PCell parameters and library connections. " + "This information is kept inside the layout files in a proprietary way. This option disables " + "this feature to maintain compatibility with other consumers of the file. If this option is " + "used, PCell parameters and library links are lost." ); } @@ -170,7 +172,8 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin cmd << tl::arg (group + "-ok|--compression-level=level", &m_oasis_writer_options.compression_level, "Specifies the OASIS compression level", "This level describes how hard the OASIS writer will try to compress the shapes " - "using shape arrays. Building shape arrays may take some time and requires some memory.\n" + "using shape arrays. Building shape arrays may take some time and requires some memory. " + "The default compression level is 2.\n" "* 0 - no shape array building\n" "* 1 - nearest neighbor shape array formation\n" "* 2++ - enhanced shape array search algorithm using 2nd and further neighbor distances as well\n" @@ -188,8 +191,8 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin ) << tl::arg (group + "#--write-std-properties", &m_oasis_writer_options.write_std_properties, "Writes some global standard properties", - "This is an integer describing what standard properties shall be written. 0 is \"none\" (the default), " - "1 means \"global standard properties such as S_TOP_CELL\" are produced. With 2 also per-cell bounding " + "This is an integer describing what standard properties shall be written. 0 is \"none\", " + "1 means \"global standard properties such as S_TOP_CELL\" are produced (the default). With 2 also per-cell bounding " "boxes are produced." ) << tl::arg (group + @@ -209,7 +212,7 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin cmd << tl::arg (group + "-op|--polygon-mode=mode", &m_dxf_writer_options.polygon_mode, "Specifies how to write polygons", "This option specifies how to write polygons:\n" - "* 0: create POLYLINE\n" + "* 0: create POLYLINE (default)\n" "* 1: create LWPOLYLINE\n" "* 2: decompose into SOLID\n" "* 3: create HATCH" @@ -255,7 +258,6 @@ static void get_selected_cells (tl::Extractor &ex, const db::Layout &layout, std bool without_children = ex.test ("("); std::string filter; ex.read_word_or_quoted (filter, "_-.*?{}$[]"); - if (without_children) { ex.expect (")"); } @@ -270,15 +272,17 @@ static void get_selected_cells (tl::Extractor &ex, const db::Layout &layout, std if (pat.match (layout.cell_name (c->cell_index ()))) { std::set cells; - cells.insert (c->cell_index ()); if (! without_children) { c->collect_called_cells (cells); } + cells.insert (c->cell_index ()); if (! remove) { selected.insert (cells.begin (), cells.end ()); } else { - selected.erase (cells.begin (), cells.end ()); + for (std::set::const_iterator c = cells.begin (); c != cells.end (); ++c) { + selected.erase (*c); + } } } diff --git a/src/buddies/bd/bdWriterOptions.h b/src/buddies/src/bd/bdWriterOptions.h similarity index 100% rename from src/buddies/bd/bdWriterOptions.h rename to src/buddies/src/bd/bdWriterOptions.h diff --git a/src/buddies/bd/main.cc b/src/buddies/src/bd/main.cc similarity index 100% rename from src/buddies/bd/main.cc rename to src/buddies/src/bd/main.cc diff --git a/src/buddies/bd/strm2cif.cc b/src/buddies/src/bd/strm2cif.cc similarity index 100% rename from src/buddies/bd/strm2cif.cc rename to src/buddies/src/bd/strm2cif.cc diff --git a/src/buddies/bd/strm2dxf.cc b/src/buddies/src/bd/strm2dxf.cc similarity index 100% rename from src/buddies/bd/strm2dxf.cc rename to src/buddies/src/bd/strm2dxf.cc diff --git a/src/buddies/bd/strm2gds.cc b/src/buddies/src/bd/strm2gds.cc similarity index 100% rename from src/buddies/bd/strm2gds.cc rename to src/buddies/src/bd/strm2gds.cc diff --git a/src/buddies/bd/strm2gdstxt.cc b/src/buddies/src/bd/strm2gdstxt.cc similarity index 100% rename from src/buddies/bd/strm2gdstxt.cc rename to src/buddies/src/bd/strm2gdstxt.cc diff --git a/src/buddies/bd/strm2oas.cc b/src/buddies/src/bd/strm2oas.cc similarity index 100% rename from src/buddies/bd/strm2oas.cc rename to src/buddies/src/bd/strm2oas.cc diff --git a/src/buddies/bd/strm2txt.cc b/src/buddies/src/bd/strm2txt.cc similarity index 100% rename from src/buddies/bd/strm2txt.cc rename to src/buddies/src/bd/strm2txt.cc diff --git a/src/buddies/bd/strmclip.cc b/src/buddies/src/bd/strmclip.cc similarity index 100% rename from src/buddies/bd/strmclip.cc rename to src/buddies/src/bd/strmclip.cc diff --git a/src/buddies/bd/strmcmp.cc b/src/buddies/src/bd/strmcmp.cc similarity index 100% rename from src/buddies/bd/strmcmp.cc rename to src/buddies/src/bd/strmcmp.cc diff --git a/src/buddies/buddy_app.pri b/src/buddies/src/buddy_app.pri similarity index 85% rename from src/buddies/buddy_app.pri rename to src/buddies/src/buddy_app.pri index 4b983c378..a5f31ade2 100644 --- a/src/buddies/buddy_app.pri +++ b/src/buddies/src/buddy_app.pri @@ -1,11 +1,11 @@ -include($$PWD/../klayout.pri) +include($$PWD/../../klayout.pri) TEMPLATE = app PRO_BASENAME = $$basename(_PRO_FILE_) TARGET = $$replace(PRO_BASENAME, ".pro", "") -DESTDIR = $$OUT_PWD/../.. +DESTDIR = $$OUT_PWD/../../.. # Since the main function is entirely unspecific, we can put it into a common # place - it's not part of the bd sources. diff --git a/src/buddies/src/src.pro b/src/buddies/src/src.pro new file mode 100644 index 000000000..2dcaa2e9a --- /dev/null +++ b/src/buddies/src/src.pro @@ -0,0 +1,24 @@ + +TEMPLATE = subdirs + +SUBDIRS = \ + bd \ + strm2cif \ + strm2dxf \ + strm2gds \ + strm2gdstxt \ + strm2oas \ + strm2txt \ + strmclip \ + strmcmp \ + strmxor \ + +strm2cif.depends += bd +strm2dxf.depends += bd +strm2gds.depends += bd +strm2gdstxt.depends += bd +strm2oas.depends += bd +strm2txt.depends += bd +strmclip.depends += bd +strmcmp.depends += bd +strmxor.depends += bd diff --git a/src/buddies/strm2cif/strm2cif.pro b/src/buddies/src/strm2cif/strm2cif.pro similarity index 100% rename from src/buddies/strm2cif/strm2cif.pro rename to src/buddies/src/strm2cif/strm2cif.pro diff --git a/src/buddies/strm2dxf/strm2dxf.pro b/src/buddies/src/strm2dxf/strm2dxf.pro similarity index 100% rename from src/buddies/strm2dxf/strm2dxf.pro rename to src/buddies/src/strm2dxf/strm2dxf.pro diff --git a/src/buddies/strm2gds/strm2gds.pro b/src/buddies/src/strm2gds/strm2gds.pro similarity index 100% rename from src/buddies/strm2gds/strm2gds.pro rename to src/buddies/src/strm2gds/strm2gds.pro diff --git a/src/buddies/strm2gdstxt/strm2gdstxt.pro b/src/buddies/src/strm2gdstxt/strm2gdstxt.pro similarity index 100% rename from src/buddies/strm2gdstxt/strm2gdstxt.pro rename to src/buddies/src/strm2gdstxt/strm2gdstxt.pro diff --git a/src/buddies/strm2oas/strm2oas.pro b/src/buddies/src/strm2oas/strm2oas.pro similarity index 100% rename from src/buddies/strm2oas/strm2oas.pro rename to src/buddies/src/strm2oas/strm2oas.pro diff --git a/src/buddies/strm2txt/strm2txt.pro b/src/buddies/src/strm2txt/strm2txt.pro similarity index 100% rename from src/buddies/strm2txt/strm2txt.pro rename to src/buddies/src/strm2txt/strm2txt.pro diff --git a/src/buddies/strmclip/strmclip.pro b/src/buddies/src/strmclip/strmclip.pro similarity index 100% rename from src/buddies/strmclip/strmclip.pro rename to src/buddies/src/strmclip/strmclip.pro diff --git a/src/buddies/strmcmp/strmcmp.pro b/src/buddies/src/strmcmp/strmcmp.pro similarity index 100% rename from src/buddies/strmcmp/strmcmp.pro rename to src/buddies/src/strmcmp/strmcmp.pro diff --git a/src/buddies/strmxor/strmxor.cc b/src/buddies/src/strmxor/strmxor.cc similarity index 100% rename from src/buddies/strmxor/strmxor.cc rename to src/buddies/src/strmxor/strmxor.cc diff --git a/src/buddies/src/strmxor/strmxor.pro b/src/buddies/src/strmxor/strmxor.pro new file mode 100644 index 000000000..0896bd247 --- /dev/null +++ b/src/buddies/src/strmxor/strmxor.pro @@ -0,0 +1,13 @@ + +include($$PWD/../../../klayout.pri) + +TEMPLATE = app + +TARGET = strmxor +DESTDIR = $$OUT_PWD/../../.. + +SOURCES = strmxor.cc + +INCLUDEPATH += ../bd ../../../tl ../../../db ../../../gsi +DEPENDPATH += ../bd ../../../tl ../../../db ../../../gsi +LIBS += -L$$DESTDIR -lklayout_bd -lklayout_tl -lklayout_db -lklayout_gsi diff --git a/src/buddies/strmxor/strmxor.pro b/src/buddies/strmxor/strmxor.pro deleted file mode 100644 index 78b09623d..000000000 --- a/src/buddies/strmxor/strmxor.pro +++ /dev/null @@ -1,13 +0,0 @@ - -include($$PWD/../../klayout.pri) - -TEMPLATE = app - -TARGET = strmxor -DESTDIR = $$OUT_PWD/../.. - -SOURCES = strmxor.cc - -INCLUDEPATH += ../bd ../../tl ../../db ../../gsi -DEPENDPATH += ../bd ../../tl ../../db ../../gsi -LIBS += -L$$DESTDIR -lklayout_bd -lklayout_tl -lklayout_db -lklayout_gsi diff --git a/src/buddies/unit_tests/bdBasicTests.cc b/src/buddies/unit_tests/bdBasicTests.cc new file mode 100644 index 000000000..d2649237a --- /dev/null +++ b/src/buddies/unit_tests/bdBasicTests.cc @@ -0,0 +1,204 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2017 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "bdWriterOptions.h" +#include "bdReaderOptions.h" +#include "tlCommandLineParser.h" +#include "dbLayout.h" +#include "dbCell.h" + +#include "utHead.h" + +// Testing writer options +TEST(1) +{ + bd::GenericWriterOptions opt; + tl::CommandLineOptions cmd; + + opt.add_options (cmd); + + char *argv[] = { "x", + "-os=1.25", + "-od=0.125", + "--drop-empty-cells", + "--keep-instances", + "--no-context-info", + // CIF + "--blank-separator", + "--dummy-calls", + // DXF + "-op=2", + // GDS2 + "-ol=MYLIBNAME", + "-ov=250", + "--multi-xy-records", + "--no-timestamps", + "--no-zero-length-paths", + "--user-units=2.5", + "--write-cell-properties", + "--write-file-properties", + // OASIS + "-ob", + "-ok=9", + "-ot", + "--recompress", + "--subst-char=XY", + "--write-std-properties=2" + }; + + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + + db::Layout layout; + + db::SaveLayoutOptions stream_opt; + EXPECT_EQ (stream_opt.dont_write_empty_cells (), false); + EXPECT_EQ (stream_opt.keep_instances (), false); + EXPECT_EQ (stream_opt.write_context_info (), true); + EXPECT_EQ (stream_opt.get_options ().blank_separator, false); + EXPECT_EQ (stream_opt.get_options ().dummy_calls, false); + EXPECT_EQ (stream_opt.get_options ().polygon_mode, 0); + EXPECT_EQ (stream_opt.get_options ().libname, "LIB"); + EXPECT_EQ (stream_opt.get_options ().max_vertex_count, (unsigned int) 8000); + EXPECT_EQ (stream_opt.get_options ().multi_xy_records, false); + EXPECT_EQ (stream_opt.get_options ().write_timestamps, true); + EXPECT_EQ (stream_opt.get_options ().no_zero_length_paths, false); + EXPECT_EQ (tl::to_string (stream_opt.get_options ().user_units), "1"); + EXPECT_EQ (stream_opt.get_options ().write_cell_properties, false); + EXPECT_EQ (stream_opt.get_options ().write_file_properties, false); + EXPECT_EQ (stream_opt.get_options ().write_cblocks, false); + EXPECT_EQ (stream_opt.get_options ().compression_level, 2); + EXPECT_EQ (stream_opt.get_options ().strict_mode, false); + EXPECT_EQ (stream_opt.get_options ().recompress, false); + EXPECT_EQ (stream_opt.get_options ().subst_char, "*"); + EXPECT_EQ (stream_opt.get_options ().write_std_properties, 1); + + opt.configure (stream_opt, layout); + + EXPECT_EQ (stream_opt.scale_factor (), 1.25); + EXPECT_EQ (stream_opt.dbu (), 0.125); + EXPECT_EQ (stream_opt.dont_write_empty_cells (), true); + EXPECT_EQ (stream_opt.keep_instances (), true); + EXPECT_EQ (stream_opt.write_context_info (), false); + EXPECT_EQ (stream_opt.get_options ().blank_separator, true); + EXPECT_EQ (stream_opt.get_options ().dummy_calls, true); + EXPECT_EQ (stream_opt.get_options ().polygon_mode, 2); + EXPECT_EQ (stream_opt.get_options ().libname, "MYLIBNAME"); + EXPECT_EQ (stream_opt.get_options ().max_vertex_count, (unsigned int) 250); + EXPECT_EQ (stream_opt.get_options ().multi_xy_records, true); + EXPECT_EQ (stream_opt.get_options ().write_timestamps, false); + EXPECT_EQ (stream_opt.get_options ().no_zero_length_paths, true); + EXPECT_EQ (tl::to_string (stream_opt.get_options ().user_units), "2.5"); + EXPECT_EQ (stream_opt.get_options ().write_cell_properties, true); + EXPECT_EQ (stream_opt.get_options ().write_file_properties, true); + EXPECT_EQ (stream_opt.get_options ().write_cblocks, true); + EXPECT_EQ (stream_opt.get_options ().compression_level, 9); + EXPECT_EQ (stream_opt.get_options ().strict_mode, true); + EXPECT_EQ (stream_opt.get_options ().recompress, true); + EXPECT_EQ (stream_opt.get_options ().subst_char, "X"); + EXPECT_EQ (stream_opt.get_options ().write_std_properties, 2); +} + +static std::string cells2string (const db::Layout &layout, const std::set &cells) +{ + std::string res; + for (std::set::const_iterator c = cells.begin (); c != cells.end (); ++c) { + if (c != cells.begin ()) { + res += ","; + } + res += layout.cell_name (*c); + } + return res; +} + +// Testing writer options: cell resolution +TEST(2) +{ + // Build a layout with the hierarchy + // TOP -> A, B + // A -> B + // B -> C + // C -> D + db::Layout layout; + db::cell_index_type itop = layout.add_cell ("TOP"); + db::cell_index_type ia = layout.add_cell ("A"); + db::cell_index_type ib = layout.add_cell ("B"); + db::cell_index_type ic = layout.add_cell ("C"); + db::cell_index_type id = layout.add_cell ("D"); + layout.cell (itop).insert (db::CellInstArray (ia, db::Trans ())); + layout.cell (itop).insert (db::CellInstArray (ib, db::Trans ())); + layout.cell (ia).insert (db::CellInstArray (ib, db::Trans ())); + layout.cell (ib).insert (db::CellInstArray (ic, db::Trans ())); + layout.cell (ic).insert (db::CellInstArray (id, db::Trans ())); + + bd::GenericWriterOptions opt; + tl::CommandLineOptions cmd; + opt.add_options (cmd); + + std::set cells; + std::vector > valid_layers; + db::SaveLayoutOptions stream_opt; + + { + char *argv[] = { "x", + "--write-cells=A,-C,(C)", + }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + + opt.configure (stream_opt, layout); + + cells.clear (); + valid_layers.clear (); + stream_opt.get_cells (layout, cells, valid_layers); + + EXPECT_EQ (cells2string (layout, cells), "A,B,C"); + + { + char *argv[] = { "x", + "--write-cells=(C),(TOP)", + }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + + opt.configure (stream_opt, layout); + + cells.clear (); + valid_layers.clear (); + stream_opt.get_cells (layout, cells, valid_layers); + + EXPECT_EQ (cells2string (layout, cells), "TOP,C"); + + { + char *argv[] = { "x", + "--write-cells=(TOP),+B", + }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + + opt.configure (stream_opt, layout); + + cells.clear (); + valid_layers.clear (); + stream_opt.get_cells (layout, cells, valid_layers); + + EXPECT_EQ (cells2string (layout, cells), "TOP,B,C,D"); +} diff --git a/src/buddies/unit_tests/unit_tests.pro b/src/buddies/unit_tests/unit_tests.pro new file mode 100644 index 000000000..0df5ec9dc --- /dev/null +++ b/src/buddies/unit_tests/unit_tests.pro @@ -0,0 +1,13 @@ + +TARGET = bd_tests + +include($$PWD/../../klayout.pri) +include($$PWD/../../lib_ut.pri) + +SOURCES = \ + bdBasicTests.cc \ + +INCLUDEPATH += ../src/bd +DEPENDPATH += ../src/bd + +LIBS += -L$$DESTDIR -lklayout_bd diff --git a/src/db/dbSaveLayoutOptions.h b/src/db/dbSaveLayoutOptions.h index 7b50d0a4d..be4688438 100644 --- a/src/db/dbSaveLayoutOptions.h +++ b/src/db/dbSaveLayoutOptions.h @@ -265,7 +265,7 @@ public: template void set_options (const T &options) { - m_options.insert (std::make_pair (options.format_name (), options.clone ())); + set_options (options.clone ()); } /** @@ -280,7 +280,13 @@ public: template void set_options (T *options) { - m_options.insert (std::make_pair (options->format_name (), options)); + std::map::iterator o = m_options.find (options->format_name ()); + if (o != m_options.end ()) { + delete o->second; + o->second = options; + } else { + m_options.insert (std::make_pair (options->format_name (), options)); + } } /** diff --git a/src/lib_ut.pri b/src/lib_ut.pri new file mode 100644 index 000000000..635dcefd1 --- /dev/null +++ b/src/lib_ut.pri @@ -0,0 +1,19 @@ + +DESTDIR_UT = $$OUT_PWD/../.. +DESTDIR = $$OUT_PWD/.. + +TEMPLATE = lib + +INCLUDEPATH += ../src ../../db ../../tl ../../gsi ../../laybasic ../../lay ../../ut +DEPENDPATH += ../src ../../db ../../tl ../../gsi ../../laybasic ../../lay ../../ut +LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay -lklayout_ut + +QMAKE_RPATHDIR += $$DESTDIR + +# Only on Windows, DESTDIR_TARGET is usable. On this platform, a blank happens to appear between +# $(DESTDIR) and $(TARGET) +win32 { + QMAKE_POST_LINK += $(COPY) $(DESTDIR_TARGET) $$DESTDIR_UT/$${TARGET}.ut +} else { + QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_UT/$${TARGET}.ut +} diff --git a/src/plugins/plugin_ut.pri b/src/plugins/plugin_ut.pri index fe3f42547..174698f52 100644 --- a/src/plugins/plugin_ut.pri +++ b/src/plugins/plugin_ut.pri @@ -1,17 +1,19 @@ -DESTDIR_KLP = $$OUT_PWD/../../.. +DESTDIR_UT = $$OUT_PWD/../../.. DESTDIR = $$OUT_PWD/.. TEMPLATE = lib -INCLUDEPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../common ../../../ut -DEPENDPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../common ../../../ut -LIBS += -L$$DESTDIR_KLP -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay -lklayout_ut +INCLUDEPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../ut +DEPENDPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../ut +LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay -lklayout_ut + +QMAKE_RPATHDIR += $$DESTDIR # Only on Windows, DESTDIR_TARGET is usable. On this platform, a blank happens to appear between # $(DESTDIR) and $(TARGET) win32 { - QMAKE_POST_LINK += $(COPY) $(DESTDIR_TARGET) $$DESTDIR_KLP/$${TARGET}.klp_ut + QMAKE_POST_LINK += $(COPY) $(DESTDIR_TARGET) $$DESTDIR_UT/$${TARGET}.ut } else { - QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_KLP/$${TARGET}.klp_ut + QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_UT/$${TARGET}.ut } diff --git a/src/tl/tlCommandLineParser.cc b/src/tl/tlCommandLineParser.cc index 27eadf24d..1bd7dcede 100644 --- a/src/tl/tlCommandLineParser.cc +++ b/src/tl/tlCommandLineParser.cc @@ -98,6 +98,22 @@ ArgBase::is_option () const return !m_option.short_option.empty () || !m_option.long_option.empty (); } +std::string +ArgBase::option_desc () const +{ + std::string res; + if (! m_option.short_option.empty ()) { + res += "-" + m_option.short_option; + } + if (! m_option.long_option.empty ()) { + if (! res.empty ()) { + res += "|"; + } + res += "--" + m_option.long_option; + } + return res; +} + // ------------------------------------------------------------------------ // Internal argument classes to implement info arguments @@ -531,43 +547,61 @@ CommandLineOptions::parse (int argc, char *argv[]) } - if (! arg->is_option ()) { + try { - arg->take_value (ex); + if (! arg->is_option ()) { - } else if (arg->wants_value ()) { - - if (ex.test ("=")) { arg->take_value (ex); + + } else if (arg->wants_value ()) { + + if (ex.test ("=")) { + arg->take_value (ex); + } else { + + ex.expect_end (); + ++i; + if (i == argc) { + throw tl::Exception (tl::to_string (QObject::tr ("Value missing"))); + } + + std::string arg_as_utf8 = tl::to_string (QString::fromLocal8Bit (argv [i])); + tl::Extractor ex_value (arg_as_utf8); + arg->take_value (ex_value); + + } + } else { - if (! ex.at_end ()) { - throw tl::Exception (tl::to_string (QObject::tr ("Syntax error in argument at \"..%1\" (use -h for help)").arg (tl::to_qstring (ex.get ())))); + if (ex.test ("=")) { + arg->take_value (ex); + } else { + arg->mark_present (arg->option ().inverted); } - ++i; - if (i == argc) { - throw tl::Exception (tl::to_string (QObject::tr ("Value missing for last argument (use -h for help)"))); - } - - std::string arg_as_utf8 = tl::to_string (QString::fromLocal8Bit (argv [i])); - tl::Extractor ex_value (arg_as_utf8); - arg->take_value (ex_value); } - } else { + // Execute the action if there is one + arg->action (this); - if (ex.test ("=")) { - arg->take_value (ex); + } catch (tl::Exception &ex) { + + std::string msg = "Parser error "; + if (i == argc) { + msg += "at end of argument list"; } else { - arg->mark_present (arg->option ().inverted); + msg += "at argument #" + tl::to_string (i); } + if (! arg->is_option ()) { + msg += " (option " + arg->option_desc () + ")"; + } + msg += ":"; + msg += ex.msg (); + + throw tl::Exception (msg); } - // Execute the action if there is one - arg->action (this); - } if (next_plain_arg != plain_args.end () && !(*next_plain_arg)->option ().optional) { diff --git a/src/tl/tlCommandLineParser.h b/src/tl/tlCommandLineParser.h index bd9583f8a..8cf3854eb 100644 --- a/src/tl/tlCommandLineParser.h +++ b/src/tl/tlCommandLineParser.h @@ -122,6 +122,12 @@ public: */ bool is_option () const; + /** + * @brief Returns an option description string + * This string is typically "-x|--xlong". + */ + std::string option_desc () const; + /** * @brief Gets a value from the extractor into the target of the argument */ @@ -173,21 +179,30 @@ private: /** * @brief A helper for extracting values by type + * + * @param repeated_hint Is true, if the value is supposed to be repeated + * @param enumerated Is true, if the value parser shall stop at a comma to allow for more entries in the next iteration */ template -inline void extract (tl::Extractor &ex, T &t, bool /*for_list*/ = false) +inline void extract (tl::Extractor &ex, T &t, bool /*repeated_hint*/, bool enumerated = false) { ex.read (t); + if (! enumerated) { + ex.expect_end (); + } } /** * @brief A specialization for the string type */ -inline void extract (tl::Extractor &ex, std::string &t, bool for_list = false) +inline void extract (tl::Extractor &ex, std::string &t, bool /*repeated_hint*/, bool enumerated = false) { if (*ex == '"' || *ex == '\'') { ex.read_quoted (t); - } else if (for_list) { + if (! enumerated) { + ex.expect_end (); + } + } else if (enumerated) { ex.read (t, ","); } else { t = ex.get (); @@ -203,13 +218,13 @@ inline void extract (tl::Extractor &ex, std::string &t, bool for_list = false) * @brief A specialization for a list of any type (vector) */ template -inline void extract (tl::Extractor &ex, std::vector &t, bool for_list = false) +inline void extract (tl::Extractor &ex, std::vector &t, bool repeated_hint, bool /*enumerated*/ = false) { while (! ex.at_end ()) { t.push_back (T ()); - extract (ex, t.back (), for_list); - if (for_list) { - ex.test (","); + extract (ex, t.back (), false, ! repeated_hint); + if (! repeated_hint && ! ex.test (",")) { + ex.expect_end (); } } } @@ -287,7 +302,7 @@ public: virtual void take_value (tl::Extractor &ex) { - extract (ex, *mp_value, !option ().repeated); + extract (ex, *mp_value, option ().repeated); } virtual void mark_present (bool inverted) @@ -327,7 +342,7 @@ public: { typedef typename type_without_const_ref::inner_type inner_type; inner_type t = inner_type (); - extract (ex, t, !option ().repeated); + extract (ex, t, option ().repeated); (mp_object->*mp_setter) (t); } diff --git a/src/ut/utMain.cc b/src/ut/utMain.cc index 99abb31e5..d1379cb97 100644 --- a/src/ut/utMain.cc +++ b/src/ut/utMain.cc @@ -803,7 +803,7 @@ main_cont (int argc, char **argv) // Search and initialize plugin unit tests QStringList name_filters; - name_filters << QString::fromUtf8 ("*.klp_ut"); + name_filters << QString::fromUtf8 ("*.ut"); QDir inst_dir (tl::to_qstring (tl::get_inst_path ())); QStringList inst_modules = inst_dir.entryList (name_filters); @@ -811,13 +811,13 @@ main_cont (int argc, char **argv) for (QStringList::const_iterator im = inst_modules.begin (); im != inst_modules.end (); ++im) { - QFileInfo klp_file (inst_dir.path (), *im); - if (klp_file.exists () && klp_file.isReadable ()) { + QFileInfo ut_file (inst_dir.path (), *im); + if (ut_file.exists () && ut_file.isReadable ()) { - std::string pp = tl::to_string (klp_file.absoluteFilePath ()); + std::string pp = tl::to_string (ut_file.absoluteFilePath ()); tl::log << "Loading plugin unit tests " << pp; - // NOTE: since we are using a different suffix ("*.klp_ut"), we can't use QLibrary. + // NOTE: since we are using a different suffix ("*.ut"), we can't use QLibrary. #ifdef _WIN32 // there is no "dlopen" on mingw, so we need to emulate it. HINSTANCE handle = LoadLibraryW ((const wchar_t *) tl::to_qstring (pp).constData ()); @@ -995,7 +995,7 @@ main_cont (int argc, char **argv) bool exclude = false; for (std::vector::const_iterator m = exclude_test_list.begin (); m != exclude_test_list.end (); ++m) { QRegExp re (tl::to_qstring (*m), Qt::CaseInsensitive, QRegExp::Wildcard); - if (re.indexIn (tl::to_qstring ((*i)->name ())) >= 0) { + if (re.indexIn (tl::to_qstring ((*i)->name ())) == 0) { exclude = true; break; } @@ -1003,7 +1003,7 @@ main_cont (int argc, char **argv) for (std::vector::const_iterator m = test_list.begin (); !exclude && m != test_list.end (); ++m) { QRegExp re (tl::to_qstring (*m), Qt::CaseInsensitive, QRegExp::Wildcard); - if (re.indexIn (tl::to_qstring ((*i)->name ())) >= 0) { + if (re.indexIn (tl::to_qstring ((*i)->name ())) == 0) { tl::info << " " << (*i)->name (); subset.push_back (*i); break;