38#include <fmt/chrono.h>
41#include <wx/tokenzr.h>
68 wxString filtered_fullpath = aFullFilename;
73 filtered_fullpath.Replace(
"/",
"_" );
74 filtered_fullpath.Replace(
"\\",
"_" );
77 if( filtered_fullpath.Length() > 1 && filtered_fullpath[1] ==
':' )
78 filtered_fullpath[1] =
' ';
81 if( wxString::npos != filtered_fullpath.find_first_of( wxFileName::GetForbiddenChars() ) )
91 bool inOverbar =
false;
94 if( aOldStr == wxT(
"~" ) )
97 newStr.reserve( aOldStr.length() );
99 for( wxString::const_iterator chIt = aOldStr.begin(); chIt != aOldStr.end(); ++chIt )
103 wxString::const_iterator lookahead = chIt + 1;
105 if( lookahead != aOldStr.end() && *lookahead ==
'~' )
107 if( ++lookahead != aOldStr.end() && *lookahead ==
'{' )
111 newStr << wxT(
"~~{}" );
116 newStr << wxT(
"~" );
120 else if( lookahead != aOldStr.end() && *lookahead ==
'{' )
130 newStr << wxT(
"}" );
135 newStr << wxT(
"~{" );
142 else if( ( *chIt ==
' ' || *chIt ==
'}' || *chIt ==
')' ) && inOverbar )
145 newStr << wxT(
"}" );
154 newStr << wxT(
"}" );
164 for( wxString::iterator ii = aString->begin(); ii != aString->end(); ++ii )
166 if( *ii ==
L'\u2018' || *ii ==
L'\u2019' )
171 if( *ii ==
L'\u201C' || *ii ==
L'\u201D' )
176 if( *ii ==
L'\u2013' || *ii ==
L'\u2014' )
190 std::vector<bool> braceStack;
192 converted.reserve( aSource.length() );
194 for( wxUniChar c: aSource )
199 converted += wxT(
"{slash}" );
200 else if( c ==
'\n' || c ==
'\r' )
201 converted += wxEmptyString;
209 converted += wxT(
"{slash}" );
211 converted += wxT(
"{backslash}" );
213 converted += wxT(
"{lt}" );
215 converted += wxT(
"{gt}" );
217 converted += wxT(
"{colon}" );
219 converted += wxT(
"{dblquote}" );
220 else if( c ==
'\n' || c ==
'\r' )
221 converted += wxEmptyString;
228 converted += wxT(
"{slash}" );
230 converted += wxT(
"{comma}" );
232 converted += wxT(
"{dblquote}" );
239 converted += wxT(
"{dblquote}" );
245 if( c >= 0x7F || c ==
'\'' || c ==
'"' || c ==
'\\' || c ==
'(' || c ==
')' )
247 unsigned int code = c;
249 snprintf( buffer,
sizeof(buffer),
"\\u%4.4X", code );
259 if( c ==
'\n' || c ==
'\r' )
260 converted += wxT(
"{return}" );
267 converted += wxT(
"{slash}" );
269 converted += wxT(
"{backslash}" );
271 converted += wxT(
"{dblquote}" );
273 converted += wxT(
"{lt}" );
275 converted += wxT(
"{gt}" );
277 converted += wxT(
"{bar}" );
279 converted += wxT(
"{colon}" );
281 converted += wxT(
"{tab}" );
282 else if( c ==
'\n' || c ==
'\r' )
283 converted += wxT(
"{return}" );
290 converted += wxT(
"{space}" );
297 converted += wxT(
"{comma}" );
298 else if( c ==
'\n' || c ==
'\r' )
299 converted += wxT(
"{return}" );
315 size_t sourceLen = aSource.length();
324 newbuf.reserve( sourceLen );
329 for(
size_t i = 0; i < sourceLen; ++i )
338 bool terminated =
false;
340 for( i = i + 1; i < sourceLen; ++i )
364 else if( prev ==
'$' || prev ==
'~' || prev ==
'^' || prev ==
'_' )
368 else if( token == wxT(
"dblquote" ) ) newbuf << wxT(
"\"" );
369 else if( token == wxT(
"quote" ) ) newbuf << wxT(
"'" );
370 else if( token == wxT(
"lt" ) ) newbuf << wxT(
"<" );
371 else if( token == wxT(
"gt" ) ) newbuf << wxT(
">" );
372 else if( token == wxT(
"backslash" ) ) newbuf << wxT(
"\\" );
373 else if( token == wxT(
"slash" ) ) newbuf << wxT(
"/" );
374 else if( token == wxT(
"bar" ) ) newbuf << wxT(
"|" );
375 else if( token == wxT(
"comma" ) ) newbuf << wxT(
"," );
376 else if( token == wxT(
"colon" ) ) newbuf << wxT(
":" );
377 else if( token == wxT(
"space" ) ) newbuf << wxT(
" " );
378 else if( token == wxT(
"dollar" ) ) newbuf << wxT(
"$" );
379 else if( token == wxT(
"tab" ) ) newbuf << wxT(
"\t" );
380 else if( token == wxT(
"return" ) ) newbuf << wxT(
"\n" );
381 else if( token == wxT(
"brace" ) ) newbuf << wxT(
"{" );
404 result.reserve( aString.length() );
406 for(
const wxString& word : words )
411 result += word.Capitalize();
425 result.reserve( aString.length() );
427 for(
const wxString& word : words )
430 result += word.Capitalize();
432 result += wxT(
" " ) + word.Lower();
443 const char* start = aSource;
446 while( (cc = *aSource++) != 0 )
466 if( cc !=
'"' && cc !=
'\\' )
480 return aSource - start;
490 const char* start = aSource;
491 char* limit = aDest + aDestSize - 1;
494 while( ( cc = *aSource++ ) != 0 && aDest < limit )
513 if( cc !=
'"' && cc !=
'\\' )
528 return aSource - start;
534 wxString str = aString;
537 str.Replace( wxT(
"\r\n" ), wxT(
"\r" ) );
538 str.Replace( wxT(
"\n" ), wxT(
"\r" ) );
540 std::string utf8 =
TO_UTF8( aString );
544 ret.reserve( utf8.length() + 2 );
548 for( std::string::const_iterator it = utf8.begin(); it!=utf8.end(); ++it )
556 else if( *it ==
'\\' )
577 converted.reserve( aString.length() );
579 for( wxUniChar c : aString )
582 converted += wxT(
""" );
584 converted += wxT(
"'" );
586 converted += wxT(
"&" );
588 converted += wxT(
"<" );
590 converted += wxT(
">" );
602 static const std::map<wxString, wxString> c_replacements = {
603 { wxS(
"quot" ), wxS(
"\"" ) },
604 { wxS(
"apos" ), wxS(
"'" ) },
605 { wxS(
"amp" ), wxS(
"&" ) },
606 { wxS(
"lt" ), wxS(
"<" ) },
607 { wxS(
"gt" ), wxS(
">" ) }
612 wxString regexStr =
"&(#(\\d*)|#x([a-zA-Z0-9]{4})";
614 for(
auto& [key, value] : c_replacements )
615 regexStr <<
'|' << key;
619 wxRegEx regex( regexStr );
626 wxString str = aString;
628 while( regex.Matches( str ) )
630 std::vector<wxString> matches;
631 regex.GetMatch( &start, &len );
633 result << str.Left( start );
635 wxString code = regex.GetMatch( str, 1 );
636 wxString codeDec = regex.GetMatch( str, 2 );
637 wxString codeHex = regex.GetMatch( str, 3 );
639 if( !codeDec.IsEmpty() || !codeHex.IsEmpty() )
641 unsigned long codeVal = 0;
643 if( !codeDec.IsEmpty() )
644 codeDec.ToCULong( &codeVal );
645 else if( !codeHex.IsEmpty() )
646 codeHex.ToCULong( &codeVal, 16 );
649 result << wxUniChar( codeVal );
651 else if(
auto val =
get_opt( c_replacements, code ) )
656 str = str.Mid( start + len );
667 wxString str = aInput;
668 wxRegEx( wxS(
"<[^>]*>" ) ).ReplaceAll( &str, wxEmptyString );
676 static wxRegEx regex( wxS(
"\\b(https?|ftp|file)://([-\\w+&@#/%?=~|!:,.;]*[^.,:;<>\\(\\)\\s\u00b6])" ),
679 regex.ReplaceAll( &aStr,
"<a href=\"\\0\">\\0</a>" );
687 static wxRegEx regex( wxS(
"(https?|ftp|file)://([-\\w+&@#/%?=~|!:,.;]*[^.,:;<>\\s\u00b6])" ),
690 regex.ReplaceAll( &aStr,
"<a href=\"\\0\">\\0</a>" );
692 return regex.Matches( aStr );
698 wxString tmp = aString;
700 return tmp.Trim(
true ).Trim(
false ).IsEmpty();
707 int overbarDepth = -1;
708 int superSubDepth = -1;
709 int braceNesting = 0;
711 for(
auto chIt = aString.begin(),
end = aString.end(); chIt <
end; ++chIt )
719 else if( *chIt ==
'^' && superSubDepth == -1 )
721 auto lookahead = chIt;
723 if( ++lookahead !=
end && *lookahead ==
'{' )
726 superSubDepth = braceNesting;
731 else if( *chIt ==
'_' && superSubDepth == -1 )
733 auto lookahead = chIt;
735 if( ++lookahead !=
end && *lookahead ==
'{' )
738 superSubDepth = braceNesting;
743 else if( *chIt ==
'~' && overbarDepth == -1 )
745 auto lookahead = chIt;
747 if( ++lookahead !=
end && *lookahead ==
'{' )
750 overbarDepth = braceNesting;
755 else if( *chIt ==
'{' )
759 else if( *chIt ==
'}' )
761 if( braceNesting > 0 )
764 if( braceNesting == superSubDepth )
770 if( braceNesting == overbarDepth )
786 static const char whitespace[] =
" \t\n\r\f\v";
790 while( *
text && strchr( whitespace, *
text ) )
793 char* cp =
text + strlen(
text ) - 1;
795 while( cp >=
text && strchr( whitespace, *cp ) )
803char*
GetLine( FILE* File,
char* Line,
int* LineNum,
int SizeLine )
806 if( fgets( Line, SizeLine, File ) ==
nullptr )
812 }
while( Line[0] ==
'#' || Line[0] ==
'\n' || Line[0] ==
'\r' || Line[0] == 0 );
814 strtok( Line,
"\n\r" );
821 return wxDateTime::Now().FormatISOCombined(
'T' );
825int StrNumCmp(
const wxString& aString1,
const wxString& aString2,
bool aIgnoreCase )
827 int nb1 = 0, nb2 = 0;
829 auto str1 = aString1.begin();
830 auto str2 = aString2.begin();
832 const auto str1End = aString1.end();
833 const auto str2End = aString2.end();
835 while( str1 != str1End && str2 != str2End )
837 wxUniChar c1 = *str1;
838 wxUniChar c2 = *str2;
840 if( wxIsdigit( c1 ) && wxIsdigit( c2 ) )
848 nb1 = nb1 * 10 + (int) c1 -
'0';
850 }
while( str1 != str1End && wxIsdigit( *str1 ) );
855 nb2 = nb2 * 10 + (int) c2 -
'0';
857 }
while( str2 != str2End && wxIsdigit( *str2 ) );
865 c1 = ( str1 != str1End ) ? *str1 : wxUniChar( 0 );
866 c2 = ( str2 != str2End ) ? *str2 : wxUniChar( 0 );
874 wxUniChar uc1 = wxToupper( c1 );
875 wxUniChar uc2 = wxToupper( c2 );
878 return uc1 < uc2 ? -1 : 1;
890 if( str1 != str1End )
893 if( str2 != str2End )
897 if( str1 == str1End && str2 != str2End )
901 else if( str1 != str1End && str2 == str2End )
911 bool case_sensitive )
913 const wxChar* cp =
nullptr;
914 const wxChar* mp =
nullptr;
915 const wxChar* wild =
nullptr;
916 const wxChar* str =
nullptr;
917 wxString _pattern, _string_to_tst;
921 wild = pattern.GetData();
922 str = string_to_tst.GetData();
927 _pattern.MakeUpper();
928 _string_to_tst = string_to_tst;
929 _string_to_tst.MakeUpper();
930 wild = _pattern.GetData();
931 str = _string_to_tst.GetData();
934 while( ( *str ) && ( *wild !=
'*' ) )
936 if( ( *wild != *str ) && ( *wild !=
'?' ) )
953 else if( ( *wild == *str ) || ( *wild ==
'?' ) )
965 while( *wild ==
'*' )
977 static const wxString modifiers( wxT(
"afpnuµμmLRFkKMGTPE" ) );
979 if( !aString.length() )
985 if( modifiers.Find( aString[ 0 ] ) >= 0 )
987 modifier = aString[ 0 ];
988 units = aString.Mid( 1 ).Trim();
993 units = aString.Mid( 0 ).Trim();
997 && !units.IsSameAs( wxT(
"F" ),
false )
998 && !units.IsSameAs( wxT(
"hz" ),
false )
999 && !units.IsSameAs( wxT(
"W" ),
false )
1000 && !units.IsSameAs( wxT(
"V" ),
false )
1001 && !units.IsSameAs( wxT(
"A" ),
false )
1002 && !units.IsSameAs( wxT(
"H" ),
false ) )
1008 if( modifier ==
'a' )
1010 else if( modifier ==
'f' )
1012 if( modifier ==
'p' )
1014 if( modifier ==
'n' )
1016 else if( modifier ==
'u' || modifier == wxS(
"µ" )[0] || modifier == wxS(
"μ" )[0] )
1018 else if( modifier ==
'm' || modifier ==
'L' )
1020 else if( modifier ==
'R' || modifier ==
'F' )
1022 else if( modifier ==
'k' || modifier ==
'K' )
1024 else if( modifier ==
'M' )
1026 else if( modifier ==
'G' )
1028 else if( modifier ==
'T' )
1030 else if( modifier ==
'P' )
1032 else if( modifier ==
'E' )
1052 value->Replace( wxS(
" " ), wxEmptyString );
1054 wxChar ambiguousSeparator =
'?';
1055 wxChar thousandsSeparator =
'?';
1056 bool thousandsSeparatorFound =
false;
1057 wxChar decimalSeparator =
'?';
1058 bool decimalSeparatorFound =
false;
1061 for(
int ii = (
int) value->length() - 1; ii >= 0; --ii )
1063 wxChar c = value->GetChar( ii );
1065 if( c >=
'0' && c <=
'9' )
1069 else if( c ==
'.' || c ==
',' )
1071 if( decimalSeparator !=
'?' || thousandsSeparator !=
'?' )
1075 if( c == decimalSeparator )
1077 if( thousandsSeparatorFound )
1079 else if( decimalSeparatorFound )
1082 decimalSeparatorFound =
true;
1084 else if( c == thousandsSeparator )
1089 thousandsSeparatorFound =
true;
1092 else if( ambiguousSeparator !=
'?' )
1096 if( c == ambiguousSeparator )
1099 thousandsSeparator = ambiguousSeparator;
1100 thousandsSeparatorFound =
true;
1101 decimalSeparator = c ==
'.' ?
',' :
'.';
1106 decimalSeparator = ambiguousSeparator;
1107 decimalSeparatorFound =
true;
1108 thousandsSeparator = c;
1109 thousandsSeparatorFound =
true;
1121 if( ( ii == 1 && value->GetChar( 0 ) ==
'0' ) || digits != 3 )
1123 decimalSeparator = c;
1124 decimalSeparatorFound =
true;
1125 thousandsSeparator = c ==
'.' ?
',' :
'.';
1129 ambiguousSeparator = c;
1142 if( decimalSeparator ==
'?' && thousandsSeparator ==
'?' )
1144 const struct lconv* lc = localeconv();
1146 decimalSeparator = lc->decimal_point[0];
1147 thousandsSeparator = decimalSeparator ==
'.' ?
',' :
'.';
1151 value->Replace( thousandsSeparator, wxEmptyString );
1152 value->Replace( decimalSeparator,
'.' );
1165 wxString strFWordBeg, strFWordMid, strFWordEnd;
1166 wxString strSWordBeg, strSWordMid, strSWordEnd;
1169 SplitString( fWord, &strFWordBeg, &strFWordMid, &strFWordEnd );
1170 SplitString( sWord, &strSWordBeg, &strSWordMid, &strSWordEnd );
1173 int isEqual = strFWordBeg.CmpNoCase( strSWordBeg );
1179 else if( isEqual < 0 )
1186 double lFirstNumber = 0;
1187 double lSecondNumber = 0;
1188 bool endingIsModifier =
false;
1193 strFWordMid.ToCDouble( &lFirstNumber );
1194 strSWordMid.ToCDouble( &lSecondNumber );
1196 endingIsModifier |=
ApplyModifier( lFirstNumber, strFWordEnd );
1197 endingIsModifier |=
ApplyModifier( lSecondNumber, strSWordEnd );
1199 if( lFirstNumber > lSecondNumber )
1201 else if( lFirstNumber < lSecondNumber )
1204 else if( !endingIsModifier )
1205 return strFWordEnd.CmpNoCase( strSWordEnd );
1214 wxString* strBeginning,
1215 wxString* strDigits,
1218 static const wxString separators( wxT(
".," ) );
1219 wxUniChar infix = 0;
1222 strBeginning->Empty();
1227 if( strToSplit.length() == 0 )
1233 for( ii = (strToSplit.length() - 1); ii >= 0; ii-- )
1235 if( wxIsdigit( strToSplit[ii] ) )
1242 *strBeginning = strToSplit;
1247 *strEnd = strToSplit.substr( ii + 1 );
1250 int position = ii + 1;
1252 for( ; ii >= 0; ii-- )
1255 wxUniChar c = strToSplit[ii];
1257 if( wxIsdigit( c ) )
1266 else if( separators.Find( strToSplit[ii] ) >= 0 )
1279 *strDigits = strToSplit.substr( 0, position );
1284 *strDigits = strToSplit.substr( ii + 1, position - ii - 1 );
1285 *strBeginning = strToSplit.substr( 0, ii + 1 );
1290 strDigits->Replace( infix,
'.' );
1291 *strEnd = infix + *strEnd;
1305 int index = aStr.Len() - 1;
1309 const char chr = aStr.GetChar(
index );
1311 if( chr <
'0' || chr >
'9' )
1314 number += ( chr -
'0' ) * base;
1333 if( first_illegal_pos == std::string::npos )
1340 result.reserve( aName.length() + 16 );
1342 result.append( aName, 0, first_illegal_pos );
1344 for(
size_t i = first_illegal_pos; i < aName.length(); ++i )
1353 result.push_back( aReplaceChar );
1357 fmt::format_to( std::back_inserter(
result ),
"%{:02x}",
static_cast<unsigned char>( c ) );
1366 aName = std::move(
result );
1373 bool changed =
false;
1375 result.reserve( aName.Length() );
1378 for( wxString::iterator it = aName.begin(); it != aName.end(); ++it )
1380 if( illWChars.Find( *it ) != wxNOT_FOUND )
1385 result += wxString::Format(
"%%%02x", *it );
1396 aName = std::move(
result );
1402void wxStringSplit(
const wxString& aText, wxArrayString& aStrings, wxChar aSplitter )
1406 for(
unsigned ii = 0; ii < aText.Length(); ii++ )
1408 if( aText[ii] == aSplitter )
1410 aStrings.Add( tmp );
1419 if( !tmp.IsEmpty() )
1420 aStrings.Add( tmp );
1426 struct lconv* lc = localeconv();
1427 char sep = lc->decimal_point[0];
1428 unsigned sep_pos = aStringValue.Find( sep );
1433 unsigned min_len = sep_pos + aTrailingZeroAllowed + 1;
1435 while( aStringValue.Len() > min_len )
1437 if( aStringValue.Last() ==
'0' )
1438 aStringValue.RemoveLast();
1450 if( aValue != 0.0 && std::fabs( aValue ) <= 0.0001 )
1452 buf = fmt::format(
"{:.16f}", aValue );
1455 while( !buf.empty() && buf[buf.size() - 1] ==
'0' )
1462 if( buf[buf.size() - 1] ==
'.' )
1469 buf = fmt::format(
"{:.10g}", aValue );
1481 if( aValue != 0.0 && std::fabs( aValue ) <= 0.0001 )
1485 len = snprintf( buf,
sizeof( buf ),
"%.16f", aValue );
1487 while( --len > 0 && buf[len] ==
'0' )
1490 if( buf[len] ==
'.' || buf[len] ==
',' )
1499 len = snprintf( buf,
sizeof( buf ),
"%.10g", aValue );
1502 return std::string( buf, len );
1509 wxString line = wxString::FromUTF8( cstring );
1511 if( line.IsEmpty() )
1513 line = wxConvCurrent->cMB2WC( cstring );
1515 if( line.IsEmpty() )
1516 line = wxString::From8BitData( cstring );
1526 wxString line = wxString::FromUTF8( aString );
1528 if( line.IsEmpty() )
1530 line = wxConvCurrent->cMB2WC( aString.c_str() );
1532 if( line.IsEmpty() )
1533 line = wxString::From8BitData( aString.c_str() );
1542 wxString uriPathAndFileName;
1544 wxCHECK( aFileUri.StartsWith( wxS(
"file://" ), &uriPathAndFileName ), aFileUri );
1546 wxString tmp = uriPathAndFileName;
1547 wxString retv = wxS(
"file://" );
1549 tmp.Replace( wxS(
"\\" ), wxS(
"/" ) );
1550 tmp.Replace( wxS(
":" ), wxS(
"" ) );
1552 if( !tmp.IsEmpty() && tmp[0] !=
'/' )
1553 tmp = wxS(
"/" ) + tmp;
1563 if( aPath.IsEmpty() || aPath == wxS(
"~" ) )
1566 bool looksLikePath = aPath.StartsWith( wxS(
"/" ) ) || aPath.StartsWith( wxS(
"${" ) )
1567 || aPath.StartsWith( wxS(
"./" ) ) || aPath.StartsWith( wxS(
"../" ) );
1570 looksLikePath = looksLikePath || ( aPath.Length() >= 2 && wxIsalpha( aPath[0] ) && aPath[1] ==
':' )
1571 || aPath.StartsWith( wxS(
"\\\\" ) ) || aPath.StartsWith( wxS(
".\\" ) )
1572 || aPath.StartsWith( wxS(
"..\\" ) );
1575 if( !looksLikePath )
1579 if( uri.HasScheme() )
1586 wxString resolved = aPath;
1591 wxFileName fname( resolved );
1593 if( !fname.IsAbsolute() && aProject && !aProject->
GetProjectPath().IsEmpty() )
1596 resolved = fname.GetFullPath();
1600 bool isUNC = resolved.StartsWith( wxS(
"\\\\" ) );
1602 if( !isUNC && !wxFileExists( resolved ) && !wxDirExists( resolved ) )
1605 if( aPath.StartsWith( wxS(
"/" ) ) )
1606 return wxS(
"file://" ) + aPath;
1608 if( aPath.StartsWith( wxS(
"${" ) ) )
1609 return wxS(
"file://" ) + aPath;
1611 if( aPath.StartsWith( wxS(
"./" ) ) || aPath.StartsWith( wxS(
"../" ) ) )
1612 return wxS(
"file://" ) + aPath;
1615 if( aPath.StartsWith( wxS(
"\\\\" ) ) )
1617 wxString
path = aPath.Mid( 2 );
1618 path.Replace( wxS(
"\\" ), wxS(
"/" ) );
1619 return wxS(
"file://" ) +
path;
1622 if( aPath.Length() >= 2 && wxIsalpha( aPath[0] ) && aPath[1] ==
':' )
1624 wxString
path = aPath;
1625 path.Replace( wxS(
"\\" ), wxS(
"/" ) );
1626 return wxS(
"file:///" ) +
path;
1629 if( aPath.StartsWith( wxS(
".\\" ) ) || aPath.StartsWith( wxS(
"..\\" ) ) )
1631 wxString
path = aPath;
1632 path.Replace( wxS(
"\\" ), wxS(
"/" ) );
1633 return wxS(
"file://" ) +
path;
1644 std::pair<wxString, long> ParseAlphaNumericPin(
const wxString& pinNum )
1649 size_t numStart = pinNum.length();
1650 for(
int i =
static_cast<int>( pinNum.length() ) - 1; i >= 0; --i )
1652 if( !wxIsdigit( pinNum[i] ) )
1661 if( numStart < pinNum.length() )
1663 prefix = pinNum.Left( numStart );
1664 wxString numericPart = pinNum.Mid( numStart );
1665 numericPart.ToLong( &numValue );
1668 return { prefix, numValue };
1677 std::vector<wxString> expanded;
1679 const bool hasOpenBracket = aPinName.Contains( wxT(
"[" ) );
1680 const bool hasCloseBracket = aPinName.Contains( wxT(
"]" ) );
1682 if( hasOpenBracket || hasCloseBracket )
1684 if( !aPinName.StartsWith( wxT(
"[" ) ) || !aPinName.EndsWith( wxT(
"]" ) ) )
1688 expanded.push_back( aPinName );
1693 if( !aPinName.StartsWith( wxT(
"[" ) ) || !aPinName.EndsWith( wxT(
"]" ) ) )
1695 expanded.push_back( aPinName );
1699 const wxString inner = aPinName.Mid( 1, aPinName.Length() - 2 );
1702 while( start < inner.length() )
1704 size_t comma = inner.find(
',', start );
1705 wxString part = ( comma == wxString::npos ) ? inner.Mid( start ) : inner.Mid( start, comma - start );
1706 part.Trim(
true ).Trim(
false );
1709 start = ( comma == wxString::npos ) ? inner.length() : comma + 1;
1713 int dashPos = part.Find(
'-' );
1714 if( dashPos != wxNOT_FOUND )
1716 wxString startTxt = part.Left( dashPos );
1717 wxString endTxt = part.Mid( dashPos + 1 );
1718 startTxt.Trim(
true ).Trim(
false );
1719 endTxt.Trim(
true ).Trim(
false );
1721 auto [startPrefix, startVal] = ParseAlphaNumericPin( startTxt );
1722 auto [endPrefix, endVal] = ParseAlphaNumericPin( endTxt );
1724 if( startPrefix != endPrefix || startVal == -1 || endVal == -1 || startVal > endVal )
1729 expanded.push_back( aPinName );
1733 for(
long ii = startVal; ii <= endVal; ++ii )
1735 if( startPrefix.IsEmpty() )
1736 expanded.emplace_back( wxString::Format( wxT(
"%ld" ), ii ) );
1738 expanded.emplace_back( wxString::Format( wxT(
"%s%ld" ), startPrefix, ii ) );
1743 expanded.push_back( part );
1746 if( comma == wxString::npos )
1751 if( expanded.empty() )
1753 expanded.push_back( aPinName );
1764 size_t len = aPinName.length();
1777 const bool hasOpenBracket = aPinName.Contains( wxT(
"[" ) );
1778 const bool hasCloseBracket = aPinName.Contains( wxT(
"]" ) );
1780 if( hasOpenBracket || hasCloseBracket )
1782 if( aPinName[0] !=
'[' || aPinName[len - 1] !=
']' )
1790 if( aPinName[0] !=
'[' || aPinName[len - 1] !=
']' )
1793 const wxString inner = aPinName.Mid( 1, aPinName.Length() - 2 );
1798 while( start < inner.length() )
1800 size_t comma = inner.find(
',', start );
1801 wxString part = ( comma == wxString::npos ) ? inner.Mid( start ) : inner.Mid( start, comma - start );
1802 part.Trim(
true ).Trim(
false );
1806 start = ( comma == wxString::npos ) ? inner.length() : comma + 1;
1810 int dashPos = part.Find(
'-' );
1811 if( dashPos != wxNOT_FOUND )
1813 wxString startTxt = part.Left( dashPos );
1814 wxString endTxt = part.Mid( dashPos + 1 );
1815 startTxt.Trim(
true ).Trim(
false );
1816 endTxt.Trim(
true ).Trim(
false );
1818 auto [startPrefix, startVal] = ParseAlphaNumericPin( startTxt );
1819 auto [endPrefix, endVal] = ParseAlphaNumericPin( endTxt );
1821 if( startPrefix != endPrefix || startVal == -1 || endVal == -1 || startVal > endVal )
1830 count +=
static_cast<int>( endVal - startVal + 1 );
1838 if( comma == wxString::npos )
1876 std::vector<LOAD_MESSAGE> messages;
1878 if( aErrorString.IsEmpty() )
1886 wxStringTokenizer tokenizer( aErrorString, wxS(
"\n" ), wxTOKEN_STRTOK );
1888 while( tokenizer.HasMoreTokens() )
1890 wxString line = tokenizer.GetNextToken();
1893 if( line.StartsWith( wxS(
"from " ) ) )
1896 if( line.StartsWith( wxS(
"Library '" ) ) || line.Contains( wxS(
"Expecting" ) ) )
1897 messages.push_back( { line,
static_cast<SEVERITY>( aSeverity ) } );
static bool IsOldSchoolDecimalSeparator(wxUniChar ch, double *siScaler)
Container for project specific data.
virtual const wxString GetProjectPath() const
Return the full path of the project.
const wxString ResolveUriByEnvVars(const wxString &aUri, const PROJECT *aProject)
Replace any environment and/or text variables in URIs.
This file contains miscellaneous commonly used macros and functions.
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
wxString RemoveHTMLTags(const wxString &aInput)
Removes HTML tags from a string.
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Compare a string against wild card (* and ?) pattern using the usual rules.
wxString GetDefaultVariantName()
std::vector< wxString > ExpandStackedPinNotation(const wxString &aPinName, bool *aValid)
Expand stacked pin notation like [1,2,3], [1-4], [A1-A4], or [AA1-AA3,AB4,CD12-CD14] into individual ...
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
int GetTrailingInt(const wxString &aStr)
Gets the trailing int, if any, from a string.
wxString UnescapeString(const wxString &aSource)
wxString LinkifyHTML(wxString aStr)
Wraps links in HTML tags.
bool convertSeparators(wxString *value)
wxString GetIllegalFileNameWxChars()
wxString From_UTF8(const char *cstring)
std::vector< LOAD_MESSAGE > ExtractLibraryLoadErrors(const wxString &aErrorString, int aSeverity)
Parse library load error messages, extracting user-facing information while stripping internal code l...
int SortVariantNames(const wxString &aLhs, const wxString &aRhs)
bool ConvertSmartQuotesAndDashes(wxString *aString)
Convert curly quotes and em/en dashes to straight quotes and dashes.
static const wxChar defaultVariantName[]
wxString ConvertPathToFileUri(const wxString &aPath, const PROJECT *aProject)
Convert a file path to a file:// URI.
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
int ReadDelimitedText(wxString *aDest, const char *aSource)
Copy bytes from aSource delimited string segment to aDest wxString.
wxString TitleCaps(const wxString &aString)
Capitalize the first letter in each word.
std::string UIDouble2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 We want to avoid scientific ...
static constexpr std::string_view illegalFileNameChars
Illegal file name characters used to ensure file names will be valid on all supported platforms.
std::string FormatDouble2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 This function is intended in...
bool ReplaceIllegalFileNameChars(std::string &aName, int aReplaceChar)
Checks aName for illegal file name characters.
int PrintableCharCount(const wxString &aString)
Return the number of printable (ie: non-formatting) chars.
std::string EscapedUTF8(const wxString &aString)
Return an 8 bit UTF8 string given aString in Unicode form.
char * GetLine(FILE *File, char *Line, int *LineNum, int SizeLine)
Read one line line from aFile.
bool ApplyModifier(double &value, const wxString &aString)
wxString InitialCaps(const wxString &aString)
Capitalize only the first word.
wxString NormalizeFileUri(const wxString &aFileUri)
Normalize file path aFileUri to URI convention.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
wxString GetISO8601CurrentDateTime()
int ValueStringCompare(const wxString &strFWord, const wxString &strSWord)
Compare strings like the strcmp function but handle numbers and modifiers within the string text corr...
int SplitString(const wxString &strToSplit, wxString *strBeginning, wxString *strDigits, wxString *strEnd)
Break a string into three parts: he alphabetic preamble, the numeric part, and any alphabetic ending.
bool IsFullFileNameValid(const wxString &aFullFilename)
Checks if a full filename is valid, i.e.
void StripTrailingZeros(wxString &aStringValue, unsigned aTrailingZeroAllowed)
Remove trailing zeros from a string containing a converted float number.
int CountStackedPinNotation(const wxString &aPinName, bool *aValid)
Count the number of pins represented by stacked pin notation without allocating strings.
char * StrPurge(char *text)
Remove leading and training spaces, tabs and end of line chars in text.
bool NoPrintableChars(const wxString &aString)
Return true if the string is empty or contains only whitespace.
wxString UnescapeHTML(const wxString &aString)
Return a new wxString unescaped from HTML format.
bool IsURL(wxString aStr)
Performs a URL sniff-test on a string.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
ESCAPE_CONTEXT
Escape/Unescape routines to safely encode reserved-characters in various contexts.
wxString result
Test unit parsing edge cases and error handling.