mirror of https://github.com/KLayout/klayout.git
Merge pull request #396 from KLayout/issue-387
Implemented issue-387 (python version in grain.xml)
This commit is contained in:
commit
65b0752c5c
|
|
@ -279,7 +279,7 @@
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>API version</string>
|
<string>API features</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
|
@ -842,7 +842,7 @@
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>(API version required - i.e. "0.25")</string>
|
<string>(API version and features - e.g. "0.26; ruby 2.0")</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
||||||
|
|
@ -305,6 +305,33 @@ SaltGrain::valid_name (const std::string &n)
|
||||||
return res == n;
|
return res == n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SaltGrain::valid_api_version (const std::string &v)
|
||||||
|
{
|
||||||
|
tl::Extractor ex (v.c_str ());
|
||||||
|
|
||||||
|
while (! ex.at_end ()) {
|
||||||
|
|
||||||
|
std::string feature;
|
||||||
|
ex.try_read_name (feature);
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
while (! ex.at_end () && ! ex.test (";")) {
|
||||||
|
int n = 0;
|
||||||
|
if (! first && ! ex.test (".")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (! ex.try_read (n)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SaltGrain::valid_version (const std::string &v)
|
SaltGrain::valid_version (const std::string &v)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,11 @@ public:
|
||||||
* The API version is the KLayout version required to run the grain's macros.
|
* The API version is the KLayout version required to run the grain's macros.
|
||||||
* A version string is of the form "x.y..." where x, y and other version
|
* A version string is of the form "x.y..." where x, y and other version
|
||||||
* components are integer numbers.
|
* components are integer numbers.
|
||||||
|
*
|
||||||
|
* The version string can also list other features such as ruby version etc.
|
||||||
|
* The components are separated with a semicolon.
|
||||||
|
* For example, "0.26; ruby; python 3.0" means: requires KLayout API 0.26,
|
||||||
|
* ruby (any version) any python (>= 3.0).
|
||||||
*/
|
*/
|
||||||
const std::string &api_version () const
|
const std::string &api_version () const
|
||||||
{
|
{
|
||||||
|
|
@ -433,6 +438,11 @@ public:
|
||||||
*/
|
*/
|
||||||
static bool valid_version (const std::string &v);
|
static bool valid_version (const std::string &v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a value indicating whether the given version string is a valid API version string
|
||||||
|
*/
|
||||||
|
static bool valid_api_version (const std::string &v);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks whether the given string is a valid name
|
* @brief Checks whether the given string is a valid name
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ SaltGrainDetailsTextWidget::details_text ()
|
||||||
|
|
||||||
stream << "<p>";
|
stream << "<p>";
|
||||||
if (! g->api_version ().empty ()) {
|
if (! g->api_version ().empty ()) {
|
||||||
stream << "<b>" << QObject::tr ("API version") << ":</b> " << tl::to_qstring (tl::escaped_to_html (g->api_version ())) << " ";
|
stream << "<b>" << QObject::tr ("API version and features") << ":</b> " << tl::to_qstring (tl::escaped_to_html (g->api_version ())) << " ";
|
||||||
}
|
}
|
||||||
stream << "</p>";
|
stream << "</p>";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -529,8 +529,8 @@ SaltGrainPropertiesDialog::accept ()
|
||||||
|
|
||||||
// API version
|
// API version
|
||||||
api_version_alert->clear ();
|
api_version_alert->clear ();
|
||||||
if (! m_grain.api_version ().empty () && ! SaltGrain::valid_version (m_grain.api_version ())) {
|
if (! m_grain.api_version ().empty () && ! SaltGrain::valid_api_version (m_grain.api_version ())) {
|
||||||
api_version_alert->error () << tr ("'%1' is not a valid API version string. An API version string needs to be numeric (like '0.25'').").arg (tl::to_qstring (m_grain.api_version ()));
|
api_version_alert->error () << tr ("'%1' is not a valid API version string. An API version string needs to be a semicolon-separated list of features with optional numeric versions (like '0.26' or 'ruby 2.0; python').").arg (tl::to_qstring (m_grain.api_version ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// doc URL
|
// doc URL
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@
|
||||||
#include "tlString.h"
|
#include "tlString.h"
|
||||||
#include "tlExceptions.h"
|
#include "tlExceptions.h"
|
||||||
|
|
||||||
|
#include "rba.h"
|
||||||
|
#include "pya.h"
|
||||||
|
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
@ -108,6 +111,176 @@ private:
|
||||||
lay::Salt *mp_salt;
|
lay::Salt *mp_salt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// SaltAPIVersionCheck
|
||||||
|
|
||||||
|
class SaltAPIVersionCheck
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct APIFeature
|
||||||
|
{
|
||||||
|
APIFeature (const std::string &_name, const std::string &_version, const std::string &_description)
|
||||||
|
: name (_name), version (_version), description (_description)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name, version, description;
|
||||||
|
};
|
||||||
|
|
||||||
|
SaltAPIVersionCheck ();
|
||||||
|
bool check (const std::string &api_version);
|
||||||
|
|
||||||
|
const std::string &message () const
|
||||||
|
{
|
||||||
|
return m_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<APIFeature> m_features;
|
||||||
|
std::string m_message;
|
||||||
|
|
||||||
|
void populate_features ();
|
||||||
|
const APIFeature *find_feature (const std::string &name) const;
|
||||||
|
std::string feature_list () const;
|
||||||
|
};
|
||||||
|
|
||||||
|
SaltAPIVersionCheck::SaltAPIVersionCheck ()
|
||||||
|
{
|
||||||
|
populate_features ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SaltAPIVersionCheck::check (const std::string &api_version)
|
||||||
|
{
|
||||||
|
tl::Extractor ex (api_version.c_str ());
|
||||||
|
|
||||||
|
bool any_not_available = false;
|
||||||
|
bool good = true;
|
||||||
|
m_message.clear ();
|
||||||
|
|
||||||
|
while (! ex.at_end ()) {
|
||||||
|
|
||||||
|
std::string fname;
|
||||||
|
ex.try_read_name (fname);
|
||||||
|
|
||||||
|
std::string v;
|
||||||
|
while (! ex.at_end () && ! ex.test (";")) {
|
||||||
|
int n = 0;
|
||||||
|
if (ex.try_read (n)) {
|
||||||
|
v += tl::to_string (n);
|
||||||
|
} else if (ex.test (".")) {
|
||||||
|
v += ".";
|
||||||
|
} else {
|
||||||
|
m_message = tl::to_string (tr ("API version string malformed - cannot check."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIFeature *f = find_feature (fname);
|
||||||
|
if (!f) {
|
||||||
|
|
||||||
|
if (! m_message.empty ()) {
|
||||||
|
m_message += "\n";
|
||||||
|
}
|
||||||
|
m_message += tl::sprintf (tl::to_string (tr ("Feature %s not available.")), fname);
|
||||||
|
|
||||||
|
good = false;
|
||||||
|
any_not_available = true;
|
||||||
|
|
||||||
|
} else if (! f->version.empty () && ! v.empty () && SaltGrain::compare_versions (f->version, v) < 0) {
|
||||||
|
|
||||||
|
// shorten the version (Python reports "3.6.7 blabla...")
|
||||||
|
std::vector<std::string> fv = tl::split (f->version, " ");
|
||||||
|
tl_assert (! fv.empty ());
|
||||||
|
std::string fv_short = fv.front ();
|
||||||
|
if (fv.size () > 1) {
|
||||||
|
fv_short += " ...";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! m_message.empty ()) {
|
||||||
|
m_message += "\n";
|
||||||
|
}
|
||||||
|
m_message += tl::sprintf (tl::to_string (tr ("%s required with version %s or later (is %s).")), f->description, v, fv_short);
|
||||||
|
|
||||||
|
good = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any_not_available) {
|
||||||
|
m_message += tl::sprintf (tl::to_string (tr ("\nAvailable features are: %s.")), feature_list ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return good;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
SaltAPIVersionCheck::feature_list () const
|
||||||
|
{
|
||||||
|
std::string fl;
|
||||||
|
for (std::vector<APIFeature>::const_iterator f = m_features.begin (); f != m_features.end (); ++f) {
|
||||||
|
if (! fl.empty ()) {
|
||||||
|
fl += ", ";
|
||||||
|
}
|
||||||
|
fl += f->name;
|
||||||
|
}
|
||||||
|
return fl;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SaltAPIVersionCheck::APIFeature *
|
||||||
|
SaltAPIVersionCheck::find_feature (const std::string &name) const
|
||||||
|
{
|
||||||
|
for (std::vector<APIFeature>::const_iterator f = m_features.begin (); f != m_features.end (); ++f) {
|
||||||
|
if (f->name == name) {
|
||||||
|
return f.operator-> ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SaltAPIVersionCheck::populate_features ()
|
||||||
|
{
|
||||||
|
m_features.push_back (APIFeature (std::string (), lay::Version::version (), "KLayout API"));
|
||||||
|
|
||||||
|
if (rba::RubyInterpreter::instance () && rba::RubyInterpreter::instance ()->available ()) {
|
||||||
|
std::string v = rba::RubyInterpreter::instance ()->version ();
|
||||||
|
m_features.push_back (APIFeature ("ruby", v, "Ruby"));
|
||||||
|
if (SaltGrain::compare_versions (v, "2") < 0) {
|
||||||
|
m_features.push_back (APIFeature ("ruby1", v, "Ruby 1"));
|
||||||
|
} else if (SaltGrain::compare_versions (v, "3") < 0) {
|
||||||
|
m_features.push_back (APIFeature ("ruby2", v, "Ruby 2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pya::PythonInterpreter::instance () && pya::PythonInterpreter::instance ()->available ()) {
|
||||||
|
std::string v = pya::PythonInterpreter::instance ()->version ();
|
||||||
|
m_features.push_back (APIFeature ("python", v, "Python"));
|
||||||
|
if (SaltGrain::compare_versions (v, "3") < 0) {
|
||||||
|
m_features.push_back (APIFeature ("python2", v, "Python 2"));
|
||||||
|
} else if (SaltGrain::compare_versions (v, "4") < 0) {
|
||||||
|
m_features.push_back (APIFeature ("python3", v, "Python 3"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_QTBINDINGS)
|
||||||
|
m_features.push_back (APIFeature ("qt_binding", std::string (), "Qt Binding for RBA or PYA"));
|
||||||
|
#endif
|
||||||
|
#if defined(HAVE_QT)
|
||||||
|
# if QT_VERSION >= 0x040000 && QT_VERSION < 0x050000
|
||||||
|
m_features.push_back (APIFeature ("qt4", std::string (), "Qt 4"));
|
||||||
|
# elif QT_VERSION >= 0x050000 && QT_VERSION < 0x060000
|
||||||
|
m_features.push_back (APIFeature ("qt5", std::string (), "Qt 5"));
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_64BIT_COORD)
|
||||||
|
m_features.push_back (APIFeature ("wide-coords", std::string (), "64 bit coordinates"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// SaltManager implementation
|
// SaltManager implementation
|
||||||
|
|
||||||
|
|
@ -790,6 +963,7 @@ SaltManagerDialog::update_models ()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SaltAPIVersionCheck svc;
|
||||||
SaltModel *mine_model;
|
SaltModel *mine_model;
|
||||||
|
|
||||||
mine_model = dynamic_cast <SaltModel *> (salt_mine_view_update->model ());
|
mine_model = dynamic_cast <SaltModel *> (salt_mine_view_update->model ());
|
||||||
|
|
@ -817,8 +991,8 @@ SaltManagerDialog::update_models ()
|
||||||
|
|
||||||
// Establish a message indicating whether the API version does not match
|
// Establish a message indicating whether the API version does not match
|
||||||
for (Salt::flat_iterator g = m_salt_mine.begin_flat (); g != m_salt_mine.end_flat (); ++g) {
|
for (Salt::flat_iterator g = m_salt_mine.begin_flat (); g != m_salt_mine.end_flat (); ++g) {
|
||||||
if (SaltGrain::compare_versions (lay::Version::version (), (*g)->api_version ()) < 0) {
|
if (! svc.check ((*g)->api_version ())) {
|
||||||
mine_model->set_message ((*g)->name (), SaltModel::Warning, tl::to_string (tr ("This package requires a newer API (%1)").arg (tl::to_qstring ((*g)->api_version ()))));
|
mine_model->set_message ((*g)->name (), SaltModel::Warning, svc.message ());
|
||||||
mine_model->set_enabled ((*g)->name (), false);
|
mine_model->set_enabled ((*g)->name (), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -848,8 +1022,8 @@ SaltManagerDialog::update_models ()
|
||||||
|
|
||||||
// Establish a message indicating whether the API version does not match
|
// Establish a message indicating whether the API version does not match
|
||||||
for (Salt::flat_iterator g = m_salt_mine.begin_flat (); g != m_salt_mine.end_flat (); ++g) {
|
for (Salt::flat_iterator g = m_salt_mine.begin_flat (); g != m_salt_mine.end_flat (); ++g) {
|
||||||
if (SaltGrain::compare_versions (lay::Version::version (), (*g)->api_version ()) < 0) {
|
if (! svc.check ((*g)->api_version ())) {
|
||||||
mine_model->set_message ((*g)->name (), SaltModel::Warning, tl::to_string (tr ("This package requires a newer API (%1)").arg (tl::to_qstring ((*g)->api_version ()))));
|
mine_model->set_message ((*g)->name (), SaltModel::Warning, svc.message ());
|
||||||
mine_model->set_enabled ((*g)->name (), false);
|
mine_model->set_enabled ((*g)->name (), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1023,6 +1023,15 @@ Extractor::read_word (std::string &value, const char *non_term)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Extractor &
|
||||||
|
Extractor::read_name (std::string &value, const char *non_term)
|
||||||
|
{
|
||||||
|
if (! try_read_name (value, non_term)) {
|
||||||
|
error (tl::to_string (tr ("Expected a name string")));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Extractor &
|
Extractor &
|
||||||
Extractor::read_word_or_quoted (std::string &value, const char *non_term)
|
Extractor::read_word_or_quoted (std::string &value, const char *non_term)
|
||||||
{
|
{
|
||||||
|
|
@ -1227,6 +1236,31 @@ Extractor::try_read (bool &value)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Extractor::try_read_name (std::string &string, const char *non_term)
|
||||||
|
{
|
||||||
|
if (! *skip ()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string.clear ();
|
||||||
|
|
||||||
|
// first character must not be a digit
|
||||||
|
if (*m_cp && (safe_isalpha (*m_cp) || strchr (non_term, *m_cp) != NULL)) {
|
||||||
|
string += *m_cp;
|
||||||
|
++m_cp;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*m_cp && (safe_isalnum (*m_cp) || strchr (non_term, *m_cp) != NULL)) {
|
||||||
|
string += *m_cp;
|
||||||
|
++m_cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ! string.empty ();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Extractor::try_read_word (std::string &string, const char *non_term)
|
Extractor::try_read_word (std::string &string, const char *non_term)
|
||||||
{
|
{
|
||||||
|
|
@ -1235,10 +1269,12 @@ Extractor::try_read_word (std::string &string, const char *non_term)
|
||||||
}
|
}
|
||||||
|
|
||||||
string.clear ();
|
string.clear ();
|
||||||
|
|
||||||
while (*m_cp && (safe_isalnum (*m_cp) || strchr (non_term, *m_cp) != NULL)) {
|
while (*m_cp && (safe_isalnum (*m_cp) || strchr (non_term, *m_cp) != NULL)) {
|
||||||
string += *m_cp;
|
string += *m_cp;
|
||||||
++m_cp;
|
++m_cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ! string.empty ();
|
return ! string.empty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -528,6 +528,13 @@ public:
|
||||||
*/
|
*/
|
||||||
Extractor &read (std::string &value, const char *term = "");
|
Extractor &read (std::string &value, const char *term = "");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a name string
|
||||||
|
*
|
||||||
|
* Name strings are like words, but for the first character digits are not allowed.
|
||||||
|
*/
|
||||||
|
Extractor &read_name (std::string &value, const char *non_term = "_.$");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read a string consisting of "word" characters
|
* @brief Read a string consisting of "word" characters
|
||||||
*
|
*
|
||||||
|
|
@ -610,6 +617,13 @@ public:
|
||||||
*/
|
*/
|
||||||
bool try_read (std::string &string, const char *term = "");
|
bool try_read (std::string &string, const char *term = "");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to read a name string
|
||||||
|
*
|
||||||
|
* Name strings are like words, but for the first character digits are not allowed.
|
||||||
|
*/
|
||||||
|
bool try_read_name (std::string &value, const char *non_term = "_.$");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Try to read a string consisting of "word" characters
|
* @brief Try to read a string consisting of "word" characters
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -312,23 +312,49 @@ TEST(8)
|
||||||
x = Extractor ("a_word!");
|
x = Extractor ("a_word!");
|
||||||
x.read_word (s);
|
x.read_word (s);
|
||||||
EXPECT_EQ (s, "a_word");
|
EXPECT_EQ (s, "a_word");
|
||||||
|
|
||||||
|
x = Extractor ("a_word!");
|
||||||
|
s.clear ();
|
||||||
|
x.read_name (s);
|
||||||
|
EXPECT_EQ (s, "a_word");
|
||||||
EXPECT_EQ (x.test ("!"), true);
|
EXPECT_EQ (x.test ("!"), true);
|
||||||
|
|
||||||
|
x = Extractor ("0_word!");
|
||||||
|
EXPECT_EQ (x.try_read_word (s), true);
|
||||||
|
|
||||||
|
x = Extractor ("0_word!");
|
||||||
|
EXPECT_EQ (x.try_read_name (s), false);
|
||||||
|
|
||||||
x = Extractor ("a_word!");
|
x = Extractor ("a_word!");
|
||||||
EXPECT_EQ (x.try_read_word (s), true);
|
EXPECT_EQ (x.try_read_word (s), true);
|
||||||
EXPECT_EQ (s, "a_word");
|
EXPECT_EQ (s, "a_word");
|
||||||
EXPECT_EQ (x.test ("!"), true);
|
EXPECT_EQ (x.test ("!"), true);
|
||||||
|
|
||||||
|
x = Extractor ("a_word!");
|
||||||
|
EXPECT_EQ (x.try_read_name (s), true);
|
||||||
|
EXPECT_EQ (s, "a_word");
|
||||||
|
EXPECT_EQ (x.test ("!"), true);
|
||||||
|
|
||||||
x = Extractor ("a_word!");
|
x = Extractor ("a_word!");
|
||||||
x.read_word (s, "_!");
|
x.read_word (s, "_!");
|
||||||
EXPECT_EQ (s, "a_word!");
|
EXPECT_EQ (s, "a_word!");
|
||||||
EXPECT_EQ (x.at_end (), true);
|
EXPECT_EQ (x.at_end (), true);
|
||||||
|
|
||||||
|
x = Extractor ("a_word!");
|
||||||
|
x.read_name (s, "_!");
|
||||||
|
EXPECT_EQ (s, "a_word!");
|
||||||
|
EXPECT_EQ (x.at_end (), true);
|
||||||
|
|
||||||
x = Extractor ("a_word!");
|
x = Extractor ("a_word!");
|
||||||
EXPECT_EQ (x.try_read_word (s, "_!"), true);
|
EXPECT_EQ (x.try_read_word (s, "_!"), true);
|
||||||
EXPECT_EQ (s, "a_word!");
|
EXPECT_EQ (s, "a_word!");
|
||||||
EXPECT_EQ (x.at_end (), true);
|
EXPECT_EQ (x.at_end (), true);
|
||||||
|
|
||||||
|
x = Extractor ("a_word!");
|
||||||
|
EXPECT_EQ (x.try_read_name (s, "_!"), true);
|
||||||
|
EXPECT_EQ (s, "a_word!");
|
||||||
|
EXPECT_EQ (x.at_end (), true);
|
||||||
|
|
||||||
x = Extractor ("a_word!");
|
x = Extractor ("a_word!");
|
||||||
x.read_word_or_quoted (s);
|
x.read_word_or_quoted (s);
|
||||||
EXPECT_EQ (s, "a_word");
|
EXPECT_EQ (s, "a_word");
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# This script is sourced to define the main version parameters
|
# This script is sourced to define the main version parameters
|
||||||
|
|
||||||
# The main version
|
# The main version
|
||||||
KLAYOUT_VERSION="0.26"
|
KLAYOUT_VERSION="0.26.1"
|
||||||
|
|
||||||
# The build date
|
# The build date
|
||||||
KLAYOUT_VERSION_DATE=$(date "+%Y-%m-%d")
|
KLAYOUT_VERSION_DATE=$(date "+%Y-%m-%d")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue