This commit is contained in:
2020-06-02 13:05:39 +03:00
6 changed files with 221 additions and 4 deletions

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(pip)
set(_PIP_MAJOR 1)
set(_PIP_MINOR 17)
set(_PIP_MINOR 18)
set(_PIP_REVISION 0)
set(_PIP_SUFFIX alpha)
set(_PIP_COMPANY SHS)

View File

@@ -30,3 +30,7 @@ You should add ${<out_var>} to your target.
Generate C++ files for resource file.
You should add ${<out_var>} to your target.
## Documentation
[Online documentation](https://shs.tools/pip/html/index.html)

View File

@@ -211,6 +211,16 @@ piCout << s.find("3"); // 9
piCout << s.find("3", 4); // 9
piCout << s.find("3", 10); // -1
//! [PIString::findLast]
//! [PIString::findAny]
piCout << PIString("1.str").findAny(".,:"); // 1
piCout << PIString("1,str").findAny(".,:"); // 1
piCout << PIString("1:str").findAny(".,:"); // 1
//! [PIString::findAny]
//! [PIString::findAnyLast]
piCout << PIString("str.0").findAny(".,:"); // 3
piCout << PIString("str,0").findAny(".,:"); // 3
piCout << PIString("str:0").findAny(".,:"); // 3
//! [PIString::findAnyLast]
//! [PIString::findWord]
PIString s("this is <PIP>");
piCout << s.find("this"); // 0

View File

@@ -68,6 +68,48 @@
*/
/*! \fn int versionCompare(const PIString & v0, const PIString & v1, int components = 6)
* \relatesalso PIString
* \brief Compare two version strings in free notation and returns 0, -1 or 1
* \details This function parse version to number codes and labels. Then it
* compare no more than "components" codes. If there is no difference, compare
* labels. Each label has corresponding integer value, so
* "prealpha" < "alpha" < "prebeta" < "beta" < "rcN" < "" < "rN".
* Example:
* \code
* piCout << versionCompare("1.0.0_rc2-999", "1.0.1_rc2-999"); // -1
* piCout << versionCompare("1.0.0", "0.9.2"); // 1
* piCout << versionCompare("1.0.0_r1", "1.0.0"); // 1
* piCout << versionCompare("1.0.0_r1", "1.0.0", 3); // 0
* piCout << versionCompare("1.0.0_r1", "1.0.0", 3); // 0
* piCout << versionCompare(".2-alpha", "0.2_alpha"); // 0
* piCout << versionCompare("1_prebeta", "1.0_alpha"); // 1
* \endcode
* \return
* * 0 - equal
* * 1 - v0 > v1
* * -1 - v0 < v1
*
*
* \fn PIString versionNormalize(const PIString & v)
* \relatesalso PIString
* \brief Converts version string in free notation to classic view
* \details Parse version as described in \a versionCompare() and
* returns classic view of codes and labels: major.minor.revision[-build][_label].
* Example:
* \code
* piCout << versionNormalize(""); // 0.0.0
* piCout << versionNormalize("1"); // 1.0.0
* piCout << versionNormalize("1.2"); // 1.2.0
* piCout << versionNormalize("1.2.3"); // 1.2.3
* piCout << versionNormalize("1.2+rc1.99"); // 1.2.99_rc1
* piCout << versionNormalize("1.2-alpha"); // 1.2.0_alpha
* piCout << versionNormalize("1..4_rc2-999"); // 1.0.4-999_rc2
* \endcode
*
*/
const char PIString::toBaseN[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
@@ -760,6 +802,30 @@ int PIString::findRange(const PIChar & start, const PIChar & end, const PIChar &
}
int PIString::findAny(const PIString & str, const int start) const {
for (int i = start; i < length(); ++i)
if (str.contains(at(i)))
return i;
return -1;
}
int PIString::findAnyLast(const PIString & str, const int start) const {
for (int i = length() - 1; i >= start; --i)
if (str.contains(at(i)))
return i;
return -1;
}
int PIString::entries(const PIChar & c) const {
int sz = size_s(), ret = 0;
for (int i = 0; i < sz; ++i)
if (at(i) == c) ++ret;
return ret;
}
bool PIString::startsWith(const PIString & str) const {
if (size() < str.size()) return false;
return str == left(str.size());
@@ -1110,6 +1176,117 @@ inline char chrLwr(char c) {
}
const static PIString _versionDelims_ = PIStringAscii("._-+");
void parseVersion(PIString s, PIVector<int> & codes, PIStringList & strs) {
s.trim();
if (s.isEmpty()) {
codes.resize(3, 0);
return;
}
int mccnt = 2 - s.entries('.');
if (mccnt > 0) {
int ind = s.findLast(".") + 1;
while (!_versionDelims_.contains(s[ind])) {
++ind;
if (ind > s.size_s() - 1)
break;
}
for (int i = 0; i < mccnt; ++i)
s.insert(ind, ".0");
}
PIStringList comps;
while (!s.isEmpty()) {
int ind = s.findAny(_versionDelims_);
if (ind >= 0) {
comps << s.takeLeft(ind);
s.cutLeft(1).trim();
} else {
comps << s;
s.clear();
}
}
for (int i = 0; i < comps.size_s(); ++i) {
if (comps[i].isEmpty())
comps[i] = "0";
bool ok = false;
int val = comps[i].toInt(-1, &ok);
if (ok) {
codes << val;
} else {
strs << comps[i];
}
}
//piCout << codes << strs;
}
int versionLabelValue(PIString s) {
int ret = -10000;
if (s.isEmpty()) return 0;
if (s.startsWith("pre")) {
s.cutLeft(3);
ret -= 1;
}
if (s.startsWith("rc")) {
s.cutLeft(2);
ret += s.toInt();
}
if (s.startsWith("r")) {
s.cutLeft(1);
ret += 10000 + s.toInt();
}
if (s == "alpha") ret -= 4;
if (s == "beta" ) ret -= 2;
return ret;
}
int versionCompare(const PIString & v0, const PIString & v1, int components) {
PIStringList strs[2]; PIVector<int> codes[2];
parseVersion(v0.toLowerCase(), codes[0], strs[0]);
parseVersion(v1.toLowerCase(), codes[1], strs[1]);
//piCout << codes[0] << strs[0];
int mc = piMaxi(codes[0].size_s(), codes[1].size_s());
if (codes[0].size_s() < mc) codes[0].resize(mc, 0);
if (codes[1].size_s() < mc) codes[1].resize(mc, 0);
mc = piMaxi(strs[0].size_s(), strs[1].size_s());
if (strs[0].size_s() < mc) strs[0].resize(mc, "");
if (strs[1].size_s() < mc) strs[1].resize(mc, "");
int comps = piMini(components, codes[0].size_s(), codes[1].size_s());
if (comps < 1) return (v0 == v1 ? 0 : (v0 > v1 ? 1 : -1));
for (int c = 0; c < comps; ++c) {
if (codes[0][c] > codes[1][c]) return 1;
if (codes[0][c] < codes[1][c]) return -1;
}
mc = piClampi(mc, 0, components - comps);
for (int c = 0; c < mc; ++c) {
int lv0 = versionLabelValue(strs[0][c]);
int lv1 = versionLabelValue(strs[1][c]);
if (lv0 > lv1) return 1;
if (lv0 < lv1) return -1;
}
return 0;
}
PIString versionNormalize(const PIString & v) {
PIStringList strs; PIVector<int> codes;
parseVersion(v.toLowerCase(), codes, strs);
PIString ret;
for (int i = 0; i < codes.size_s(); ++i) {
if (i > 0) {
if (i < 3) ret += ".";
else ret += "-";
}
ret += PIString::fromNumber(codes[i]);
}
for (int i = 0; i < strs.size_s(); ++i) {
ret += "_";
ret += strs[i];
}
return ret;
}
PICout operator <<(PICout s, const PIString & v) {
s.space();
s.quote();
@@ -1146,4 +1323,3 @@ PIStringList& PIStringList::removeDuplicates() {
}
return *this;
}

View File

@@ -547,7 +547,29 @@ public:
//! \brief Search range between "start" and "end" symbols at index "start_index" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::findRange
int findRange(const PIChar & start, const PIChar & end, const PIChar & shield = '\\', const int start_index = 0, int * len = 0) const;
//! \brief Search any symbol of "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::findAny
int findAny(const PIString & str, const int start = 0) const;
//! \brief Search any symbol of "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::findAny
int findAny(const char * str, const int start = 0) const {return findAny(PIString(str), start);}
//! \brief Search any symbol of "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findAnyLast
int findAnyLast(const PIString & str, const int start = 0) const;
//! \brief Search any symbol of "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findAnyLast
int findAnyLast(const char * str, const int start = 0) const {return findAnyLast(PIString(str), start);}
//! \brief Returns number of occurrences of symbol "c"
int entries(const PIChar & c) const;
//! \brief Returns number of occurrences of symbol "c"
int entries(char c) const {return entries(PIChar(c));}
//! \brief Return if string starts with "str"
bool startsWith(const PIString & str) const;
@@ -785,6 +807,11 @@ inline char chrUpr(char c);
inline char chrLwr(char c);
int versionCompare(const PIString & v0, const PIString & v1, int components = 6);
PIString versionNormalize(const PIString & v);
/*!\brief Strings array class
* \details This class is based on \a PIDeque<PIString> and
* expand it functionality. */

View File

@@ -143,7 +143,7 @@
* This class provide access to serial device, e.g. COM port. It can read,
* write, wait for write. There are several read and write functions.
*
* \section PISerial_sec0 FullPath
* \section PISerial_sec1 FullPath
* Since version 1.16.0 you can use as \a path DeviceInfo::id() USB identifier.
* \code
* PISerial * s = new PISerial("0403:6001");