KiCad PCB EDA Suite
Loading...
Searching...
No Matches
common.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2014-2020 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <eda_base_frame.h>
27#include <kiplatform/app.h>
28#include <project.h>
29#include <common.h>
30#include <confirm.h>
31#include <env_vars.h>
32#include <advanced_config.h>
33#include <reporter.h>
34#include <macros.h>
35#include <string_utils.h>
37#include <mutex>
38#include <wx/config.h>
39#include <wx/log.h>
40#include <wx/msgdlg.h>
41#include <wx/stdpaths.h>
42#include <wx/url.h>
43#include <wx/utils.h>
44#include <wx/regex.h>
45
46#ifdef _WIN32
47#include <windows.h>
48#endif
49
50
52{
56#ifdef __WINDOWS__
57 Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-)
58#endif
60};
61
62wxString ExpandTextVars( const wxString& aSource, const PROJECT* aProject, int aFlags )
63{
64 std::function<bool( wxString* )> projectResolver = [&]( wxString* token ) -> bool
65 {
66 return aProject->TextVarResolver( token );
67 };
68
69 return ExpandTextVars( aSource, &projectResolver, aFlags );
70}
71
72
73wxString ExpandTextVars( const wxString& aSource, const std::function<bool( wxString* )>* aResolver, int aFlags,
74 int aDepth )
75{
76 wxString newbuf;
77 size_t sourceLen = aSource.length();
78
79 newbuf.Alloc( sourceLen ); // best guess (improves performance)
80
81 // Get the maximum recursion depth from advanced config
83
84 for( size_t i = 0; i < sourceLen; ++i )
85 {
86 // Skip over existing escape markers without processing their contents
87 // This prevents expanding ${} or @{} that are inside escaped expressions
88 if( i + 14 <= sourceLen && aSource.Mid( i, 14 ) == wxT( "<<<ESC_DOLLAR:" ) )
89 {
90 // Copy the entire escape marker including contents until matching closing }
91 newbuf.append( wxT( "<<<ESC_DOLLAR:" ) );
92 i += 14;
93
94 // Count braces to find the matching closing }
95 int braceCount = 1;
96 while( i < sourceLen && braceCount > 0 )
97 {
98 if( aSource[i] == '{' )
99 braceCount++;
100 else if( aSource[i] == '}' )
101 braceCount--;
102
103 newbuf.append( aSource[i] );
104 i++;
105 }
106 i--; // Back up one since the for loop will increment
107 continue;
108 }
109 else if( i + 10 <= sourceLen && aSource.Mid( i, 10 ) == wxT( "<<<ESC_AT:" ) )
110 {
111 // Copy the entire escape marker including contents until matching closing }
112 newbuf.append( wxT( "<<<ESC_AT:" ) );
113 i += 10;
114
115 // Count braces to find the matching closing }
116 int braceCount = 1;
117 while( i < sourceLen && braceCount > 0 )
118 {
119 if( aSource[i] == '{' )
120 braceCount++;
121 else if( aSource[i] == '}' )
122 braceCount--;
123
124 newbuf.append( aSource[i] );
125 i++;
126 }
127 i--; // Back up one since the for loop will increment
128 continue;
129 }
130
131 // Handle escaped variable references: \${...} or \@{...}
132 // Replace with escape markers that won't be expanded by multi-pass loops
133 // The markers will be converted back to ${...} or @{...} only at the final display stage
134 if( aSource[i] == '\\' && i + 1 < sourceLen )
135 {
136 if( ( aSource[i + 1] == '$' || aSource[i + 1] == '@' ) && i + 2 < sourceLen && aSource[i + 2] == '{' )
137 {
138 // Replace \${ with <<<ESC_DOLLAR: and \@{ with <<<ESC_AT:
139 // Using unique delimiters without braces to avoid confusing the expression evaluator
140 if( aSource[i + 1] == '$' )
141 newbuf.append( wxT( "<<<ESC_DOLLAR:" ) );
142 else
143 newbuf.append( wxT( "<<<ESC_AT:" ) );
144 i += 2;
145
146 // Copy everything until the matching closing brace, including the brace
147 int braceDepth = 1;
148 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
149 {
150 if( aSource[i] == '{' )
151 braceDepth++;
152 else if( aSource[i] == '}' )
153 braceDepth--;
154
155 newbuf.append( aSource[i] );
156 }
157 i--; // Adjust because loop will increment
158 continue;
159 }
160 }
161
162 if( ( aSource[i] == '$' || aSource[i] == '@' ) && i + 1 < sourceLen && aSource[i + 1] == '{' )
163 {
164 bool isMathExpr = ( aSource[i] == '@' );
165 wxString token;
166 int braceDepth = 1; // Track brace depth for nested expressions like @{${VAR}}
167
168 for( i = i + 2; i < sourceLen; ++i )
169 {
170 // Skip over escape markers - don't count their braces
171 // This prevents <<<ESC_DOLLAR:X} from interfering with outer brace counting
172 if( i + 14 <= sourceLen && aSource.Mid( i, 14 ) == wxT( "<<<ESC_DOLLAR:" ) )
173 {
174 token.append( wxT( "<<<ESC_DOLLAR:" ) );
175 i += 14;
176
177 // Copy contents until matching closing brace (tracking nested braces)
178 int markerBraceCount = 1;
179
180 while( i < sourceLen && markerBraceCount > 0 )
181 {
182 if( aSource[i] == '{' )
183 markerBraceCount++;
184 else if( aSource[i] == '}' )
185 markerBraceCount--;
186
187 token.append( aSource[i] );
188 i++;
189 }
190
191 i--; // Adjust for outer loop increment
192 continue;
193 }
194 else if( i + 10 <= sourceLen && aSource.Mid( i, 10 ) == wxT( "<<<ESC_AT:" ) )
195 {
196 token.append( wxT( "<<<ESC_AT:" ) );
197 i += 10;
198
199 // Copy contents until matching closing brace (tracking nested braces)
200 int markerBraceCount = 1;
201
202 while( i < sourceLen && markerBraceCount > 0 )
203 {
204 if( aSource[i] == '{' )
205 markerBraceCount++;
206 else if( aSource[i] == '}' )
207 markerBraceCount--;
208
209 token.append( aSource[i] );
210 i++;
211 }
212
213 i--; // Adjust for outer loop increment
214 continue;
215 }
216
217 if( aSource[i] == '{' )
218 {
219 braceDepth++;
220 token.append( aSource[i] );
221 }
222 else if( aSource[i] == '}' )
223 {
224 braceDepth--;
225
226 if( braceDepth == 0 )
227 break; // Found the matching closing brace
228 else
229 token.append( aSource[i] );
230 }
231 else
232 {
233 token.append( aSource[i] );
234 }
235 }
236
237 if( token.IsEmpty() )
238 continue;
239
240 // For math expressions @{...}, recursively expand any nested ${...} variables
241 // but DON'T evaluate the math - leave that for EvaluateText() called by the user
242 if( isMathExpr )
243 {
244 if( ( token.Contains( wxT( "${" ) ) || token.Contains( wxT( "@{" ) ) ) && aDepth < maxDepth )
245 {
246 token = ExpandTextVars( token, aResolver, aFlags, aDepth + 1 );
247 }
248
249 // Return the expression with variables expanded but NOT evaluated
250 // The caller will use EvaluateText() to handle the math evaluation
251 newbuf.append( wxT( "@{" ) + token + wxT( "}" ) );
252 }
253 else // Variable reference ${...}
254 {
255 // Recursively expand nested variables BEFORE passing to resolver
256 // This ensures innermost variables are expanded first (standard evaluation order)
257 if( ( token.Contains( wxT( "${" ) ) || token.Contains( wxT( "@{" ) ) ) && aDepth < maxDepth )
258 {
259 token = ExpandTextVars( token, aResolver, aFlags, aDepth + 1 );
260
261 // Also evaluate math expressions after expanding variables
262 if( token.Contains( wxT( "@{" ) ) )
263 {
264 // Must not be static. ExpandTextVars runs on parallel workers
265 // (e.g. CONNECTION_GRAPH) and a shared evaluator races on its
266 // internal error collector.
267 EXPRESSION_EVALUATOR evaluator;
268 token = evaluator.Evaluate( token );
269 }
270 }
271
272 if( ( aFlags & FOR_ERC_DRC ) == 0
273 && ( token.StartsWith( wxS( "ERC_WARNING" ) ) || token.StartsWith( wxS( "ERC_ERROR" ) )
274 || token.StartsWith( wxS( "DRC_WARNING" ) ) || token.StartsWith( wxS( "DRC_ERROR" ) ) ) )
275 {
276 // Only show user-defined warnings/errors during ERC/DRC
277 }
278 else if( aResolver && ( *aResolver )( &token ) )
279 {
280 newbuf.append( token );
281 }
282 else
283 {
284 // Token not resolved: leave the reference unchanged
285 newbuf.append( "${" + token + "}" );
286 }
287 }
288 }
289 else
290 {
291 newbuf.append( aSource[i] );
292 }
293 }
294
295 return newbuf;
296}
297
298
299wxString ResolveTextVars( const wxString& aSource, const std::function<bool( wxString* )>* aResolver, int& aDepth )
300{
301 // Multi-pass resolution to handle nested variables like ${J601:UNIT(${ROW})}
302 // and math expressions like @{${ROW}-1}
303 wxString text = aSource;
305
306 // Must not be static. ResolveTextVars runs on parallel workers (e.g.
307 // CONNECTION_GRAPH) and a shared evaluator races on its internal error
308 // collector.
309 EXPRESSION_EVALUATOR evaluator;
310
311 while( ( text.Contains( wxT( "${" ) ) || text.Contains( wxT( "@{" ) ) ) && ++aDepth <= maxDepth )
312 {
313 // Always expand when ${} or @{} present to handle escape sequences (\${} and \@{})
314 // ExpandTextVars converts escapes to markers and expands ${} variables
315 // Don't expand if the only remaining $ or @ are in escape markers like <<<ESC_DOLLAR: or <<<ESC_AT:
316 if( text.Contains( wxT( "${" ) ) || text.Contains( wxT( "@{" ) ) )
317 text = ExpandTextVars( text, aResolver );
318
319 // Only evaluate if there are @{} expressions present (not escape markers)
320 // Don't evaluate if the only remaining @ are in escape markers like <<<ESC_AT:
321 if( text.Contains( wxT( "@{" ) ) )
322 text = evaluator.Evaluate( text ); // Evaluate math expressions
323 }
324
325 return text;
326}
327
328
329wxString GetGeneratedFieldDisplayName( const wxString& aSource )
330{
331 std::function<bool( wxString* )> tokenExtractor = [&]( wxString* token ) -> bool
332 {
333 *token = *token; // token value is the token name
334 return true;
335 };
336
337 return ExpandTextVars( aSource, &tokenExtractor );
338}
339
340
341bool IsGeneratedField( const wxString& aSource )
342{
343 static wxRegEx expr( wxS( "^\\$\\{\\w*\\}$" ) );
344 return expr.Matches( aSource );
345}
346
347
348wxString DescribeRef( const wxString& aRef )
349{
350 if( aRef.IsEmpty() )
351 return wxT( "<i>" ) + _( "unannotated footprint" ) + wxT( " </i>" );
352 else
353 return EscapeHTML( aRef );
354}
355
356
357//
358// Stolen from wxExpandEnvVars and then heavily optimized
359//
360wxString KIwxExpandEnvVars( const wxString& str, const PROJECT* aProject, std::set<wxString>* aSet = nullptr )
361{
362 // If the same string is inserted twice, we have a loop
363 if( aSet )
364 {
365 if( auto [_, result] = aSet->insert( str ); !result )
366 return str;
367 }
368
369 size_t strlen = str.length();
370
371 wxString strResult;
372 strResult.Alloc( strlen ); // best guess (improves performance)
373
374 auto getVersionedEnvVar = []( const wxString& aMatch, wxString& aResult ) -> bool
375 {
376 for( const wxString& var : ENV_VAR::GetPredefinedEnvVars() )
377 {
378 if( var.Matches( aMatch ) )
379 {
380 const auto value = ENV_VAR::GetEnvVar<wxString>( var );
381
382 if( !value )
383 continue;
384
385 aResult += *value;
386 return true;
387 }
388 }
389
390 return false;
391 };
392
393 for( size_t n = 0; n < strlen; n++ )
394 {
395 wxUniChar str_n = str[n];
396
397 switch( str_n.GetValue() )
398 {
399#ifdef __WINDOWS__
400 case wxT( '%' ):
401#endif // __WINDOWS__
402 case wxT( '$' ):
403 {
404 Bracket bracket;
405#ifdef __WINDOWS__
406 if( str_n == wxT( '%' ) )
407 {
408 bracket = Bracket_Windows;
409 }
410 else
411#endif // __WINDOWS__
412 if( n == strlen - 1 )
413 {
414 bracket = Bracket_None;
415 }
416 else
417 {
418 switch( str[n + 1].GetValue() )
419 {
420 case wxT( '(' ):
421 bracket = Bracket_Normal;
422 str_n = str[++n]; // skip the bracket
423 break;
424
425 case wxT( '{' ):
426 bracket = Bracket_Curly;
427 str_n = str[++n]; // skip the bracket
428 break;
429
430 default: bracket = Bracket_None;
431 }
432 }
433
434 size_t m = n + 1;
435
436 if( m >= strlen )
437 break;
438
439 wxUniChar str_m = str[m];
440
441 while( wxIsalnum( str_m ) || str_m == wxT( '_' ) || str_m == wxT( ':' ) )
442 {
443 if( ++m == strlen )
444 {
445 str_m = 0;
446 break;
447 }
448
449 str_m = str[m];
450 }
451
452 wxString strVarName( str.c_str() + n + 1, m - n - 1 );
453
454 // NB: use wxGetEnv instead of wxGetenv as otherwise variables
455 // set through wxSetEnv may not be read correctly!
456 bool expanded = false;
457 wxString tmp = strVarName;
458
459 if( aProject && aProject->TextVarResolver( &tmp ) )
460 {
461 strResult += tmp;
462 expanded = true;
463 }
464 else if( wxGetEnv( strVarName, &tmp ) )
465 {
466 strResult += tmp;
467 expanded = true;
468 }
469 // Replace unmatched older variables with current locations
470 // If the user has the older location defined, that will be matched
471 // first above. But if they do not, this will ensure that their board still
472 // displays correctly
473 else if( strVarName.Contains( "KISYS3DMOD" ) || strVarName.Matches( "KICAD*_3DMODEL_DIR" ) )
474 {
475 if( getVersionedEnvVar( "KICAD*_3DMODEL_DIR", strResult ) )
476 expanded = true;
477 }
478 else if( strVarName.Matches( "KICAD*_SYMBOL_DIR" ) )
479 {
480 if( getVersionedEnvVar( "KICAD*_SYMBOL_DIR", strResult ) )
481 expanded = true;
482 }
483 else if( strVarName.Matches( "KICAD*_FOOTPRINT_DIR" ) )
484 {
485 if( getVersionedEnvVar( "KICAD*_FOOTPRINT_DIR", strResult ) )
486 expanded = true;
487 }
488 else if( strVarName.Matches( "KICAD*_3RD_PARTY" ) )
489 {
490 if( getVersionedEnvVar( "KICAD*_3RD_PARTY", strResult ) )
491 expanded = true;
492 }
493 else
494 {
495 // variable doesn't exist => don't change anything
496#ifdef __WINDOWS__
497 if( bracket != Bracket_Windows )
498#endif
499 if( bracket != Bracket_None )
500 strResult << str[n - 1];
501
502 strResult << str_n << strVarName;
503 }
504
505 // When a versioned-wildcard branch matched but no env var was found, emit
506 // the original ${VARNAME} text so the closing-bracket handler can append the
507 // closing bracket. Without this, the handler emits only '}', producing a
508 // garbage path like "}/Device.kicad_sym" instead of the full unexpanded var.
509 if( !expanded && bracket != Bracket_None )
510 {
511 auto isVersionedWildcard =
512 strVarName.Contains( wxT( "KISYS3DMOD" ) )
513 || strVarName.Matches( wxT( "KICAD*_3DMODEL_DIR" ) )
514 || strVarName.Matches( wxT( "KICAD*_SYMBOL_DIR" ) )
515 || strVarName.Matches( wxT( "KICAD*_FOOTPRINT_DIR" ) )
516 || strVarName.Matches( wxT( "KICAD*_3RD_PARTY" ) );
517
518 if( isVersionedWildcard )
519 {
520#ifdef __WINDOWS__
521 if( bracket != Bracket_Windows )
522#endif
523 strResult << str[n - 1];
524
525 strResult << str_n << strVarName;
526 }
527 }
528
529 // check the closing bracket
530 if( bracket != Bracket_None )
531 {
532 if( m == strlen || str_m != (wxChar) bracket )
533 {
534 // under MSW it's common to have '%' characters in the registry
535 // and it's annoying to have warnings about them each time, so
536 // ignore them silently if they are not used for env vars
537 //
538 // under Unix, OTOH, this warning could be useful for the user to
539 // understand why isn't the variable expanded as intended
540#ifndef __WINDOWS__
541 wxLogWarning( _( "Environment variables expansion failed: missing '%c' "
542 "at position %u in '%s'." ),
543 (char) bracket, (unsigned int) ( m + 1 ), str.c_str() );
544#endif // __WINDOWS__
545 }
546 else
547 {
548 // skip closing bracket unless the variables wasn't expanded
549 if( !expanded )
550 strResult << (wxChar) bracket;
551
552 m++;
553 }
554 }
555
556 n = m - 1; // skip variable name
557 str_n = str[n];
558 }
559 break;
560
561 case wxT( '\\' ):
562 // backslash can be used to suppress special meaning of % and $
563 if( n < strlen - 1 && ( str[n + 1] == wxT( '%' ) || str[n + 1] == wxT( '$' ) ) )
564 {
565 str_n = str[++n];
566 strResult += str_n;
567
568 break;
569 }
570
572
573 default: strResult += str_n;
574 }
575 }
576
577 std::set<wxString> loop_check;
578 auto first_pos = strResult.find_first_of( wxS( "{(%" ) );
579 auto last_pos = strResult.find_last_of( wxS( "})%" ) );
580
581 if( first_pos != strResult.npos && last_pos != strResult.npos && first_pos != last_pos )
582 strResult = KIwxExpandEnvVars( strResult, aProject, aSet ? aSet : &loop_check );
583
584 return strResult;
585}
586
587
588const wxString ExpandEnvVarSubstitutions( const wxString& aString, const PROJECT* aProject )
589{
590 // wxGetenv( wchar_t* ) is not re-entrant on linux.
591 // Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
592 static std::mutex getenv_mutex;
593
594 std::lock_guard<std::mutex> lock( getenv_mutex );
595
596 // We reserve the right to do this another way, by providing our own member function.
597 return KIwxExpandEnvVars( aString, aProject );
598}
599
600
601const wxString ResolveUriByEnvVars( const wxString& aUri, const PROJECT* aProject )
602{
603 wxString uri = ExpandTextVars( aUri, aProject );
604
605 return ExpandEnvVarSubstitutions( uri, aProject );
606}
607
608
609bool EnsureFileDirectoryExists( wxFileName* aTargetFullFileName, const wxString& aBaseFilename, REPORTER* aReporter )
610{
611 wxString msg;
612 wxString baseFilePath = wxFileName( aBaseFilename ).GetPath();
613
614 // make aTargetFullFileName path, which is relative to aBaseFilename path (if it is not
615 // already an absolute path) absolute:
616 if( !aTargetFullFileName->MakeAbsolute( baseFilePath ) )
617 {
618 if( aReporter )
619 {
620 msg.Printf( _( "Cannot make path '%s' absolute with respect to '%s'." ), aTargetFullFileName->GetPath(),
621 baseFilePath );
622 aReporter->Report( msg, RPT_SEVERITY_ERROR );
623 }
624
625 return false;
626 }
627
628 // Ensure the path of aTargetFullFileName exists, and create it if needed:
629 wxString outputPath( aTargetFullFileName->GetPath() );
630
631 if( !wxFileName::DirExists( outputPath ) )
632 {
633 // Make every directory provided when the provided path doesn't exist
634 if( wxFileName::Mkdir( outputPath, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
635 {
636 if( aReporter )
637 {
638 msg.Printf( _( "Output directory '%s' created." ), outputPath );
639 aReporter->Report( msg, RPT_SEVERITY_INFO );
640 return true;
641 }
642 }
643 else
644 {
645 if( aReporter )
646 {
647 msg.Printf( _( "Cannot create output directory '%s'." ), outputPath );
648 aReporter->Report( msg, RPT_SEVERITY_ERROR );
649 }
650
651 return false;
652 }
653 }
654
655 return true;
656}
657
658
659wxString EnsureFileExtension( const wxString& aFilename, const wxString& aExtension )
660{
661 wxString newFilename( aFilename );
662
663 // It's annoying to throw up nag dialogs when the extension isn't right. Just fix it,
664 // but be careful not to destroy existing after-dot-text that isn't actually a bad
665 // extension, such as "Schematic_1.1".
666 if( newFilename.Lower().AfterLast( '.' ) != aExtension )
667 {
668 if( !newFilename.EndsWith( '.' ) )
669 newFilename.Append( '.' );
670
671 newFilename.Append( aExtension );
672 }
673
674 return newFilename;
675}
676
677
678wxString JoinExtensions( const std::vector<std::string>& aExts )
679{
680 wxString joined;
681
682 for( const std::string& ext : aExts )
683 {
684 if( !joined.empty() )
685 joined << wxS( ", " );
686
687 joined << wxS( "*." ) << ext;
688 }
689
690 return joined;
691}
692
693
701
708bool matchWild( const char* pat, const char* text, bool dot_special )
709{
710 if( !*text )
711 {
712 /* Match if both are empty. */
713 return !*pat;
714 }
715
716 const char *m = pat, *n = text, *ma = nullptr, *na = nullptr;
717 int just = 0, acount = 0, count = 0;
718
719 if( dot_special && ( *n == '.' ) )
720 {
721 /* Never match so that hidden Unix files
722 * are never found. */
723 return false;
724 }
725
726 for( ;; )
727 {
728 if( *m == '*' )
729 {
730 ma = ++m;
731 na = n;
732 just = 1;
733 acount = count;
734 }
735 else if( *m == '?' )
736 {
737 m++;
738
739 if( !*n++ )
740 return false;
741 }
742 else
743 {
744 if( *m == '\\' )
745 {
746 m++;
747
748 /* Quoting "nothing" is a bad thing */
749 if( !*m )
750 return false;
751 }
752
753 if( !*m )
754 {
755 /*
756 * If we are out of both strings or we just
757 * saw a wildcard, then we can say we have a
758 * match
759 */
760 if( !*n )
761 return true;
762
763 if( just )
764 return true;
765
766 just = 0;
767 goto not_matched;
768 }
769
770 /*
771 * We could check for *n == NULL at this point, but
772 * since it's more common to have a character there,
773 * check to see if they match first (m and n) and
774 * then if they don't match, THEN we can check for
775 * the NULL of n
776 */
777 just = 0;
778
779 if( *m == *n )
780 {
781 m++;
782 count++;
783 n++;
784 }
785 else
786 {
787 not_matched:
788
789 /*
790 * If there are no more characters in the
791 * string, but we still need to find another
792 * character (*m != NULL), then it will be
793 * impossible to match it
794 */
795 if( !*n )
796 return false;
797
798 if( ma )
799 {
800 m = ma;
801 n = ++na;
802 count = acount;
803 }
804 else
805 return false;
806 }
807 }
808 }
809}
810
811
813{
815 return false;
816
817 KICAD_MESSAGE_DIALOG dialog( nullptr,
818 _( "This operating system is not supported "
819 "by KiCad and its dependencies." ),
820 _( "Unsupported Operating System" ), wxOK | wxICON_EXCLAMATION );
821
822 dialog.SetExtendedMessage( _( "Any issues with KiCad on this system cannot "
823 "be reported to the official bugtracker." ) );
824 dialog.ShowModal();
825
826 return true;
827}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
High-level wrapper for evaluating mathematical and string expressions in wxString format.
wxString Evaluate(const wxString &aInput)
Main evaluation function - processes input string and evaluates all} expressions.
Container for project specific data.
Definition project.h:66
virtual bool TextVarResolver(wxString *aToken) const
Definition project.cpp:85
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:75
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:104
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition common.cpp:588
wxString JoinExtensions(const std::vector< std::string > &aExts)
Join a list of file extensions for use in a file dialog.
Definition common.cpp:678
wxString GetGeneratedFieldDisplayName(const wxString &aSource)
Returns any variables unexpanded, e.g.
Definition common.cpp:329
const wxString ResolveUriByEnvVars(const wxString &aUri, const PROJECT *aProject)
Replace any environment and/or text variables in URIs.
Definition common.cpp:601
wxString EnsureFileExtension(const wxString &aFilename, const wxString &aExtension)
It's annoying to throw up nag dialogs when the extension isn't right.
Definition common.cpp:659
bool WarnUserIfOperatingSystemUnsupported()
Checks if the operating system is explicitly unsupported and displays a disclaimer message box.
Definition common.cpp:812
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition common.cpp:62
bool matchWild(const char *pat, const char *text, bool dot_special)
Performance enhancements to file and directory operations.
Definition common.cpp:708
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Make aTargetFullFileName absolute and create the path of this file if it doesn't yet exist.
Definition common.cpp:609
wxString KIwxExpandEnvVars(const wxString &str, const PROJECT *aProject, std::set< wxString > *aSet=nullptr)
Definition common.cpp:360
Bracket
Definition common.cpp:52
@ Bracket_Max
Definition common.cpp:59
@ Bracket_None
Definition common.cpp:53
@ Bracket_Normal
Definition common.cpp:54
@ Bracket_Curly
Definition common.cpp:55
bool IsGeneratedField(const wxString &aSource)
Returns true if the string is generated, e.g contains a single text var reference.
Definition common.cpp:341
wxString DescribeRef(const wxString &aRef)
Returns a user-visible HTML string describing a footprint reference designator.
Definition common.cpp:348
wxString ResolveTextVars(const wxString &aSource, const std::function< bool(wxString *)> *aResolver, int &aDepth)
Multi-pass text variable expansion and math expression evaluation.
Definition common.cpp:299
The common library.
#define FOR_ERC_DRC
Expand '${var-name}' templates in text.
Definition common.h:96
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:52
#define _(s)
Base window classes and related definitions.
Functions related to environment variables, including help functions.
int m_ResolveTextRecursionDepth
The number of recursions to resolve text variables.
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:83
KICOMMON_API std::optional< VAL_TYPE > GetEnvVar(const wxString &aEnvVarName)
Get an environment variable as a specific type, if set correctly.
KICOMMON_API const std::vector< wxString > & GetPredefinedEnvVars()
Get the list of pre-defined environment variables.
Definition env_vars.cpp:61
bool IsOperatingSystemUnsupported()
Checks if the Operating System is explicitly unsupported and we want to prevent users from sending bu...
Definition unix/app.cpp:70
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
wxString result
Test unit parsing edge cases and error handling.