mirror of https://github.com/KLayout/klayout.git
Merge pull request #2307 from KLayout/feature/issue-2300
Feature/issue 2300
This commit is contained in:
commit
766380b6ea
|
|
@ -41,7 +41,9 @@ INCLUDEPATH += $$RBA_INC
|
|||
DEPENDPATH += $$RBA_INC
|
||||
|
||||
equals(HAVE_RUBY, "1") {
|
||||
LIBS += -lklayout_rba
|
||||
INCLUDEPATH += $$DRC_INC $$LVS_INC
|
||||
DEPENDPATH += $$DRC_INC $$LVS_INC
|
||||
LIBS += -lklayout_rba -lklayout_drc -lklayout_lvs
|
||||
} else {
|
||||
LIBS += -lklayout_rbastub
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,10 +153,10 @@ void clip (ClipData &data)
|
|||
// write the layout
|
||||
|
||||
db::SaveLayoutOptions save_options;
|
||||
save_options.set_format_from_filename (data.file_out);
|
||||
std::string of = save_options.set_format_from_filename (data.file_out).second;
|
||||
data.writer_options.configure (save_options, target_layout);
|
||||
|
||||
tl::OutputStream stream (data.file_out);
|
||||
tl::OutputStream stream (of);
|
||||
db::Writer writer (save_options);
|
||||
writer.write (target_layout, stream);
|
||||
}
|
||||
|
|
@ -176,7 +176,9 @@ BD_PUBLIC int strmclip (int argc, char *argv[])
|
|||
<< 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\"."
|
||||
"\".oas\", \".gds.gz\", \".dxf\" or \".gds2\". You can also use any name, and specify the "
|
||||
"desired suffix in square brackets after the file name. For example, 'file.clip[oas]' will "
|
||||
"create an OASIS file called 'file.clip'."
|
||||
)
|
||||
<< 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."
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
#include "libForceLink.h"
|
||||
#include "rdbForceLink.h"
|
||||
#include "pexForceLink.h"
|
||||
#include "drcForceLink.h"
|
||||
#include "lvsForceLink.h"
|
||||
#include "lymMacro.h"
|
||||
#include "lymMacroCollection.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -408,7 +408,9 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
<< tl::arg ("?output", &output, "The output file to which the XOR differences are written",
|
||||
"This argument is optional. If not given, the exit status alone will indicate whether the layouts "
|
||||
"are identical or not. The output is a layout file. The format of the file is derived "
|
||||
"from the file name's suffix (.oas[.gz] for (gzipped) OASIS, .gds[.gz] for (gzipped) GDS2 etc.)."
|
||||
"from the file name's suffix (.oas for OASIS, .gds[.gz] for (gzipped) GDS2 etc.). "
|
||||
"You can also use any name, and specify the desired suffix in square brackets after the file name. "
|
||||
"For example, 'file.xor[oas]' will create an OASIS file called 'file.xor'."
|
||||
)
|
||||
<< tl::arg ("-ta|--top-a=name", &top_a, "Specifies the top cell for the first layout",
|
||||
"Use this option to take a specific cell as the top cell from the first layout. All "
|
||||
|
|
@ -587,10 +589,10 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
if (output_layout.get ()) {
|
||||
|
||||
db::SaveLayoutOptions save_options;
|
||||
save_options.set_format_from_filename (output);
|
||||
std::string of = save_options.set_format_from_filename (output).second;
|
||||
writer_options.configure (save_options, *output_layout);
|
||||
|
||||
tl::OutputStream stream (output);
|
||||
tl::OutputStream stream (of);
|
||||
db::Writer writer (save_options);
|
||||
writer.write (*output_layout, stream);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ INCLUDEPATH += $$RBA_INC
|
|||
DEPENDPATH += $$RBA_INC
|
||||
|
||||
equals(HAVE_RUBY, "1") {
|
||||
LIBS += -lklayout_rba
|
||||
LIBS += -lklayout_rba -lklayout_drc -lklayout_lvs
|
||||
} else {
|
||||
LIBS += -lklayout_rbastub
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,6 +212,34 @@ TEST(7)
|
|||
db::compare_layouts (this, layout, input, db::NoNormalization);
|
||||
}
|
||||
|
||||
// Small DEF example with explicit format
|
||||
TEST(8)
|
||||
{
|
||||
std::string input = tl::testdata ();
|
||||
input += "/lefdef/strm2oas_small/in.defok[def]";
|
||||
|
||||
std::string input_au = tl::testdata ();
|
||||
input_au += "/lefdef/strm2oas_small/au.gds";
|
||||
|
||||
std::string output = this->tmp_file ("small_def");
|
||||
|
||||
const char *argv[] = { "x", input.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::LoadLayoutOptions options;
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, options);
|
||||
EXPECT_EQ (reader.format (), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteGDS2);
|
||||
}
|
||||
|
||||
// Large LEF/DEF to OAS converter test
|
||||
TEST(10)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,6 +97,34 @@ TEST(2)
|
|||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
EXPECT_EQ (reader.format (), "GDS2");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
// with explicit output format
|
||||
TEST(3)
|
||||
{
|
||||
std::string input = tl::testdata ();
|
||||
input += "/bd/strm2clip_in.gds";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/bd/strm2clip_au2.gds";
|
||||
|
||||
std::string output = this->tmp_file () + "[oas]";
|
||||
|
||||
const char *argv[] = { "x", input.c_str (), output.c_str (), "-r=0,-2,9,5", "-t", "INV2", "-x=CLIP_OUT" };
|
||||
|
||||
EXPECT_EQ (strmclip (sizeof (argv) / sizeof (argv[0]), (char **) argv), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
EXPECT_EQ (reader.format (), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@
|
|||
TEST(1)
|
||||
{
|
||||
#if defined(HAVE_PYTHON)
|
||||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.py";
|
||||
|
||||
std::string cmd;
|
||||
std::string cmd_call;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// NOTE: because of system integrity, MacOS does not inherit DYLD_LIBRARY_PATH to child
|
||||
|
|
@ -39,19 +36,42 @@ TEST(1)
|
|||
const char *ldpath_name = "DYLD_LIBRARY_PATH";
|
||||
const char *ldpath = getenv (ldpath_name);
|
||||
if (ldpath) {
|
||||
cmd += std::string (ldpath_name) + "=\"" + ldpath + "\"; export " + ldpath_name + "; ";
|
||||
cmd_call += std::string (ldpath_name) + "=\"" + ldpath + "\"; export " + ldpath_name + "; ";
|
||||
}
|
||||
#endif
|
||||
|
||||
cmd += tl::combine_path (tl::get_inst_path (), "strmrun ") + fp;
|
||||
tl::info << cmd;
|
||||
cmd_call += tl::combine_path (tl::get_inst_path (), "strmrun");
|
||||
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
tl::info << data;
|
||||
{
|
||||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.py";
|
||||
|
||||
std::string cmd = cmd_call + " " + fp;
|
||||
tl::info << cmd;
|
||||
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
tl::info << data;
|
||||
|
||||
EXPECT_EQ (data, "Hello, world (0,-42;42,0)!\n");
|
||||
}
|
||||
|
||||
{
|
||||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.drc";
|
||||
|
||||
std::string cmd = cmd_call + " " + fp;
|
||||
tl::info << cmd;
|
||||
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
tl::info << data;
|
||||
|
||||
EXPECT_EQ (data, "This is DRC.\n");
|
||||
}
|
||||
|
||||
EXPECT_EQ (data, "Hello, world (0,-42;42,0)!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,52 @@ TEST(1A_Flat)
|
|||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
|
||||
EXPECT_EQ (std::string (reader.format ()), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
"Result summary (layers without differences are not shown):\n"
|
||||
"\n"
|
||||
" Layer Output Differences (shape count)\n"
|
||||
" ----------------------------------------------------------------\n"
|
||||
" 3/0 3/0 30\n"
|
||||
" 6/0 6/0 41\n"
|
||||
" 8/1 8/1 1\n"
|
||||
" 10/0 - (no such layer in first layout)\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(1A_FlatWithExplicitOutputFormat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testdata ();
|
||||
input_a += "/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testdata ();
|
||||
input_b += "/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/bd/strmxor_au1.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.xxx[oas]");
|
||||
|
||||
const char *argv[] = { "x", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
|
||||
EXPECT_EQ (std::string (reader.format ()), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ SOURCES = \
|
|||
gsiDeclDbRecursiveInstanceIterator.cc \
|
||||
gsiDeclDbRecursiveShapeIterator.cc \
|
||||
gsiDeclDbRegion.cc \
|
||||
gsiDeclDbSaveLayoutOptions.cc \
|
||||
gsiDeclDbShape.cc \
|
||||
gsiDeclDbShapeProcessor.cc \
|
||||
gsiDeclDbShapes.cc \
|
||||
|
|
|
|||
|
|
@ -113,9 +113,8 @@ EdgePairs::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,9 +145,8 @@ Edges::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,13 +134,26 @@ ReaderBase::check_dbu (double dbu) const
|
|||
Reader::Reader (tl::InputStream &stream)
|
||||
: mp_actual_reader (0), m_stream (stream)
|
||||
{
|
||||
// Detect the format by asking all reader declarations
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end () && ! mp_actual_reader; ++rdr) {
|
||||
m_stream.reset ();
|
||||
if (rdr->detect (m_stream)) {
|
||||
m_stream.reset ();
|
||||
mp_actual_reader = rdr->create_reader (m_stream);
|
||||
if (stream.is_explicit_suffix ()) {
|
||||
|
||||
// If an explicit suffix is given for the stream, use it to find the reader
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end () && ! mp_actual_reader; ++rdr) {
|
||||
if (tl::match_filename_to_format ("." + stream.suffix (), rdr->file_format ())) {
|
||||
mp_actual_reader = rdr->create_reader (m_stream);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Detect the format by asking all reader declarations
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end () && ! mp_actual_reader; ++rdr) {
|
||||
m_stream.reset ();
|
||||
if (rdr->detect (m_stream)) {
|
||||
m_stream.reset ();
|
||||
mp_actual_reader = rdr->create_reader (m_stream);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! mp_actual_reader) {
|
||||
|
|
|
|||
|
|
@ -142,9 +142,8 @@ Region::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "tlStream.h"
|
||||
#include "tlExpression.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -444,16 +445,33 @@ SaveLayoutOptions::get_cells (const db::Layout &layout, std::set <db::cell_index
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
std::pair<bool, std::string>
|
||||
SaveLayoutOptions::set_format_from_filename (const std::string &fn)
|
||||
{
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator fmt = tl::Registrar<db::StreamFormatDeclaration>::begin (); fmt != tl::Registrar<db::StreamFormatDeclaration>::end (); ++fmt) {
|
||||
if (tl::match_filename_to_format (fn, fmt->file_format ())) {
|
||||
m_format = fmt->format_name ();
|
||||
return true;
|
||||
tl::GlobPattern pat ("(*)\\[(*)\\]");
|
||||
|
||||
std::vector<std::string> pat_parts;
|
||||
if (pat.match (fn, pat_parts) && pat_parts.size () == 2) {
|
||||
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator fmt = tl::Registrar<db::StreamFormatDeclaration>::begin (); fmt != tl::Registrar<db::StreamFormatDeclaration>::end (); ++fmt) {
|
||||
if (tl::match_filename_to_format ("." + pat_parts[1], fmt->file_format ())) {
|
||||
m_format = fmt->format_name ();
|
||||
return std::make_pair (true, pat_parts[0]);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator fmt = tl::Registrar<db::StreamFormatDeclaration>::begin (); fmt != tl::Registrar<db::StreamFormatDeclaration>::end (); ++fmt) {
|
||||
if (tl::match_filename_to_format (fn, fmt->file_format ())) {
|
||||
m_format = fmt->format_name ();
|
||||
return std::make_pair (true, fn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
|
||||
return std::make_pair (false, fn);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ public:
|
|||
*
|
||||
* Returns true, if the suffix indicates a known format.
|
||||
*/
|
||||
bool set_format_from_filename (const std::string &fn);
|
||||
std::pair<bool, std::string> set_format_from_filename(const std::string &fn);
|
||||
|
||||
/**
|
||||
* @brief Sets specific options for the given format
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::
|
|||
} else {
|
||||
// write the temp file in the same format than the au file
|
||||
tmp_file = _this->tmp_file (tl::sprintf ("tmp_%x." + tl::extension (au_file), hash));
|
||||
options.set_format_from_filename (tmp_file);
|
||||
tmp_file = options.set_format_from_filename (tmp_file).second;
|
||||
}
|
||||
|
||||
if ((norm & NoContext) != 0) {
|
||||
|
|
|
|||
|
|
@ -109,9 +109,8 @@ Texts::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1310,10 +1310,10 @@ write_simple (const db::Cell *cell, const std::string &filename)
|
|||
db::SaveLayoutOptions options;
|
||||
options.clear_cells ();
|
||||
options.add_cell (cell->cell_index ());
|
||||
options.set_format_from_filename (filename);
|
||||
std::string fn = options.set_format_from_filename (filename).second;
|
||||
|
||||
db::Writer writer (options);
|
||||
tl::OutputStream stream (filename);
|
||||
tl::OutputStream stream (fn);
|
||||
writer.write (*layout, stream);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -690,12 +690,13 @@ static void
|
|||
write_simple (db::Layout *layout, const std::string &filename)
|
||||
{
|
||||
db::SaveLayoutOptions options;
|
||||
if (! options.set_format_from_filename (filename)) {
|
||||
auto ff = options.set_format_from_filename (filename);
|
||||
if (! ff.first) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot determine format from filename")));
|
||||
}
|
||||
|
||||
db::Writer writer (options);
|
||||
tl::OutputStream stream (filename);
|
||||
tl::OutputStream stream (ff.second);
|
||||
writer.write (*layout, stream);
|
||||
}
|
||||
|
||||
|
|
@ -2863,231 +2864,4 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"@/code\n"
|
||||
);
|
||||
|
||||
static db::SaveLayoutOptions *new_v ()
|
||||
{
|
||||
return new db::SaveLayoutOptions ();
|
||||
}
|
||||
|
||||
static bool set_format_from_filename (db::SaveLayoutOptions *opt, const std::string &fn)
|
||||
{
|
||||
if (! opt->set_format_from_filename (fn)) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot determine format from filename")));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Class<db::SaveLayoutOptions> decl_SaveLayoutOptions ("db", "SaveLayoutOptions",
|
||||
gsi::constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
"\n"
|
||||
"This will initialize the scale factor to 1.0, the database unit is set to\n"
|
||||
"\"same as original\" and all layers are selected as well as all cells.\n"
|
||||
"The default format is GDS2."
|
||||
) +
|
||||
gsi::method_ext ("set_format_from_filename", &set_format_from_filename, gsi::arg ("filename"),
|
||||
"@brief Select a format from the given file name\n"
|
||||
"\n"
|
||||
"This method will set the format according to the file's extension.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.22. "
|
||||
"Beginning with version 0.23, this method always returns true, since the "
|
||||
"only consumer for the return value, Layout#write, now ignores that "
|
||||
"parameter and automatically determines the compression mode from the file name.\n"
|
||||
) +
|
||||
gsi::method ("format=", &db::SaveLayoutOptions::set_format, gsi::arg ("format"),
|
||||
"@brief Select a format\n"
|
||||
"The format string can be either \"GDS2\", \"OASIS\", \"CIF\" or \"DXF\". Other formats may be available if\n"
|
||||
"a suitable plugin is installed."
|
||||
) +
|
||||
gsi::method ("format", &db::SaveLayoutOptions::format,
|
||||
"@brief Gets the format name\n"
|
||||
"\n"
|
||||
"See \\format= for a description of that method.\n"
|
||||
) +
|
||||
gsi::method ("add_layer", &db::SaveLayoutOptions::add_layer, gsi::arg ("layer_index"), gsi::arg ("properties"),
|
||||
"@brief Add a layer to be saved \n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Adds the layer with the given index to the layer list that will be written.\n"
|
||||
"If all layers have been selected previously, all layers will \n"
|
||||
"be unselected first and only the new layer remains.\n"
|
||||
"\n"
|
||||
"The 'properties' argument can be used to assign different layer properties than the ones\n"
|
||||
"present in the layout. Pass a default \\LayerInfo object to this argument to use the\n"
|
||||
"properties from the layout object. Construct a valid \\LayerInfo object with explicit layer,\n"
|
||||
"datatype and possibly a name to override the properties stored in the layout.\n"
|
||||
) +
|
||||
gsi::method ("select_all_layers", &db::SaveLayoutOptions::select_all_layers,
|
||||
"@brief Select all layers to be saved\n"
|
||||
"\n"
|
||||
"This method will clear all layers selected with \\add_layer so far and set the 'select all layers' flag.\n"
|
||||
"This is the default.\n"
|
||||
) +
|
||||
gsi::method ("deselect_all_layers", &db::SaveLayoutOptions::deselect_all_layers,
|
||||
"@brief Unselect all layers: no layer will be saved\n"
|
||||
"\n"
|
||||
"This method will clear all layers selected with \\add_layer so far and clear the 'select all layers' flag.\n"
|
||||
"Using this method is the only way to save a layout without any layers."
|
||||
) +
|
||||
gsi::method ("select_cell", &db::SaveLayoutOptions::select_cell, gsi::arg ("cell_index"),
|
||||
"@brief Selects a cell to be saved (plus hierarchy below)\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This method is basically a convenience method that combines \\clear_cells and \\add_cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.22.\n"
|
||||
) +
|
||||
gsi::method ("select_this_cell", &db::SaveLayoutOptions::select_this_cell, gsi::arg ("cell_index"),
|
||||
"@brief Selects a cell to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This method is basically a convenience method that combines \\clear_cells and \\add_this_cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("clear_cells", &db::SaveLayoutOptions::clear_cells,
|
||||
"@brief Clears all cells to be saved\n"
|
||||
"\n"
|
||||
"This method can be used to ensure that no cell is selected before \\add_cell is called to specify a cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.22.\n"
|
||||
) +
|
||||
gsi::method ("add_this_cell", &db::SaveLayoutOptions::add_this_cell, gsi::arg ("cell_index"),
|
||||
"@brief Adds a cell to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The index of the cell must be a valid index in the context of the layout that will be saved.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"Unlike \\add_cell, this method does not implicitly add all children of that cell.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("add_cell", &db::SaveLayoutOptions::add_cell, gsi::arg ("cell_index"),
|
||||
"@brief Add a cell (plus hierarchy) to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The index of the cell must be a valid index in the context of the layout that will be saved.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method also implicitly adds the children of that cell. A method that does not add the "
|
||||
"children in \\add_this_cell.\n"
|
||||
) +
|
||||
gsi::method ("select_all_cells", &db::SaveLayoutOptions::select_all_cells,
|
||||
"@brief Select all cells to save\n"
|
||||
"\n"
|
||||
"This method will clear all cells specified with \\add_cells so far and set the 'select all cells' flag.\n"
|
||||
"This is the default.\n"
|
||||
) +
|
||||
gsi::method ("write_context_info=", &db::SaveLayoutOptions::set_write_context_info, gsi::arg ("flag"),
|
||||
"@brief Enables or disables context information\n"
|
||||
"\n"
|
||||
"If this flag is set to false, no context information for PCell or library cell instances is written. "
|
||||
"Those cells will be converted to plain cells and KLayout will not be able to restore the identity of "
|
||||
"those cells. Use this option to enforce compatibility with other tools that don't understand the "
|
||||
"context information of KLayout.\n"
|
||||
"\n"
|
||||
"The default value is true (context information is stored). Not all formats support context information, hence "
|
||||
"that flag has no effect for formats like CIF or DXF.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("write_context_info?", &db::SaveLayoutOptions::write_context_info,
|
||||
"@brief Gets a flag indicating whether context information will be stored\n"
|
||||
"\n"
|
||||
"See \\write_context_info= for details about this flag.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("keep_instances=", &db::SaveLayoutOptions::set_keep_instances, gsi::arg ("flag"),
|
||||
"@brief Enables or disables instances for dropped cells\n"
|
||||
"\n"
|
||||
"If this flag is set to true, instances for cells will be written, even if the cell is dropped. "
|
||||
"That may happen, if cells are selected with \\select_this_cell or \\add_this_cell or \\no_empty_cells is used. "
|
||||
"Even if cells called by such cells are not selected, instances will be written for that "
|
||||
"cell if \"keep_instances\" is true. That feature is supported by the GDS format currently and "
|
||||
"results in \"ghost cells\" which have instances but no cell definition.\n"
|
||||
"\n"
|
||||
"The default value is false (instances of dropped cells are not written).\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("keep_instances?", &db::SaveLayoutOptions::keep_instances,
|
||||
"@brief Gets a flag indicating whether instances will be kept even if the target cell is dropped\n"
|
||||
"\n"
|
||||
"See \\keep_instances= for details about this flag.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("dbu=", &db::SaveLayoutOptions::set_dbu, gsi::arg ("dbu"),
|
||||
"@brief Sets the database unit to be used in the stream file\n"
|
||||
"\n"
|
||||
"By default, the database unit of the layout is used. This method allows one to explicitly use a different\n"
|
||||
"database unit. A scale factor is introduced automatically which scales all layout objects accordingly so their physical dimensions remain the same. "
|
||||
"When scaling to a larger database unit or one that is not an integer fraction of the original one, rounding errors may occur and the "
|
||||
"layout may become slightly distorted."
|
||||
) +
|
||||
gsi::method ("dbu", &db::SaveLayoutOptions::dbu,
|
||||
"@brief Gets the explicit database unit if one is set\n"
|
||||
"\n"
|
||||
"See \\dbu= for a description of that attribute.\n"
|
||||
) +
|
||||
gsi::method ("no_empty_cells=", &db::SaveLayoutOptions::set_dont_write_empty_cells, gsi::arg ("flag"),
|
||||
"@brief Don't write empty cells if this flag is set\n"
|
||||
"\n"
|
||||
"By default, all cells are written (no_empty_cells is false).\n"
|
||||
"This applies to empty cells which do not contain shapes for the specified layers "
|
||||
"as well as cells which are empty because they reference empty cells only.\n"
|
||||
) +
|
||||
gsi::method ("no_empty_cells?", &db::SaveLayoutOptions::dont_write_empty_cells,
|
||||
"@brief Returns a flag indicating whether empty cells are not written.\n"
|
||||
) +
|
||||
gsi::method ("libname=|#gds2_libname=", &db::SaveLayoutOptions::set_libname, gsi::arg ("libname"),
|
||||
"@brief Sets the library name\n"
|
||||
"\n"
|
||||
"The library name is an attribute and specifies a formal name for a library, if the layout files is to be used as one.\n"
|
||||
"Currently, this attribute is only supported by the GDS2 format. Hence the alias.\n"
|
||||
"\n"
|
||||
"By default or if the libname is an empty string, the current library name of the layout or 'LIB' is used.\n"
|
||||
"\n"
|
||||
"The 'libname' alias has been introduced in version 0.30.5. The original name \\gds2_libname= is still available."
|
||||
) +
|
||||
gsi::method ("libname|#gds2_libname", &db::SaveLayoutOptions::libname,
|
||||
"@brief Gets the library name\n"
|
||||
"\n"
|
||||
"See \\libname= for details.\n"
|
||||
"The 'libname' alias has been introduced in version 0.30.5. The original name \\gds2_libname is still available."
|
||||
) +
|
||||
gsi::method ("scale_factor=", &db::SaveLayoutOptions::set_scale_factor, gsi::arg ("scale_factor"),
|
||||
"@brief Sets the scaling factor for the saving \n"
|
||||
"\n"
|
||||
"Using a scaling factor will scale all objects accordingly. "
|
||||
"This scale factor adds to a potential scaling implied by using an explicit database unit.\n"
|
||||
"\n"
|
||||
"Be aware that rounding effects may occur if fractional scaling factors are used.\n"
|
||||
"\n"
|
||||
"By default, no scaling is applied."
|
||||
) +
|
||||
gsi::method ("scale_factor", &db::SaveLayoutOptions::scale_factor,
|
||||
"@brief Gets the scaling factor currently set\n"
|
||||
),
|
||||
"@brief Options for saving layouts\n"
|
||||
"\n"
|
||||
"This class describes the various options for saving a layout to a stream file (GDS2, OASIS and others).\n"
|
||||
"There are: layers to be saved, cell or cells to be saved, scale factor, format, database unit\n"
|
||||
"and format specific options.\n"
|
||||
"\n"
|
||||
"Usually the default constructor provides a suitable object. Please note, that the format written is \"GDS2\" by default. Either explicitly set a "
|
||||
"format using \\format= or derive the format from the file name using \\set_format_from_filename.\n"
|
||||
"\n"
|
||||
"The layers are specified by either selecting all layers or by defining layer by layer using the\n"
|
||||
"\\add_layer method. \\select_all_layers will explicitly select all layers for saving, \\deselect_all_layers will explicitly clear the list of layers.\n"
|
||||
"\n"
|
||||
"Cells are selected in a similar fashion: by default, all cells are selected. Using \\add_cell, specific\n"
|
||||
"cells can be selected for saving. All these cells plus their hierarchy will then be written to the stream file.\n"
|
||||
"\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,262 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2026 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 "gsiDecl.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
static db::SaveLayoutOptions *new_v ()
|
||||
{
|
||||
return new db::SaveLayoutOptions ();
|
||||
}
|
||||
|
||||
static std::string set_format_from_filename (db::SaveLayoutOptions *opt, const std::string &fn)
|
||||
{
|
||||
auto ff = opt->set_format_from_filename (fn);
|
||||
if (! ff.first) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot determine format from filename")));
|
||||
}
|
||||
return ff.second;
|
||||
}
|
||||
|
||||
Class<db::SaveLayoutOptions> decl_SaveLayoutOptions ("db", "SaveLayoutOptions",
|
||||
gsi::constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
"\n"
|
||||
"This will initialize the scale factor to 1.0, the database unit is set to\n"
|
||||
"\"same as original\" and all layers are selected as well as all cells.\n"
|
||||
"The default format is GDS2."
|
||||
) +
|
||||
gsi::method_ext ("set_format_from_filename", &set_format_from_filename, gsi::arg ("filename"),
|
||||
"@brief Select a format from the given file name\n"
|
||||
"\n"
|
||||
"This method will set the format according to the file's extension.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.22. "
|
||||
"Beginning with version 0.23, this method always returns true, since the "
|
||||
"only consumer for the return value, Layout#write, now ignores that "
|
||||
"parameter and automatically determines the compression mode from the file name.\n"
|
||||
"\n"
|
||||
"Starting with version 0.30.8, this method allows specifying the desired format's extension in square brackets "
|
||||
"after the file name (e.g. 'file.txt[def]'). This allows writing files with non-standard extensions. "
|
||||
"The return value of this function now is the actual file name used without the square brackets ('file.txt' in the example case)."
|
||||
) +
|
||||
gsi::method ("format=", &db::SaveLayoutOptions::set_format, gsi::arg ("format"),
|
||||
"@brief Select a format\n"
|
||||
"The format string can be either \"GDS2\", \"OASIS\", \"CIF\" or \"DXF\". Other formats may be available if\n"
|
||||
"a suitable plugin is installed."
|
||||
) +
|
||||
gsi::method ("format", &db::SaveLayoutOptions::format,
|
||||
"@brief Gets the format name\n"
|
||||
"\n"
|
||||
"See \\format= for a description of that method.\n"
|
||||
) +
|
||||
gsi::method ("add_layer", &db::SaveLayoutOptions::add_layer, gsi::arg ("layer_index"), gsi::arg ("properties"),
|
||||
"@brief Add a layer to be saved \n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Adds the layer with the given index to the layer list that will be written.\n"
|
||||
"If all layers have been selected previously, all layers will \n"
|
||||
"be unselected first and only the new layer remains.\n"
|
||||
"\n"
|
||||
"The 'properties' argument can be used to assign different layer properties than the ones\n"
|
||||
"present in the layout. Pass a default \\LayerInfo object to this argument to use the\n"
|
||||
"properties from the layout object. Construct a valid \\LayerInfo object with explicit layer,\n"
|
||||
"datatype and possibly a name to override the properties stored in the layout.\n"
|
||||
) +
|
||||
gsi::method ("select_all_layers", &db::SaveLayoutOptions::select_all_layers,
|
||||
"@brief Select all layers to be saved\n"
|
||||
"\n"
|
||||
"This method will clear all layers selected with \\add_layer so far and set the 'select all layers' flag.\n"
|
||||
"This is the default.\n"
|
||||
) +
|
||||
gsi::method ("deselect_all_layers", &db::SaveLayoutOptions::deselect_all_layers,
|
||||
"@brief Unselect all layers: no layer will be saved\n"
|
||||
"\n"
|
||||
"This method will clear all layers selected with \\add_layer so far and clear the 'select all layers' flag.\n"
|
||||
"Using this method is the only way to save a layout without any layers."
|
||||
) +
|
||||
gsi::method ("select_cell", &db::SaveLayoutOptions::select_cell, gsi::arg ("cell_index"),
|
||||
"@brief Selects a cell to be saved (plus hierarchy below)\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This method is basically a convenience method that combines \\clear_cells and \\add_cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.22.\n"
|
||||
) +
|
||||
gsi::method ("select_this_cell", &db::SaveLayoutOptions::select_this_cell, gsi::arg ("cell_index"),
|
||||
"@brief Selects a cell to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This method is basically a convenience method that combines \\clear_cells and \\add_this_cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("clear_cells", &db::SaveLayoutOptions::clear_cells,
|
||||
"@brief Clears all cells to be saved\n"
|
||||
"\n"
|
||||
"This method can be used to ensure that no cell is selected before \\add_cell is called to specify a cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.22.\n"
|
||||
) +
|
||||
gsi::method ("add_this_cell", &db::SaveLayoutOptions::add_this_cell, gsi::arg ("cell_index"),
|
||||
"@brief Adds a cell to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The index of the cell must be a valid index in the context of the layout that will be saved.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"Unlike \\add_cell, this method does not implicitly add all children of that cell.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("add_cell", &db::SaveLayoutOptions::add_cell, gsi::arg ("cell_index"),
|
||||
"@brief Add a cell (plus hierarchy) to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The index of the cell must be a valid index in the context of the layout that will be saved.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method also implicitly adds the children of that cell. A method that does not add the "
|
||||
"children in \\add_this_cell.\n"
|
||||
) +
|
||||
gsi::method ("select_all_cells", &db::SaveLayoutOptions::select_all_cells,
|
||||
"@brief Select all cells to save\n"
|
||||
"\n"
|
||||
"This method will clear all cells specified with \\add_cells so far and set the 'select all cells' flag.\n"
|
||||
"This is the default.\n"
|
||||
) +
|
||||
gsi::method ("write_context_info=", &db::SaveLayoutOptions::set_write_context_info, gsi::arg ("flag"),
|
||||
"@brief Enables or disables context information\n"
|
||||
"\n"
|
||||
"If this flag is set to false, no context information for PCell or library cell instances is written. "
|
||||
"Those cells will be converted to plain cells and KLayout will not be able to restore the identity of "
|
||||
"those cells. Use this option to enforce compatibility with other tools that don't understand the "
|
||||
"context information of KLayout.\n"
|
||||
"\n"
|
||||
"The default value is true (context information is stored). Not all formats support context information, hence "
|
||||
"that flag has no effect for formats like CIF or DXF.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("write_context_info?", &db::SaveLayoutOptions::write_context_info,
|
||||
"@brief Gets a flag indicating whether context information will be stored\n"
|
||||
"\n"
|
||||
"See \\write_context_info= for details about this flag.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("keep_instances=", &db::SaveLayoutOptions::set_keep_instances, gsi::arg ("flag"),
|
||||
"@brief Enables or disables instances for dropped cells\n"
|
||||
"\n"
|
||||
"If this flag is set to true, instances for cells will be written, even if the cell is dropped. "
|
||||
"That may happen, if cells are selected with \\select_this_cell or \\add_this_cell or \\no_empty_cells is used. "
|
||||
"Even if cells called by such cells are not selected, instances will be written for that "
|
||||
"cell if \"keep_instances\" is true. That feature is supported by the GDS format currently and "
|
||||
"results in \"ghost cells\" which have instances but no cell definition.\n"
|
||||
"\n"
|
||||
"The default value is false (instances of dropped cells are not written).\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("keep_instances?", &db::SaveLayoutOptions::keep_instances,
|
||||
"@brief Gets a flag indicating whether instances will be kept even if the target cell is dropped\n"
|
||||
"\n"
|
||||
"See \\keep_instances= for details about this flag.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("dbu=", &db::SaveLayoutOptions::set_dbu, gsi::arg ("dbu"),
|
||||
"@brief Sets the database unit to be used in the stream file\n"
|
||||
"\n"
|
||||
"By default, the database unit of the layout is used. This method allows one to explicitly use a different\n"
|
||||
"database unit. A scale factor is introduced automatically which scales all layout objects accordingly so their physical dimensions remain the same. "
|
||||
"When scaling to a larger database unit or one that is not an integer fraction of the original one, rounding errors may occur and the "
|
||||
"layout may become slightly distorted."
|
||||
) +
|
||||
gsi::method ("dbu", &db::SaveLayoutOptions::dbu,
|
||||
"@brief Gets the explicit database unit if one is set\n"
|
||||
"\n"
|
||||
"See \\dbu= for a description of that attribute.\n"
|
||||
) +
|
||||
gsi::method ("no_empty_cells=", &db::SaveLayoutOptions::set_dont_write_empty_cells, gsi::arg ("flag"),
|
||||
"@brief Don't write empty cells if this flag is set\n"
|
||||
"\n"
|
||||
"By default, all cells are written (no_empty_cells is false).\n"
|
||||
"This applies to empty cells which do not contain shapes for the specified layers "
|
||||
"as well as cells which are empty because they reference empty cells only.\n"
|
||||
) +
|
||||
gsi::method ("no_empty_cells?", &db::SaveLayoutOptions::dont_write_empty_cells,
|
||||
"@brief Returns a flag indicating whether empty cells are not written.\n"
|
||||
) +
|
||||
gsi::method ("libname=|#gds2_libname=", &db::SaveLayoutOptions::set_libname, gsi::arg ("libname"),
|
||||
"@brief Sets the library name\n"
|
||||
"\n"
|
||||
"The library name is an attribute and specifies a formal name for a library, if the layout files is to be used as one.\n"
|
||||
"Currently, this attribute is only supported by the GDS2 format. Hence the alias.\n"
|
||||
"\n"
|
||||
"By default or if the libname is an empty string, the current library name of the layout or 'LIB' is used.\n"
|
||||
"\n"
|
||||
"The 'libname' alias has been introduced in version 0.30.5. The original name \\gds2_libname= is still available."
|
||||
) +
|
||||
gsi::method ("libname|#gds2_libname", &db::SaveLayoutOptions::libname,
|
||||
"@brief Gets the library name\n"
|
||||
"\n"
|
||||
"See \\libname= for details.\n"
|
||||
"The 'libname' alias has been introduced in version 0.30.5. The original name \\gds2_libname is still available."
|
||||
) +
|
||||
gsi::method ("scale_factor=", &db::SaveLayoutOptions::set_scale_factor, gsi::arg ("scale_factor"),
|
||||
"@brief Sets the scaling factor for the saving \n"
|
||||
"\n"
|
||||
"Using a scaling factor will scale all objects accordingly. "
|
||||
"This scale factor adds to a potential scaling implied by using an explicit database unit.\n"
|
||||
"\n"
|
||||
"Be aware that rounding effects may occur if fractional scaling factors are used.\n"
|
||||
"\n"
|
||||
"By default, no scaling is applied."
|
||||
) +
|
||||
gsi::method ("scale_factor", &db::SaveLayoutOptions::scale_factor,
|
||||
"@brief Gets the scaling factor currently set\n"
|
||||
),
|
||||
"@brief Options for saving layouts\n"
|
||||
"\n"
|
||||
"This class describes the various options for saving a layout to a stream file (GDS2, OASIS and others).\n"
|
||||
"There are: layers to be saved, cell or cells to be saved, scale factor, format, database unit\n"
|
||||
"and format specific options.\n"
|
||||
"\n"
|
||||
"Usually the default constructor provides a suitable object. Please note, that the format written is \"GDS2\" by default. Either explicitly set a "
|
||||
"format using \\format= or derive the format from the file name using \\set_format_from_filename.\n"
|
||||
"\n"
|
||||
"The layers are specified by either selecting all layers or by defining layer by layer using the\n"
|
||||
"\\add_layer method. \\select_all_layers will explicitly select all layers for saving, \\deselect_all_layers will explicitly clear the list of layers.\n"
|
||||
"\n"
|
||||
"Cells are selected in a similar fashion: by default, all cells are selected. Using \\add_cell, specific\n"
|
||||
"cells can be selected for saving. All these cells plus their hierarchy will then be written to the stream file.\n"
|
||||
"\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -102,3 +102,17 @@ TEST(1)
|
|||
EXPECT_EQ (opt.get_option_by_name ("mywriter_value").to_string (), "17");
|
||||
}
|
||||
|
||||
TEST(2)
|
||||
{
|
||||
db::SaveLayoutOptions opt;
|
||||
auto ff = opt.set_format_from_filename ("/home/xyz/test.def");
|
||||
EXPECT_EQ (ff.first, true);
|
||||
EXPECT_EQ (ff.second, "/home/xyz/test.def");
|
||||
EXPECT_EQ (opt.format (), "LEFDEF");
|
||||
|
||||
opt = db::SaveLayoutOptions ();
|
||||
ff = opt.set_format_from_filename ("/home/xyz/test.txt[def]");
|
||||
EXPECT_EQ (ff.first, true);
|
||||
EXPECT_EQ (ff.second, "/home/xyz/test.txt");
|
||||
EXPECT_EQ (opt.format (), "LEFDEF");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ module DRC
|
|||
|
||||
def initialize
|
||||
|
||||
cv = RBA::CellView::active
|
||||
cv = RBA.const_defined?(:CellView) && RBA::CellView::active
|
||||
|
||||
@time = Time::now
|
||||
@force_gc = ($drc_force_gc == true) # for testing, $drc_force_gc can be set to true
|
||||
|
|
@ -1444,7 +1444,7 @@ module DRC
|
|||
|
||||
if arg =~ /^@(\d+)/
|
||||
n = $1.to_i - 1
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||
cv = view.cellview(n)
|
||||
|
|
@ -1543,7 +1543,7 @@ module DRC
|
|||
|
||||
if arg =~ /^@(\d+)/
|
||||
n = $1.to_i - 1
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||
cv = view.cellview(n)
|
||||
|
|
@ -1608,7 +1608,7 @@ module DRC
|
|||
self._context("report") do
|
||||
|
||||
# finish what we got so far
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
@def_output && @def_output.finish(false, view)
|
||||
|
||||
@def_output = nil
|
||||
|
|
@ -2925,7 +2925,7 @@ CODE
|
|||
def _start(job_description)
|
||||
|
||||
# clearing the selection avoids some nasty problems
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
view && view.cancel
|
||||
|
||||
@total_timer = RBA::Timer::new
|
||||
|
|
@ -2950,7 +2950,7 @@ CODE
|
|||
|
||||
_flush
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
|
||||
@def_output && @def_output.finish(final, view)
|
||||
|
||||
|
|
@ -3484,7 +3484,7 @@ CODE
|
|||
|
||||
output_rdb_index = nil
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
if view
|
||||
if self._rdb_index
|
||||
output_rdb = RBA::ReportDatabase::new("") # reuse existing name
|
||||
|
|
@ -3518,7 +3518,7 @@ CODE
|
|||
|
||||
if arg =~ /^@(\d+|\+)/
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
if $1 == "+"
|
||||
prev_cv = view.active_cellview_index
|
||||
|
|
|
|||
|
|
@ -1060,47 +1060,72 @@ ApplicationBase::usage ()
|
|||
{
|
||||
std::string r;
|
||||
r = std::string (lay::Version::exe_name ()) + " [<options>] [<file>] ..\n";
|
||||
r += tl::to_string (QObject::tr ("options")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -b Batch mode (same as -zz -nc -rx)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -c <config file> Use this configuration file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -nc Don't use a configuration file (implies -t)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -d <log level> Set log level")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -e Editable mode (allow editing of files)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -ne Readonly mode (editing of files is disabled)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gr <file name> Record GUI test file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gp <file name> Replay GUI test file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gb <line number> Replay GUI test file up to (including) line")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gx <millisec> Replay rate for GUI test file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gi Incremental logs for GUI test file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -i Disable undo buffering (less memory requirements)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -ni Enable undo buffering (default, overrides previous -i option)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -j <path> Add the given path to the macro project paths")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -k <log file> Write log to the given file plus stdout/stderr")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -l <lyp file> Use layer properties file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -lx With -l: add other layers as well")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -lf With -l: use the lyp file as it is (no expansion to multiple layouts)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -m <database file> Load RDB (report database) file (into previous layout view)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -mn <database file> Load L2NDB (layout to netlist database) file (into previous layout view)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -n <technology> Technology to use for next layout(s) on command line")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -nn <tech file> Technology file (.lyt) to use for next layout(s) on command line")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -p <plugin> Load the plugin (can be used multiple times)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -r <script> Execute main script on startup (after having loaded files etc.)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -rr <script> Like -r, but does not exit after executing the script")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -rm <script> Execute script on startup before loading files (can be used multiple times)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -rd <name>=<value> Specify script variable")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -rx Ignore all implicit macros (*.rbm, rbainit, *.lym)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -s Load files into same view")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -t Don't update the configuration file on exit")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -nt Update the configuration file on exit (default, overrides previous -t option)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -u <file name> Restore session from given file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -v Print program version and exit (also available as --version)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -wd <name>=<value> Define a variable within expressions")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -x Synchronous drawing mode")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -y <package> Package installation: install package(s) and exit - can be used more than once")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" ('package' is a name, an URL and optionally a version in round brackets)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -yd With -y: include dependencies")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -z Non-GUI mode (hidden views)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -zz Non-GUI mode (database only, implies -nc)")) + "\n";
|
||||
r += tl::to_string (tr (
|
||||
"\n"
|
||||
"The format of the input files is usually detected automatically. In some cases, the format is derived from\n"
|
||||
"the file's suffix. If your file does not have the neccessary suffix, you can explicitly specify the format\n"
|
||||
"by adding the respective suffix to the file name in square brackets - e.g. 'file.data[def]' will read\n"
|
||||
"the file 'file.data' as a DEF file.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -b Batch mode (same as -zz -nc -rx)\n"
|
||||
" -c <config file> Use this configuration file\n"
|
||||
" -nc Don't use a configuration file (implies -t)\n"
|
||||
" -d <log level> Set log level\n"
|
||||
" -e Editable mode (allow editing of files)\n"
|
||||
" -ne Readonly mode (editing of files is disabled)\n"
|
||||
" -gr <file name> Record GUI test file\n"
|
||||
" -gp <file name> Replay GUI test file\n"
|
||||
" -gb <line number> Replay GUI test file up to (including) line\n"
|
||||
" -gx <millisec> Replay rate for GUI test file\n"
|
||||
" -gi Incremental logs for GUI test file\n"
|
||||
" -i Disable undo buffering (less memory requirements)\n"
|
||||
" -ni Enable undo buffering (default, overrides previous -i option)\n"
|
||||
" -j <path> Add the given path to the macro project paths\n"
|
||||
" -k <log file> Write log to the given file plus stdout/stderr\n"
|
||||
" -l <lyp file> Use layer properties file\n"
|
||||
" -lx With -l: add other layers as well\n"
|
||||
" -lf With -l: use the lyp file as it is (no expansion to multiple layouts)\n"
|
||||
" -m <database file> Load RDB (report database) file (into previous layout view)\n"
|
||||
" -mn <database file> Load L2NDB (layout to netlist database) file (into previous layout view)\n"
|
||||
" -n <technology> Technology to use for next layout(s) on command line\n"
|
||||
" -nn <tech file> Technology file (.lyt) to use for next layout(s) on command line\n"
|
||||
" -p <plugin> Load the plugin (can be used multiple times)\n"
|
||||
" -r <script> Execute main script on startup (after having loaded files etc.)\n"
|
||||
" -rr <script> Like -r, but does not exit after executing the script\n"
|
||||
" -rm <script> Execute script on startup before loading files (can be used multiple times)\n"
|
||||
" -rd <name>=<value> Specify script variable\n"
|
||||
" -rx Ignore all implicit macros (*.rbm, rbainit, *.lym)\n"
|
||||
" -s Load files into same view\n"
|
||||
" -t Don't update the configuration file on exit\n"
|
||||
" -nt Update the configuration file on exit (default, overrides previous -t option)\n"
|
||||
" -u <file name> Restore session from given file\n"
|
||||
" -v Print program version and exit (also available as --version)\n"
|
||||
" -wd <name>=<value> Define a variable within expressions\n"
|
||||
" -x Synchronous drawing mode\n"
|
||||
" -y <package> Package installation: install package(s) and exit - can be used more than once\n"
|
||||
" ('package' is a name, an URL and optionally a version in round brackets)\n"
|
||||
" -yd With -y: include dependencies\n"
|
||||
" -z Non-GUI mode (hidden views)\n"
|
||||
" -zz Non-GUI mode (database only, implies -nc)\n"
|
||||
"\n"
|
||||
"Environment variables:\n"
|
||||
" KLAYOUT_HOME The path to KLayout's data (configuration, macros, libraries etc.).\n"
|
||||
" Default path is '~/.klayout' on Linux and '%USERPROFILE%\\KLayout' on Windows.\n"
|
||||
" KLAYOUT_PATH A list of locations to look into additionally to KLAYOUT_HOME for macros, libraries etc.\n"
|
||||
" Separator for the locations is ':' on Linux and ';' on Windows.\n"
|
||||
" KLAYOUT_SALT_MINE The package manager repository URL. Default is 'http://sami.klayout.org/repository.xml'.\n"
|
||||
" KLAYOUT_IGNORE_MACRO_DIRS A colon-separated list of folder names to ignore in the macro editor tree.\n"
|
||||
" By default, only '__pycache__' is ignored.\n"
|
||||
" KLAYOUT_LEF_FORMAT A space-separated list of formats to be recognized as LEF files.\n"
|
||||
" By default this format list is '*.lef *.LEF *.lef.gz *.LEF.gz'.\n"
|
||||
" KLAYOUT_DEF_FORMAT A space-separated list of formats to be recognized as DEF files.\n"
|
||||
" By default this format list is '*.def *.DEF *.def.gz *.DEF.gz'.\n"
|
||||
" KLAYOUT_PYTHONPATH The equivalent of PYTHONPATH for KLayout.\n"
|
||||
" KLAYOUT_PYTHONHOME The equivalent of PYTHONHOME for KLayout.\n"
|
||||
" KLAYOUT_HTTP_TIMEOUT The timeout for HTTP(S) requests in seconds. The default value is 10.\n"
|
||||
" KLAYOUT_VERBOSITY The default verbosity (see -d option).\n"
|
||||
));
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2270,7 +2270,7 @@ MainWindow::cm_save_current_cell_as ()
|
|||
|
||||
db::SaveLayoutOptions options (cv->save_options ());
|
||||
options.set_dbu (cv->layout ().dbu ());
|
||||
options.set_format_from_filename (fn);
|
||||
fn = options.set_format_from_filename (fn).second;
|
||||
|
||||
tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto;
|
||||
if (mp_layout_save_as_options->get_options (current_view (), cv_index, fn, om, options)) {
|
||||
|
|
@ -2370,7 +2370,7 @@ MainWindow::do_save (bool as)
|
|||
db::SaveLayoutOptions options = get_save_options_from_cv (cv);
|
||||
|
||||
if (as || options.format ().empty ()) {
|
||||
options.set_format_from_filename (fn);
|
||||
fn = options.set_format_from_filename (fn).second;
|
||||
}
|
||||
|
||||
tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto;
|
||||
|
|
@ -2419,7 +2419,7 @@ MainWindow::cm_save_all ()
|
|||
db::SaveLayoutOptions options = get_save_options_from_cv (cv);
|
||||
|
||||
if (options.format ().empty ()) {
|
||||
options.set_format_from_filename (fn);
|
||||
fn = options.set_format_from_filename (fn).second;
|
||||
}
|
||||
|
||||
tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "tlTimer.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlEnv.h"
|
||||
|
||||
#include "dbReader.h"
|
||||
#include "dbStream.h"
|
||||
|
|
@ -40,44 +41,31 @@ namespace db
|
|||
// ---------------------------------------------------------------
|
||||
// Plugin for the stream reader
|
||||
|
||||
static std::string lef_file_formats ()
|
||||
{
|
||||
static std::string s;
|
||||
if (s.empty ()) {
|
||||
s = tl::get_env ("KLAYOUT_LEF_FORMAT", "*.lef *.LEF *.lef.gz *.LEF.gz");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string def_file_formats ()
|
||||
{
|
||||
static std::string s;
|
||||
if (s.empty ()) {
|
||||
s = tl::get_env ("KLAYOUT_DEF_FORMAT", "*.def *.DEF *.def.gz *.DEF.gz");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the format of the given stream
|
||||
* Returns true, if the stream has LEF format
|
||||
*/
|
||||
static bool is_lef_format (const std::string &fn)
|
||||
{
|
||||
static const char *suffixes[] = { ".lef", ".LEF", ".lef.gz", ".LEF.gz" };
|
||||
|
||||
// NOTE: there is no reliable way of (easily) detecting the format. Hence we use the file
|
||||
// name's suffix for the format hint.
|
||||
for (size_t i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); ++i) {
|
||||
std::string suffix = suffixes [i];
|
||||
if (fn.size () > suffix.size () && fn.find (suffix) == fn.size () - suffix.size ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the format of the given stream
|
||||
* Returns true, if the stream has DEF format
|
||||
*/
|
||||
static bool is_def_format (const std::string &fn)
|
||||
{
|
||||
static const char *suffixes[] = { ".def", ".DEF", ".def.gz", ".DEF.gz" };
|
||||
|
||||
// NOTE: there is no reliable way of (easily) detecting the format. Hence we use the file
|
||||
// name's suffix for the format hint.
|
||||
for (size_t i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); ++i) {
|
||||
std::string suffix = suffixes [i];
|
||||
if (fn.size () > suffix.size () && fn.find (suffix) == fn.size () - suffix.size ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return tl::match_filename_to_format (fn, std::string ("LEF files (") + lef_file_formats () + ")");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
|
@ -92,13 +80,13 @@ LEFDEFReader::LEFDEFReader (tl::InputStream &s)
|
|||
const db::LayerMap &
|
||||
LEFDEFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||
{
|
||||
return read_lefdef (layout, options, is_lef_format (m_stream.filename ()));
|
||||
return read_lefdef (layout, options, is_lef_format ("." + m_stream.suffix ()));
|
||||
}
|
||||
|
||||
const db::LayerMap &
|
||||
LEFDEFReader::read (db::Layout &layout)
|
||||
{
|
||||
return read_lefdef (layout, db::LoadLayoutOptions (), is_lef_format (m_stream.filename ()));
|
||||
return read_lefdef (layout, db::LoadLayoutOptions (), is_lef_format ("." + m_stream.suffix ()));
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
@ -283,11 +271,11 @@ class LEFDEFFormatDeclaration
|
|||
virtual std::string format_name () const { return "LEFDEF"; }
|
||||
virtual std::string format_desc () const { return "LEF/DEF"; }
|
||||
virtual std::string format_title () const { return "LEF/DEF (unified reader)"; }
|
||||
virtual std::string file_format () const { return "LEF/DEF files (*.lef *.LEF *.lef.gz *.LEF.gz *.def *.DEF *.def.gz *.DEF.gz)"; }
|
||||
virtual std::string file_format () const { return std::string ("LEF/DEF files (") + lef_file_formats () + " " + def_file_formats () + ")"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &stream) const
|
||||
{
|
||||
return is_lef_format (stream.filename ()) || is_def_format (stream.filename ());
|
||||
return tl::match_filename_to_format (stream.filename (), file_format ());
|
||||
}
|
||||
|
||||
virtual db::ReaderBase *create_reader (tl::InputStream &s) const
|
||||
|
|
|
|||
|
|
@ -467,15 +467,27 @@ TEST(100)
|
|||
run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false);
|
||||
}
|
||||
|
||||
TEST(101)
|
||||
TEST(101a)
|
||||
{
|
||||
db::LEFDEFReaderOptions opt = default_options ();
|
||||
opt.set_produce_pin_names (true);
|
||||
opt.set_pin_property_name (2);
|
||||
opt.set_cell_outline_layer ("OUTLINE (13/0)");
|
||||
|
||||
run_test (_this, "issue-489", "lef:in.lef+def:in.def", "au.oas", opt, false);
|
||||
}
|
||||
|
||||
TEST(101b)
|
||||
{
|
||||
db::LEFDEFReaderOptions opt = default_options ();
|
||||
opt.set_produce_pin_names (true);
|
||||
opt.set_pin_property_name (2);
|
||||
opt.set_cell_outline_layer ("OUTLINE (13/0)");
|
||||
|
||||
// also with fake suffix
|
||||
run_test (_this, "issue-489", "lef:'in.l[lef]'+def:'in.d[def]'", "au.oas", opt, false);
|
||||
}
|
||||
|
||||
TEST(102)
|
||||
{
|
||||
db::LEFDEFReaderOptions opt = default_options ();
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "tlString.h"
|
||||
#include "tlUri.h"
|
||||
#include "tlHttpStream.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
# include <QByteArray>
|
||||
|
|
@ -304,6 +305,9 @@ InputStream::InputStream (InputStreamBase &delegate)
|
|||
m_bcap = 4096; // initial buffer capacity
|
||||
m_blen = 0;
|
||||
mp_buffer = new char [m_bcap];
|
||||
|
||||
m_explicit_suffix = false;
|
||||
m_suffix = tl::extension (delegate.filename ());
|
||||
}
|
||||
|
||||
InputStream::InputStream (InputStreamBase *delegate)
|
||||
|
|
@ -312,9 +316,14 @@ InputStream::InputStream (InputStreamBase *delegate)
|
|||
m_bcap = 4096; // initial buffer capacity
|
||||
m_blen = 0;
|
||||
mp_buffer = new char [m_bcap];
|
||||
|
||||
m_explicit_suffix = false;
|
||||
if (delegate) {
|
||||
m_suffix = tl::extension (delegate->filename ());
|
||||
}
|
||||
}
|
||||
|
||||
InputStream::InputStream (const std::string &abstract_path)
|
||||
InputStream::InputStream (const std::string &abstract_path_in, bool allow_explicit_suffix)
|
||||
: m_pos (0), mp_bptr (0), mp_delegate (0), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false), m_stop_after_inflate (false)
|
||||
{
|
||||
m_bcap = 4096; // initial buffer capacity
|
||||
|
|
@ -323,6 +332,22 @@ InputStream::InputStream (const std::string &abstract_path)
|
|||
|
||||
bool needs_inflate = false;
|
||||
|
||||
std::string abstract_path = abstract_path_in;
|
||||
m_explicit_suffix = false;
|
||||
|
||||
// extract override suffix if needed
|
||||
if (allow_explicit_suffix) {
|
||||
|
||||
tl::GlobPattern pat ("(*)\\[(*)\\]");
|
||||
std::vector<std::string> pat_parts;
|
||||
if (pat.match (abstract_path_in, pat_parts) && pat_parts.size () == 2) {
|
||||
abstract_path = pat_parts[0];
|
||||
m_suffix = pat_parts[1];
|
||||
m_explicit_suffix = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tl::Extractor ex (abstract_path.c_str ());
|
||||
|
||||
if (ex.test (":")) {
|
||||
|
|
@ -404,6 +429,10 @@ InputStream::InputStream (const std::string &abstract_path)
|
|||
|
||||
m_owns_delegate = true;
|
||||
|
||||
if (mp_delegate && ! m_explicit_suffix) {
|
||||
m_suffix = tl::extension (mp_delegate->filename ());
|
||||
}
|
||||
|
||||
if (needs_inflate) {
|
||||
inflate_always ();
|
||||
}
|
||||
|
|
@ -1696,7 +1725,7 @@ match_filename_to_format (const std::string &fn, const std::string &fmt)
|
|||
while (*fpp && *fpp != ' ' && *fpp != ')') {
|
||||
++fpp;
|
||||
}
|
||||
if (fn.size () > (unsigned int) (fpp - fp) && strncmp (fn.c_str () + fn.size () - (fpp - fp), fp, fpp - fp) == 0) {
|
||||
if (fn.size () >= (unsigned int) (fpp - fp) && strncmp (fn.c_str () + fn.size () - (fpp - fp), fp, fpp - fp) == 0) {
|
||||
return true;
|
||||
}
|
||||
fp = fpp;
|
||||
|
|
|
|||
|
|
@ -408,9 +408,14 @@ public:
|
|||
* This will automatically create the appropriate delegate and
|
||||
* delete it later.
|
||||
*
|
||||
* The abstract path
|
||||
* @param abstract_path The abstract path (can be "pipe:<cmd>", "data:<base64-data>", "file:...", "http(s):...".
|
||||
* @param allow_explicit_suffix If true, extracts the suffix from the abstract path
|
||||
*
|
||||
* With explicit suffix, the abstract path can be appended an override suffix in the
|
||||
* form "path[suffix]" (e.g. "file.any[gds]"). The override suffix can be accessed with
|
||||
* the "suffix" accessor. If an explicit suffix is given, "is_explicit_suffix" is true.
|
||||
*/
|
||||
InputStream (const std::string &abstract_path);
|
||||
InputStream (const std::string &abstract_path, bool allow_explicit_suffix = true);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
@ -528,6 +533,25 @@ public:
|
|||
return mp_delegate->absolute_path ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the suffix
|
||||
*
|
||||
* The suffix is either the override suffix or the
|
||||
* filename's suffix if no override is given.
|
||||
*/
|
||||
const std::string &suffix () const
|
||||
{
|
||||
return m_suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating if an explicit suffix is given
|
||||
*/
|
||||
bool is_explicit_suffix () const
|
||||
{
|
||||
return m_explicit_suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset to the initial position
|
||||
*/
|
||||
|
|
@ -593,6 +617,9 @@ private:
|
|||
InputStreamBase *mp_delegate;
|
||||
bool m_owns_delegate;
|
||||
|
||||
std::string m_suffix;
|
||||
bool m_explicit_suffix;
|
||||
|
||||
// inflate support
|
||||
InflateFilter *mp_inflate;
|
||||
bool m_inflate_always;
|
||||
|
|
|
|||
|
|
@ -187,6 +187,29 @@ TEST(DataInputStream)
|
|||
EXPECT_EQ (tis.get_line (), "separated by a LFCR and CRLF.");
|
||||
EXPECT_EQ (tis.line_number (), size_t (4));
|
||||
EXPECT_EQ (tis.at_end (), true);
|
||||
|
||||
EXPECT_EQ (is.is_explicit_suffix (), false);
|
||||
EXPECT_EQ (is.suffix (), "");
|
||||
}
|
||||
|
||||
TEST(DataInputStreamWithSuffix)
|
||||
{
|
||||
tl::InputStream is ("data:SGVsbG8sIHdvcmxkIQpXaXRoIGFub3RoZXIgbGluZQoNDQpzZXBhcmF0ZWQgYnkgYSBMRkNSIGFuZCBDUkxGLg==[txt]");
|
||||
tl::TextInputStream tis (is);
|
||||
EXPECT_EQ (tis.get_line (), "Hello, world!");
|
||||
EXPECT_EQ (tis.line_number (), size_t (1));
|
||||
EXPECT_EQ (tis.get_line (), "With another line");
|
||||
EXPECT_EQ (tis.line_number (), size_t (2));
|
||||
EXPECT_EQ (tis.peek_char (), '\n');
|
||||
EXPECT_EQ (tis.get_line (), "");
|
||||
EXPECT_EQ (tis.line_number (), size_t (3));
|
||||
EXPECT_EQ (tis.peek_char (), 's');
|
||||
EXPECT_EQ (tis.get_line (), "separated by a LFCR and CRLF.");
|
||||
EXPECT_EQ (tis.line_number (), size_t (4));
|
||||
EXPECT_EQ (tis.at_end (), true);
|
||||
|
||||
EXPECT_EQ (is.is_explicit_suffix (), true);
|
||||
EXPECT_EQ (is.suffix (), "txt");
|
||||
}
|
||||
|
||||
namespace
|
||||
|
|
@ -588,3 +611,16 @@ TEST(AbstractPathFunctions)
|
|||
EXPECT_EQ (tl::InputStream::as_file_path ("a\\b\\c"), "a\\b\\c");
|
||||
tl::file_utils_force_reset ();
|
||||
}
|
||||
|
||||
TEST(MatchFormat)
|
||||
{
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.txt", "Text files (*.txt *.TXT)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.txt", "Text files (*.txt)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.txt", "Text files (*.TXT)"), false);
|
||||
EXPECT_EQ (tl::match_filename_to_format (".txt", "Text files (*.txt *.TXT)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("/home/xyz/abc.txt", "Text files (*.txt *.TXT)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("txt", "Text files (*.txt *.TXT)"), false);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.TXT", "Text files (*.txt *.TXT)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.TEXT", "Text files (*.txt *.TXT)"), false);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.TEXT", "Text files (*)"), true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
# This is a smoke test
|
||||
deep
|
||||
|
||||
puts("This is DRC.")
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
VERSION 5.7 ;
|
||||
DIVIDERCHAR "/" ;
|
||||
BUSBITCHARS "[]" ;
|
||||
DESIGN test ;
|
||||
UNITS DISTANCE MICRONS 2000 ;
|
||||
|
||||
DIEAREA ( 0 0 ) ( 37520 7840 ) ;
|
||||
|
||||
PINS 12 ;
|
||||
- VDD + NET VDD + SPECIAL + DIRECTION INOUT + USE POWER
|
||||
+ LAYER M2 ( -320 0 ) ( 320 37520 )
|
||||
+ FIXED ( 37520 3920 ) W ;
|
||||
- VSS + NET VSS + SPECIAL + DIRECTION INOUT + USE GROUND
|
||||
+ PORT
|
||||
+ LAYER M2 ( -18760 0 ) ( 18760 640 )
|
||||
+ FIXED ( 18760 -320 ) N
|
||||
+ PORT
|
||||
+ LAYER M2 ( -18760 0 ) ( 18760 640 )
|
||||
+ FIXED ( 18760 8160 ) S
|
||||
;
|
||||
END PINS
|
||||
|
||||
SPECIALNETS 4 ;
|
||||
- VSS ( * VSS )
|
||||
+ ROUTED M2 640 + SHAPE FOLLOWPIN ( 0 0 ) ( 37520 * )
|
||||
NEW M2 640 + SHAPE FOLLOWPIN ( 0 7840 ) ( 37520 * )
|
||||
+ USE GROUND
|
||||
;
|
||||
- VDD ( * VDD )
|
||||
+ ROUTED M2 640 + SHAPE FOLLOWPIN ( 0 3920 ) ( 37520 * )
|
||||
+ USE POWER
|
||||
;
|
||||
END SPECIALNETS
|
||||
END DESIGN
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
VERSION 5.7 ;
|
||||
|
||||
BUSBITCHARS "[]" ;
|
||||
DIVIDERCHAR "/" ;
|
||||
UNITS
|
||||
DATABASE MICRONS 1000 ;
|
||||
END UNITS
|
||||
|
||||
MANUFACTURINGGRID 0.002 ;
|
||||
|
||||
USEMINSPACING OBS OFF ;
|
||||
|
||||
LAYER overlap
|
||||
TYPE OVERLAP ;
|
||||
END overlap
|
||||
|
||||
LAYER contact
|
||||
TYPE CUT ;
|
||||
END contact
|
||||
|
||||
LAYER metal1
|
||||
TYPE ROUTING ;
|
||||
DIRECTION HORIZONTAL ;
|
||||
END metal1
|
||||
|
||||
LAYER via1
|
||||
TYPE CUT ;
|
||||
END via1
|
||||
|
||||
LAYER metal2
|
||||
TYPE ROUTING ;
|
||||
DIRECTION VERTICAL ;
|
||||
END metal2
|
||||
|
||||
LAYER via2
|
||||
TYPE CUT ;
|
||||
END via2
|
||||
|
||||
LAYER metal3
|
||||
TYPE ROUTING ;
|
||||
DIRECTION HORIZONTAL ;
|
||||
END metal3
|
||||
|
||||
LAYER via3
|
||||
TYPE CUT ;
|
||||
END via3
|
||||
|
||||
LAYER metal4
|
||||
TYPE ROUTING ;
|
||||
DIRECTION VERTICAL ;
|
||||
END metal4
|
||||
|
||||
LAYER via4
|
||||
TYPE CUT ;
|
||||
END via4
|
||||
|
||||
LAYER metal5
|
||||
TYPE ROUTING ;
|
||||
DIRECTION HORIZONTAL ;
|
||||
END metal5
|
||||
|
||||
|
||||
END LIBRARY
|
||||
Binary file not shown.
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
VERSION 5.6 ;
|
||||
NAMESCASESENSITIVE ON ;
|
||||
DIVIDERCHAR "/" ;
|
||||
BUSBITCHARS "<>" ;
|
||||
DESIGN SMALL ;
|
||||
UNITS DISTANCE MICRONS 100 ;
|
||||
|
||||
DIEAREA ( -30 -30 ) ( 1030 1030 ) ;
|
||||
|
||||
VIAS 1 ;
|
||||
- via1_960x340
|
||||
+ VIARULE Via1Array-0
|
||||
+ CUTSIZE 140 140
|
||||
+ LAYERS metal1 via1 metal2
|
||||
+ CUTSPACING 160 160
|
||||
+ ENCLOSURE 110 100 110 100
|
||||
+ ROWCOL 1 3
|
||||
;
|
||||
END VIAS
|
||||
|
||||
SPECIALNETS 1 ;
|
||||
- VDD ( * VDD )
|
||||
+ ROUTED metal1 0 + SHAPE STRIPE ( 500 500 ) via1_960x340
|
||||
+ USE POWER ;
|
||||
END SPECIALNETS
|
||||
|
||||
END DESIGN
|
||||
|
||||
Loading…
Reference in New Issue