38#include <fmt/chrono.h>
60 wxString filtered_fullpath = aFullFilename;
65 filtered_fullpath.Replace(
"/",
"_" );
66 filtered_fullpath.Replace(
"\\",
"_" );
69 if( filtered_fullpath.Length() > 1 && filtered_fullpath[1] ==
':' )
70 filtered_fullpath[1] =
' ';
73 if( wxString::npos != filtered_fullpath.find_first_of( wxFileName::GetForbiddenChars() ) )
83 bool inOverbar =
false;
86 if( aOldStr == wxT(
"~" ) )
89 newStr.reserve( aOldStr.length() );
91 for( wxString::const_iterator chIt = aOldStr.begin(); chIt != aOldStr.end(); ++chIt )
95 wxString::const_iterator lookahead = chIt + 1;
97 if( lookahead != aOldStr.end() && *lookahead ==
'~' )
99 if( ++lookahead != aOldStr.end() && *lookahead ==
'{' )
103 newStr << wxT(
"~~{}" );
108 newStr << wxT(
"~" );
112 else if( lookahead != aOldStr.end() && *lookahead ==
'{' )
122 newStr << wxT(
"}" );
127 newStr << wxT(
"~{" );
134 else if( ( *chIt ==
' ' || *chIt ==
'}' || *chIt ==
')' ) && inOverbar )
137 newStr << wxT(
"}" );
146 newStr << wxT(
"}" );
156 for( wxString::iterator ii = aString->begin(); ii != aString->end(); ++ii )
158 if( *ii == L
'\u00B4' || *ii == L
'\u2018' || *ii == L
'\u2019' )
163 if( *ii == L
'\u201C' || *ii == L
'\u201D' )
168 if( *ii == L
'\u2013' || *ii == L
'\u2014' )
182 std::vector<bool> braceStack;
184 converted.reserve( aSource.length() );
186 for( wxUniChar c: aSource )
191 converted += wxT(
"{slash}" );
192 else if( c ==
'\n' || c ==
'\r' )
193 converted += wxEmptyString;
201 converted += wxT(
"{slash}" );
203 converted += wxT(
"{backslash}" );
205 converted += wxT(
"{lt}" );
207 converted += wxT(
"{gt}" );
209 converted += wxT(
"{colon}" );
211 converted += wxT(
"{dblquote}" );
212 else if( c ==
'\n' || c ==
'\r' )
213 converted += wxEmptyString;
220 converted += wxT(
"{slash}" );
222 converted += wxT(
"{comma}" );
224 converted += wxT(
"{dblquote}" );
231 converted += wxT(
"{dblquote}" );
237 if( c >= 0x7F || c ==
'\'' || c ==
'\\' || c ==
'(' || c ==
')' )
239 unsigned int code = c;
241 snprintf( buffer,
sizeof(buffer),
"\\u%4.4X", code );
251 if( c ==
'\n' || c ==
'\r' )
252 converted += wxT(
"{return}" );
259 converted += wxT(
"{slash}" );
261 converted += wxT(
"{backslash}" );
263 converted += wxT(
"{dblquote}" );
265 converted += wxT(
"{lt}" );
267 converted += wxT(
"{gt}" );
269 converted += wxT(
"{bar}" );
271 converted += wxT(
"{colon}" );
273 converted += wxT(
"{tab}" );
274 else if( c ==
'\n' || c ==
'\r' )
275 converted += wxT(
"{return}" );
282 converted += wxT(
"{space}" );
289 converted += wxT(
"{comma}" );
290 else if( c ==
'\n' || c ==
'\r' )
291 converted += wxT(
"{return}" );
307 size_t sourceLen = aSource.length();
316 newbuf.reserve( sourceLen );
321 for(
size_t i = 0; i < sourceLen; ++i )
330 bool terminated =
false;
332 for( i = i + 1; i < sourceLen; ++i )
356 else if( prev ==
'$' || prev ==
'~' || prev ==
'^' || prev ==
'_' )
360 else if( token == wxT(
"dblquote" ) ) newbuf << wxT(
"\"" );
361 else if( token == wxT(
"quote" ) ) newbuf << wxT(
"'" );
362 else if( token == wxT(
"lt" ) ) newbuf << wxT(
"<" );
363 else if( token == wxT(
"gt" ) ) newbuf << wxT(
">" );
364 else if( token == wxT(
"backslash" ) ) newbuf << wxT(
"\\" );
365 else if( token == wxT(
"slash" ) ) newbuf << wxT(
"/" );
366 else if( token == wxT(
"bar" ) ) newbuf << wxT(
"|" );
367 else if( token == wxT(
"comma" ) ) newbuf << wxT(
"," );
368 else if( token == wxT(
"colon" ) ) newbuf << wxT(
":" );
369 else if( token == wxT(
"space" ) ) newbuf << wxT(
" " );
370 else if( token == wxT(
"dollar" ) ) newbuf << wxT(
"$" );
371 else if( token == wxT(
"tab" ) ) newbuf << wxT(
"\t" );
372 else if( token == wxT(
"return" ) ) newbuf << wxT(
"\n" );
373 else if( token == wxT(
"brace" ) ) newbuf << wxT(
"{" );
396 result.reserve( aString.length() );
398 for(
const wxString& word : words )
400 if( !result.IsEmpty() )
401 result += wxT(
" " );
403 result += word.Capitalize();
414 const char* start = aSource;
417 while( (cc = *aSource++) != 0 )
437 if( cc !=
'"' && cc !=
'\\' )
451 return aSource - start;
461 const char* start = aSource;
462 char* limit = aDest + aDestSize - 1;
465 while( ( cc = *aSource++ ) != 0 && aDest < limit )
484 if( cc !=
'"' && cc !=
'\\' )
499 return aSource - start;
505 wxString str = aString;
508 str.Replace( wxT(
"\r\n" ), wxT(
"\r" ) );
509 str.Replace( wxT(
"\n" ), wxT(
"\r" ) );
511 std::string utf8 =
TO_UTF8( aString );
515 ret.reserve( utf8.length() + 2 );
519 for( std::string::const_iterator it = utf8.begin(); it!=utf8.end(); ++it )
527 else if( *it ==
'\\' )
548 converted.reserve( aString.length() );
550 for( wxUniChar c : aString )
553 converted += wxT(
""" );
555 converted += wxT(
"'" );
557 converted += wxT(
"&" );
559 converted += wxT(
"<" );
561 converted += wxT(
">" );
572 wxString converted = aString;
575 static const std::map<wxString, wxString> c_replacements = {
576 { wxS(
"quot" ), wxS(
"\"" ) },
577 { wxS(
"apos" ), wxS(
"'" ) },
578 { wxS(
"amp" ), wxS(
"&" ) },
579 { wxS(
"lt" ), wxS(
"<" ) },
580 { wxS(
"gt" ), wxS(
">" ) }
585 wxString regexStr =
"&(#(\\d*)|#x([a-zA-Z0-9]{4})";
587 for(
auto& [key, value] : c_replacements )
588 regexStr <<
'|' << key;
592 wxRegEx regex( regexStr );
599 wxString str = converted;
601 while( regex.Matches( str ) )
603 std::vector<wxString> matches;
604 regex.GetMatch( &start, &len );
606 result << str.Left( start );
608 wxString code = regex.GetMatch( str, 1 );
609 wxString codeDec = regex.GetMatch( str, 2 );
610 wxString codeHex = regex.GetMatch( str, 3 );
612 if( !codeDec.IsEmpty() || !codeHex.IsEmpty() )
614 unsigned long codeVal = 0;
616 if( !codeDec.IsEmpty() )
617 codeDec.ToCULong( &codeVal );
618 else if( !codeHex.IsEmpty() )
619 codeHex.ToCULong( &codeVal, 16 );
622 result << wxUniChar( codeVal );
624 else if(
auto val =
get_opt( c_replacements, code ) )
629 str = str.Mid( start + len );
640 wxString str = aInput;
641 wxRegEx( wxS(
"<[^>]*>" ) ).ReplaceAll( &str, wxEmptyString );
649 wxRegEx regex( wxS(
"\\b(https?|ftp|file)://([-\\w+&@#/%?=~|!:,.;]*[^.,:;<>\\s\u00b6])" ),
652 regex.ReplaceAll( &aStr,
"<a href=\"\\0\">\\0</a>" );
660 wxString tmp = aString;
662 return tmp.Trim(
true ).Trim(
false ).IsEmpty();
669 int overbarDepth = -1;
670 int superSubDepth = -1;
671 int braceNesting = 0;
673 for(
auto chIt = aString.begin(), end = aString.end(); chIt < end; ++chIt )
681 else if( *chIt ==
'^' && superSubDepth == -1 )
683 auto lookahead = chIt;
685 if( ++lookahead != end && *lookahead ==
'{' )
688 superSubDepth = braceNesting;
693 else if( *chIt ==
'_' && superSubDepth == -1 )
695 auto lookahead = chIt;
697 if( ++lookahead != end && *lookahead ==
'{' )
700 superSubDepth = braceNesting;
705 else if( *chIt ==
'~' && overbarDepth == -1 )
707 auto lookahead = chIt;
709 if( ++lookahead != end && *lookahead ==
'{' )
712 overbarDepth = braceNesting;
717 else if( *chIt ==
'{' )
721 else if( *chIt ==
'}' )
723 if( braceNesting > 0 )
726 if( braceNesting == superSubDepth )
732 if( braceNesting == overbarDepth )
748 static const char whitespace[] =
" \t\n\r\f\v";
752 while( *
text && strchr( whitespace, *
text ) )
755 char* cp =
text + strlen(
text ) - 1;
757 while( cp >=
text && strchr( whitespace, *cp ) )
765char*
GetLine( FILE* File,
char* Line,
int* LineNum,
int SizeLine )
768 if( fgets( Line, SizeLine, File ) ==
nullptr )
774 }
while( Line[0] ==
'#' || Line[0] ==
'\n' || Line[0] ==
'\r' || Line[0] == 0 );
776 strtok( Line,
"\n\r" );
787#if defined(__MINGW32__) && !defined(_UCRT)
788 return fmt::format(
"{:%FT%T}", fmt::localtime( std::time(
nullptr ) ) );
790 return fmt::format(
"{:%FT%T%z}", fmt::localtime( std::time(
nullptr ) ) );
795int StrNumCmp(
const wxString& aString1,
const wxString& aString2,
bool aIgnoreCase )
797 int nb1 = 0, nb2 = 0;
799 auto str1 = aString1.begin();
800 auto str2 = aString2.begin();
802 while( str1 != aString1.end() && str2 != aString2.end() )
804 wxUniChar c1 = *str1;
805 wxUniChar c2 = *str2;
807 if( wxIsdigit( c1 ) && wxIsdigit( c2 ) )
815 nb1 = nb1 * 10 + (int) c1 -
'0';
817 }
while( str1 != aString1.end() && wxIsdigit( *str1 ) );
822 nb2 = nb2 * 10 + (int) c2 -
'0';
824 }
while( str2 != aString2.end() && wxIsdigit( *str2 ) );
832 c1 = ( str1 != aString1.end() ) ? *str1 : wxUniChar( 0 );
833 c2 = ( str2 != aString2.end() ) ? *str2 : wxUniChar( 0 );
841 wxUniChar uc1 = wxToupper( c1 );
842 wxUniChar uc2 = wxToupper( c2 );
845 return uc1 < uc2 ? -1 : 1;
857 if( str1 != aString1.end() )
860 if( str2 != aString2.end() )
864 if( str1 == aString1.end() && str2 != aString2.end() )
868 else if( str1 != aString1.end() && str2 == aString2.end() )
878 bool case_sensitive )
880 const wxChar* cp =
nullptr;
881 const wxChar* mp =
nullptr;
882 const wxChar* wild =
nullptr;
883 const wxChar* str =
nullptr;
884 wxString _pattern, _string_to_tst;
888 wild = pattern.GetData();
889 str = string_to_tst.GetData();
894 _pattern.MakeUpper();
895 _string_to_tst = string_to_tst;
896 _string_to_tst.MakeUpper();
897 wild = _pattern.GetData();
898 str = _string_to_tst.GetData();
901 while( ( *str ) && ( *wild !=
'*' ) )
903 if( ( *wild != *str ) && ( *wild !=
'?' ) )
920 else if( ( *wild == *str ) || ( *wild ==
'?' ) )
932 while( *wild ==
'*' )
944 static const wxString modifiers( wxT(
"pnuµμmkKM" ) );
946 if( !aString.length() )
952 if( modifiers.Find( aString[ 0 ] ) >= 0 )
954 modifier = aString[ 0 ];
955 units = aString.Mid( 1 ).Trim();
960 units = aString.Mid( 0 ).Trim();
964 && !units.IsSameAs( wxT(
"F" ),
false )
965 && !units.IsSameAs( wxT(
"hz" ),
false )
966 && !units.IsSameAs( wxT(
"W" ),
false )
967 && !units.IsSameAs( wxT(
"V" ),
false )
968 && !units.IsSameAs( wxT(
"A" ),
false )
969 && !units.IsSameAs( wxT(
"H" ),
false ) )
974 if( modifier ==
'p' )
976 if( modifier ==
'n' )
978 else if( modifier ==
'u' || modifier == wxS(
"µ" )[0] || modifier == wxS(
"μ" )[0] )
980 else if( modifier ==
'm' )
982 else if( modifier ==
'k' || modifier ==
'K' )
984 else if( modifier ==
'M' )
986 else if( modifier ==
'G' )
1006 value->Replace( wxS(
" " ), wxEmptyString );
1008 wxChar ambiguousSeparator =
'?';
1009 wxChar thousandsSeparator =
'?';
1010 bool thousandsSeparatorFound =
false;
1011 wxChar decimalSeparator =
'?';
1012 bool decimalSeparatorFound =
false;
1015 for(
int ii = (
int) value->length() - 1; ii >= 0; --ii )
1017 wxChar c = value->GetChar( ii );
1019 if( c >=
'0' && c <=
'9' )
1023 else if( c ==
'.' || c ==
',' )
1025 if( decimalSeparator !=
'?' || thousandsSeparator !=
'?' )
1029 if( c == decimalSeparator )
1031 if( thousandsSeparatorFound )
1033 else if( decimalSeparatorFound )
1036 decimalSeparatorFound =
true;
1038 else if( c == thousandsSeparator )
1043 thousandsSeparatorFound =
true;
1046 else if( ambiguousSeparator !=
'?' )
1050 if( c == ambiguousSeparator )
1053 thousandsSeparator = ambiguousSeparator;
1054 thousandsSeparatorFound =
true;
1055 decimalSeparator = c ==
'.' ?
',' :
'.';
1060 decimalSeparator = ambiguousSeparator;
1061 decimalSeparatorFound =
true;
1062 thousandsSeparator = c;
1063 thousandsSeparatorFound =
true;
1075 if( ( ii == 1 && value->GetChar( 0 ) ==
'0' ) || digits != 3 )
1077 decimalSeparator = c;
1078 decimalSeparatorFound =
true;
1079 thousandsSeparator = c ==
'.' ?
',' :
'.';
1083 ambiguousSeparator = c;
1096 if( decimalSeparator ==
'?' && thousandsSeparator ==
'?' )
1098 const struct lconv* lc = localeconv();
1100 decimalSeparator = lc->decimal_point[0];
1101 thousandsSeparator = decimalSeparator ==
'.' ?
',' :
'.';
1105 value->Replace( thousandsSeparator, wxEmptyString );
1106 value->Replace( decimalSeparator,
'.' );
1119 wxString strFWordBeg, strFWordMid, strFWordEnd;
1120 wxString strSWordBeg, strSWordMid, strSWordEnd;
1123 SplitString( fWord, &strFWordBeg, &strFWordMid, &strFWordEnd );
1124 SplitString( sWord, &strSWordBeg, &strSWordMid, &strSWordEnd );
1127 int isEqual = strFWordBeg.CmpNoCase( strSWordBeg );
1133 else if( isEqual < 0 )
1140 double lFirstNumber = 0;
1141 double lSecondNumber = 0;
1142 bool endingIsModifier =
false;
1149 strFWordMid.ToDouble( &lFirstNumber );
1150 strSWordMid.ToDouble( &lSecondNumber );
1152 endingIsModifier |=
ApplyModifier( lFirstNumber, strFWordEnd );
1153 endingIsModifier |=
ApplyModifier( lSecondNumber, strSWordEnd );
1155 if( lFirstNumber > lSecondNumber )
1157 else if( lFirstNumber < lSecondNumber )
1160 else if( !endingIsModifier )
1161 return strFWordEnd.CmpNoCase( strSWordEnd );
1170 wxString* strBeginning,
1171 wxString* strDigits,
1174 static const wxString separators( wxT(
".," ) );
1177 strBeginning->Empty();
1182 if( strToSplit.length() == 0 )
1188 for( ii = (strToSplit.length() - 1); ii >= 0; ii-- )
1190 if( wxIsdigit( strToSplit[ii] ) )
1197 *strBeginning = strToSplit;
1202 *strEnd = strToSplit.substr( ii + 1 );
1205 int position = ii + 1;
1207 for( ; ii >= 0; ii-- )
1209 if( !wxIsdigit( strToSplit[ii] ) && separators.Find( strToSplit[ii] ) < 0 )
1215 *strDigits = strToSplit.substr( 0, position );
1221 *strDigits = strToSplit.substr( ii + 1, position - ii - 1 );
1222 *strBeginning = strToSplit.substr( 0, ii + 1 );
1236 int index = aStr.Len() - 1;
1240 const char chr = aStr.GetChar( index );
1242 if( chr <
'0' || chr >
'9' )
1245 number += ( chr -
'0' ) * base;
1262 bool changed =
false;
1264 result.reserve( aName->length() );
1266 for( std::string::iterator it = aName->begin(); it != aName->end(); ++it )
1271 StrPrintf( &result,
"%c", aReplaceChar );
1292 bool changed =
false;
1294 result.reserve( aName.Length() );
1297 for( wxString::iterator it = aName.begin(); it != aName.end(); ++it )
1299 if( illWChars.Find( *it ) != wxNOT_FOUND )
1302 result += aReplaceChar;
1304 result += wxString::Format(
"%%%02x", *it );
1321void wxStringSplit(
const wxString& aText, wxArrayString& aStrings, wxChar aSplitter )
1325 for(
unsigned ii = 0; ii < aText.Length(); ii++ )
1327 if( aText[ii] == aSplitter )
1329 aStrings.Add( tmp );
1338 if( !tmp.IsEmpty() )
1339 aStrings.Add( tmp );
1345 struct lconv* lc = localeconv();
1346 char sep = lc->decimal_point[0];
1347 unsigned sep_pos = aStringValue.Find( sep );
1352 unsigned min_len = sep_pos + aTrailingZeroAllowed + 1;
1354 while( aStringValue.Len() > min_len )
1356 if( aStringValue.Last() ==
'0' )
1357 aStringValue.RemoveLast();
1369 if( aValue != 0.0 && std::fabs( aValue ) <= 0.0001 )
1371 buf = fmt::format(
"{:.16f}", aValue );
1374 while( !buf.empty() && buf[buf.size() - 1] ==
'0' )
1381 if( buf[buf.size() - 1] ==
'.' )
1388 buf = fmt::format(
"{:.10g}", aValue );
1400 if( aValue != 0.0 && std::fabs( aValue ) <= 0.0001 )
1404 len = snprintf( buf,
sizeof( buf ),
"%.16f", aValue );
1406 while( --len > 0 && buf[len] ==
'0' )
1409 if( buf[len] ==
'.' || buf[len] ==
',' )
1418 len = snprintf( buf,
sizeof( buf ),
"%.10g", aValue );
1421 return std::string( buf, len );
1428 wxString line = wxString::FromUTF8( cstring );
1430 if( line.IsEmpty() )
1432 line = wxConvCurrent->cMB2WC( cstring );
1434 if( line.IsEmpty() )
1435 line = wxString::From8BitData( cstring );
1445 wxString line = wxString::FromUTF8( aString );
1447 if( line.IsEmpty() )
1449 line = wxConvCurrent->cMB2WC( aString.c_str() );
1451 if( line.IsEmpty() )
1452 line = wxString::From8BitData( aString.c_str() );
1461 wxString uriPathAndFileName;
1463 wxCHECK( aFileUri.StartsWith( wxS(
"file://" ), &uriPathAndFileName ), aFileUri );
1465 wxString tmp = uriPathAndFileName;
1466 wxString retv = wxS(
"file://" );
1468 tmp.Replace( wxS(
"\\" ), wxS(
"/" ) );
1469 tmp.Replace( wxS(
":" ), wxS(
"" ) );
1471 if( !tmp.IsEmpty() && tmp[0] !=
'/' )
1472 tmp = wxS(
"/" ) + tmp;
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
This file contains miscellaneous commonly used macros and functions.
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
int StrPrintf(std::string *result, const char *format,...)
This is like sprintf() but the output is appended to a std::string instead of to a character array.
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 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)
static const char illegalFileNameChars[]
Illegal file name characters used to ensure file names will be valid on all supported platforms.
wxString LinkifyHTML(wxString aStr)
Wraps links in HTML tags.
bool convertSeparators(wxString *value)
wxString GetIllegalFileNameWxChars()
wxString From_UTF8(const char *cstring)
bool ConvertSmartQuotesAndDashes(wxString *aString)
Convert curly quotes and em/en dashes to straight quotes and dashes.
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.
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
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 ...
std::string FormatDouble2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 This function is intended in...
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 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.
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.
#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.