Allowing to explicity specify a format

Most tools and functions now allow to explicitly
specify a format for input and output. On input,
the format is usually detected, but for some
cases, this is not possible (e.g. DEF). So you can
specify the format attached to the file name in
square brackets:

e.g. file.defok[def]

"def" is the intended suffix, "defok" is the given one.

On output, the same is possible, specifically in strmxor
and strmclip:

strmxor a.gds b.gds out.xor[oas]
This commit is contained in:
Matthias Koefferlein 2026-03-20 16:30:28 +01:00
parent 00c826688f
commit 2dfcc9293e
26 changed files with 425 additions and 76 deletions

View File

@ -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);
}

View File

@ -587,10 +587,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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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));

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
@ -2868,12 +2869,13 @@ static db::SaveLayoutOptions *new_v ()
return new db::SaveLayoutOptions ();
}
static bool set_format_from_filename (db::SaveLayoutOptions *opt, const std::string &fn)
static std::string set_format_from_filename (db::SaveLayoutOptions *opt, const std::string &fn)
{
if (! opt->set_format_from_filename (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 true;
return ff.second;
}
Class<db::SaveLayoutOptions> decl_SaveLayoutOptions ("db", "SaveLayoutOptions",
@ -2893,6 +2895,10 @@ Class<db::SaveLayoutOptions> decl_SaveLayoutOptions ("db", "SaveLayoutOptions",
"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.7, 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 the is 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"

View File

@ -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");
}

View File

@ -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;

View File

@ -46,38 +46,8 @@ namespace db
*/
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;
static std::string lef_format ("LEF files (*.lef *.LEF *.lef.gz *.LEF.gz)");
return tl::match_filename_to_format (fn, lef_format);
}
// ---------------------------------------------------------------
@ -92,13 +62,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 *
@ -287,7 +257,7 @@ class LEFDEFFormatDeclaration
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

View File

@ -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 ();

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

34
testdata/lefdef/issue-489/in.d vendored Normal file
View File

@ -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

63
testdata/lefdef/issue-489/in.l vendored Normal file
View File

@ -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

BIN
testdata/lefdef/strm2oas_small/au.gds vendored Normal file

Binary file not shown.

29
testdata/lefdef/strm2oas_small/in.defok vendored Normal file
View File

@ -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