41                              const wxFileName& aLibraryFileName, 
REPORTER* aReporter )
 
   43    std::map<wxString, wxString> mapOfAscFiles;
 
   44    std::map<wxString, wxString> mapOfAsyFiles;
 
   60    std::queue<wxString> ascFileQueue;
 
   61    ascFileQueue.push( aLibraryFileName.GetName().Lower() );
 
   63    LTSPICE_FILE rootAscFile( ascFileQueue.front(), { 0, 0 } );
 
   65    rootAscFile.
Sheet = aRootSheet;
 
   68    int parentSheetIndex = 0;
 
   71    std::vector<LTSPICE_FILE> ascFiles;
 
   73    ascFiles.push_back( rootAscFile );
 
   75    while( !ascFileQueue.empty() )
 
   80        wxString ascFilePath = mapOfAscFiles[ ascFileQueue.front() ];
 
   85        std::erase_if( newSubSchematicElements,
 
   91        for( 
LTSPICE_FILE& newSubSchematicElement : newSubSchematicElements )
 
   93            wxString asyName = newSubSchematicElement.ElementName;
 
   94            auto     it = mapOfAsyFiles.find( asyName );
 
   96            if( it == mapOfAsyFiles.end() )
 
  106                newSubSchematicElement.ParentIndex = parentSheetIndex;
 
  107                newSubSchematicElement.Screen = screen;
 
  108                newSubSchematicElement.Sheet = 
new SCH_SHEET();
 
  110                ascFileQueue.push( newSubSchematicElement.ElementName );
 
  111                ascFiles.push_back( newSubSchematicElement );
 
  120    for( 
unsigned int i = 0; i < ascFiles.size(); i++ )
 
  123        wxString buffer = 
SafeReadFile( mapOfAscFiles[ascFiles[i].ElementName], wxS( 
"r" ) );
 
  130            m_fileCache[ wxS( 
"ascFiles" ) ][ wxS( 
"parentFile" ) ] = buffer;
 
  133                wxASSERT( file.Sheet == 
nullptr && file.Screen == 
nullptr );
 
  142            std::map   tempAsyMap = 
ReadAsyFile( ascFiles[i], mapOfAsyFiles );
 
  143            wxString   ascFileName = ascFiles[i].ElementName;
 
  146            LIB_SYMBOL tempLibSymbol( ascFiles[i].ElementName );
 
  154            curSheet->
SetParent( ascFiles[ascFiles[i].ParentIndex].Sheet );
 
  158            wxString   sheetName = wxString::Format( wxS( 
"%s-subsheet-%d" ),
 
  159                                                     ascFiles[i].ElementName,
 
  162            sheetNameField->
SetText( sheetName );
 
  163            fileNameSheet->
SetText( sheetName + 
".kicad_sch" );
 
  165            curSheet->
SetScreen( ascFiles[i].Screen );
 
  167            curSheetPath = ascFiles[ascFiles[i].ParentIndex].SheetPath;
 
  170            ascFiles[i].SheetPath = curSheetPath;
 
  172            ascFiles[ascFiles[i].ParentIndex].Sheet->GetScreen()->Append( curSheet );
 
  180            ascFiles[i].SheetPath.push_back( curSheet );
 
  181            curSheetPath = ascFiles[i].SheetPath;
 
  184        std::vector<wxString> subSchematicAsyFiles;
 
  187            subSchematicAsyFiles.push_back( ascFile.ElementName );
 
  192            parser.
Parse( &curSheetPath, lt_ascs, subSchematicAsyFiles );
 
 
  203                                               std::map<wxString, wxString>& aMapOfAscFiles,
 
  204                                               std::map<wxString, wxString>& aMapOfAsyFiles,
 
  205                                               const std::vector<wxString>&  aBaseDirs )
 
  210        bool cont = aDir.GetFirst( &filename, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN );
 
  214            wxFileName 
path( aDir.GetName(), filename );
 
  216            auto logToMap = [&]( std::map<wxString, wxString>& aMapToLogTo, 
const wxString& aKey )
 
  218                if( aMapToLogTo.count( aKey ) )
 
  222                        m_reporter->Report( wxString::Format( 
_( 
"File at '%s' was ignored. Using previously " 
  223                                                                 "found file at '%s' instead." ),
 
  225                                                              aMapToLogTo.at( aKey ) ) );
 
  230                    aMapToLogTo.emplace( aKey, 
path.GetFullPath() );
 
  235            wxString extension = 
path.GetExt().Lower();
 
  237            for( 
size_t i = 0; i < aBaseDirs.size() + 1; i++ )
 
  241                for( 
size_t j = i; j < aBaseDirs.size(); j++ )
 
  242                    alias << aBaseDirs[j].Lower() << 
'/';
 
  244                alias << 
path.GetName().Lower();
 
  246                if( extension == wxS( 
"asc" ) )
 
  247                    logToMap( aMapOfAscFiles, alias );
 
  248                else if( extension == wxS( 
"asy" ) )
 
  249                    logToMap( aMapOfAsyFiles, alias );
 
  252            cont = aDir.GetNext( &filename );
 
  258        bool cont = aDir.GetFirst( &filename, wxEmptyString, wxDIR_DIRS | wxDIR_HIDDEN );
 
  262            wxFileName 
path( aDir.GetName(), filename );
 
  263            wxDir      subDir( 
path.GetFullPath() );
 
  265            std::vector<wxString> newBase = aBaseDirs;
 
  266            newBase.push_back( filename );
 
  270            cont = aDir.GetNext( &filename );
 
 
  557                                                               const wxString& aAsyFileContent,
 
  563    lt_symbol.
Name = aAscFileName;
 
  567    for( wxString line : wxSplit( aAsyFileContent, 
'\n' ) )
 
  571        wxArrayString tokens = wxSplit( line, 
' ' );
 
  573        if( tokens.IsEmpty() )
 
  576        wxString element = tokens[0].Upper();
 
  578        if( element == 
"LINE" )
 
  582            wxString lineWidth = tokens[1];
 
  583            wxString startPointX = tokens[2];
 
  584            wxString startPointY = tokens[3];
 
  585            wxString endPointX = tokens[4];
 
  586            wxString endPointY = tokens[5];
 
  590            lt_line.
Start = 
pointCheck( startPointX, startPointY, lineNumber, aAscFileName );
 
  591            lt_line.
End = 
pointCheck( endPointX, endPointY, lineNumber, aAscFileName );
 
  593            int lineStyleNumber = 0;  
 
  595            if( tokens.size() == 7 )
 
  597                wxString lineStyle = tokens[6];
 
  598                lineStyleNumber = 
integerCheck( lineStyle, lineNumber, aAscFileName );
 
  603            lt_symbol.
Lines.push_back( lt_line );
 
  605        else if( element == 
"RECTANGLE" )
 
  609            wxString lineWidth = tokens[1];
 
  610            wxString botRightX = tokens[2];
 
  611            wxString botRightY = tokens[3];
 
  612            wxString topLeftX = tokens[4];
 
  613            wxString topRightY = tokens[5];
 
  620            int lineStyleNumber = 0;  
 
  622            if( tokens.size() == 7 )
 
  624                wxString lineStyle = tokens[6];
 
  625                lineStyleNumber = 
integerCheck( lineStyle, lineNumber, aAscFileName );
 
  632        else if( element == 
"CIRCLE" )
 
  640            wxString lineWidth = tokens[1];
 
  641            wxString botRightX = tokens[2];
 
  642            wxString botRightY = tokens[3];
 
  643            wxString topLeftX = tokens[4];
 
  644            wxString topRightY = tokens[5];
 
  648            circle.BotRight = 
pointCheck( botRightX, botRightY, lineNumber, aAscFileName );
 
  649            circle.TopLeft = 
pointCheck( topLeftX, topRightY, lineNumber, aAscFileName );
 
  651            int lineStyleNumber = 0;  
 
  653            if( tokens.size() == 7 )
 
  655                wxString lineStyle = tokens[6];
 
  656                lineStyleNumber = 
integerCheck( lineStyle, lineNumber, aAscFileName );
 
  663        else if( element == 
"ARC" )
 
  672            wxString lineWidth = tokens[1];
 
  673            wxString botRightX = tokens[2];
 
  674            wxString botRightY = tokens[3];
 
  675            wxString topLeftX = tokens[4];
 
  676            wxString topRightY = tokens[5];
 
  677            wxString arcStartPointX = tokens[6];
 
  678            wxString arcStartPointY = tokens[7];
 
  679            wxString arcEndPointX = tokens[8];
 
  680            wxString arcEndPointY = tokens[9];
 
  686            arc.
ArcStart = 
pointCheck( arcStartPointX, arcStartPointY, lineNumber, aAscFileName );
 
  687            arc.
ArcEnd = 
pointCheck( arcEndPointX, arcEndPointY, lineNumber, aAscFileName );
 
  689            int lineStyleNumber = 0;  
 
  691            if( tokens.size() == 11 )
 
  693                wxString lineStyle = tokens[10];
 
  694                lineStyleNumber = 
integerCheck( lineStyle, lineNumber, aAscFileName );
 
  699            lt_symbol.
Arcs.push_back( arc );
 
  701        else if( element == 
"WINDOW" )
 
  705            wxString number = tokens[1];
 
  706            wxString windowPosX = tokens[2];
 
  707            wxString windowPosY = tokens[3];
 
  708            wxString justification = tokens[4];
 
  709            wxString fontSize = tokens[5];
 
  721            lt_symbol.
Windows.push_back( window );
 
  723        else if( element == 
"SYMATTR" )
 
  729            wxString key = tokens[1];
 
  730            wxString value = tokens[2];
 
  732            if( value == wxS( 
"\"\"" ) )
 
  733                value = wxEmptyString;
 
  737        else if( element == 
"PIN" )
 
  741            wxString pinLocationX = tokens[1];
 
  742            wxString pinLocationY = tokens[2];
 
  743            wxString Justification = tokens[3];
 
  744            wxString nameOffSet = tokens[4];
 
  747            pin.PinLocation = 
pointCheck( pinLocationX, pinLocationY, lineNumber,aAscFileName );
 
  751            lt_symbol.
Pins.push_back( 
pin );
 
  753        else if( element == 
"PINATTR" )
 
  759            wxString 
name = tokens[1];
 
  760            wxString Value = tokens[2];
 
  762            lt_symbol.
Pins.back().PinAttribute.insert( { 
name, Value } );
 
  764        else if( element == 
"SYMBOLTYPE" )
 
  768            wxString symbolType = tokens[1];
 
 
  804    std::vector<LT_ASC> ascFiles;
 
  806    for( 
const auto& [ fileName, contents ] : 
m_fileCache[ wxS( 
"ascFiles" ) ] )
 
  809        std::vector<LT_SYMBOL> symbolArray;
 
  819        for( wxString line : wxSplit( contents, 
'\n' ) )
 
  823            wxArrayString tokens = wxSplit( line, 
' ' );
 
  825            if( tokens.IsEmpty() )
 
  828            wxString element = tokens[0].Upper();
 
  830            if( element == 
"SHEET" )
 
  834                wxString sheetNumber = tokens[1];
 
  835                wxString sheetWidth = tokens[2];
 
  836                wxString sheetHeight = tokens[3];
 
  841            else if( element == 
"SYMBOL" )
 
  845                wxString symbolName = tokens[1];
 
  846                wxString posX = tokens[2];
 
  847                wxString posY = tokens[3];
 
  848                wxString rotate_mirror_option = tokens[4];
 
  850                symbolName.Replace( 
'\\', 
'/' );
 
  858                    ascFile.
Symbols.push_back( lt_symbol );
 
  871                    ascFile.
Symbols.push_back( lt_symbol );
 
  875            else if( element == 
"WIRE" )
 
  879                wxString startPointX = tokens[1];
 
  880                wxString startPointY = tokens[2];
 
  881                wxString endPointX = tokens[3];
 
  882                wxString endPointY = tokens[4];
 
  885                wire.
Start = 
pointCheck( startPointX, startPointY, lineNumber, fileName );
 
  886                wire.
End = 
pointCheck( endPointX, endPointY, lineNumber, fileName );
 
  888                ascFile.
Wires.push_back( wire );
 
  892            else if( element == 
"FLAG" )
 
  896                wxString posX = tokens[1];
 
  897                wxString posY = tokens[2];
 
  898                wxString 
name = tokens[3];
 
  908            else if( element == 
"DATAFLAG" )
 
  912                wxString posX = tokens[1];
 
  913                wxString posY = tokens[2];
 
  914                wxString expression = tokens[3];
 
  918                flag.Expression = expression;
 
  924            else if( element == 
"WINDOW" )
 
  928                wxString number = tokens[1];
 
  929                wxString windowPosX = tokens[2];
 
  930                wxString windowPosY = tokens[3];
 
  931                wxString justification = tokens[4];
 
  932                wxString fontSize = tokens[5];
 
  934                int        windowNumber = 
integerCheck( number, lineNumber, fileName );
 
  940                    if( candidate.WindowNumber == windowNumber )
 
  950                    window = &ascFile.
Symbols.back().Windows.back();
 
  960            else if( element == 
"SYMATTR" )
 
  966                wxString 
name = tokens[1];
 
  967                wxString value = tokens[2];
 
  969                if( value == wxS( 
"\"\"" ) )
 
  970                    value = wxEmptyString;
 
  972                ascFile.
Symbols.back().SymAttributes[ 
name.Upper() ] = value;
 
  974            else if( element == 
"LINE" )
 
  978                wxString lineWidth = tokens[1];
 
  979                wxString startPointX = tokens[2];
 
  980                wxString startPointY = tokens[3];
 
  981                wxString endPointX = tokens[4];
 
  982                wxString endPointY = tokens[5];
 
  986                lt_line.
Start = 
pointCheck( startPointX, startPointY, lineNumber, fileName );
 
  987                lt_line.
End = 
pointCheck( endPointX, endPointY, lineNumber, fileName );
 
  989                int lineStyleNumber = 0;  
 
  991                if( tokens.size() == 7 )
 
  993                    wxString lineStyle = tokens[6];
 
  994                    lineStyleNumber = 
integerCheck( lineStyle, lineNumber, fileName );
 
  999                ascFile.
Lines.push_back( lt_line );
 
 1003            else if( element == 
"RECTANGLE" )
 
 1008                wxString botRightX = tokens[2];
 
 1009                wxString botRightY = tokens[3];
 
 1010                wxString topLeftX = tokens[4];
 
 1011                wxString topRightY = tokens[5];
 
 1018                int lineStyleNumber = 0;  
 
 1020                if( tokens.size() == 7 )
 
 1022                    wxString lineStyle = tokens[6];
 
 1023                    lineStyleNumber = 
integerCheck( lineStyle, lineNumber, fileName );
 
 1032            else if( element == 
"CIRCLE" )
 
 1036                wxString lineWidth = tokens[1];
 
 1037                wxString botRightX = tokens[2];
 
 1038                wxString botRightY = tokens[3];
 
 1039                wxString topLeftX = tokens[4];
 
 1040                wxString topRightY = tokens[5];
 
 1044                circle.BotRight = 
pointCheck( botRightX, botRightY, lineNumber, fileName );
 
 1047                int lineStyleNumber = 0;  
 
 1049                if( tokens.size() == 7 )
 
 1051                    wxString lineStyle = tokens[6];
 
 1052                    lineStyleNumber = 
integerCheck( lineStyle, lineNumber, fileName );
 
 1061            else if( element == 
"ARC" )
 
 1070                wxString lineWidth = tokens[1];
 
 1071                wxString botRightX = tokens[2];
 
 1072                wxString botRightY = tokens[3];
 
 1073                wxString topLeftX = tokens[4];
 
 1074                wxString topRightY = tokens[5];
 
 1075                wxString arcStartPointX = tokens[6];
 
 1076                wxString arcStartPointY = tokens[7];
 
 1077                wxString arcEndPointX = tokens[8];
 
 1078                wxString arcEndPointY = tokens[9];
 
 1084                arc.
ArcEnd = 
pointCheck( arcStartPointX, arcStartPointY, lineNumber, fileName );
 
 1087                int lineStyleNumber = 0;  
 
 1089                if( tokens.size() == 11 )
 
 1091                    wxString lineStyle = tokens[10];
 
 1092                    lineStyleNumber = 
integerCheck( lineStyle, lineNumber, fileName );
 
 1097                ascFile.
Arcs.push_back( arc );
 
 1101            else if( element == 
"IOPIN" )
 
 1105                wxString pinLocationX = tokens[1];
 
 1106                wxString pinLocationY = tokens[2];
 
 1107                wxString pinPolarity = tokens[3];
 
 1113                ascFile.
Iopins.push_back( iopin );
 
 1116            else if( element == 
"TEXT" )
 
 1122                wxString positionX = tokens[1];
 
 1123                wxString positionY = tokens[2];
 
 1124                wxString justification = tokens[3];
 
 1125                wxString fontSize = tokens[4];
 
 1126                wxString value = tokens[5];
 
 1129                text.Offset = 
pointCheck( positionX, positionY, lineNumber, fileName );
 
 1133                if( value.StartsWith( wxS( 
"!" ), &
text.Value ) )
 
 1134                    text.Value.Replace( wxS( 
"! " ), wxS( 
"\n" ) );  
 
 1135                else if( value.StartsWith( wxS( 
";" ), &
text.Value ) )
 
 1136                    text.Value.Replace( wxS( 
"; " ), wxS( 
"\n" ) );  
 
 1140                text.Value.Replace( wxS( 
"\\n" ), wxS( 
"\n" ) );
 
 1145            else if( element == 
"BUSTAP" )
 
 1149                wxString startPointX = tokens[1];
 
 1150                wxString startPointY = tokens[2];
 
 1151                wxString endPointX = tokens[3];
 
 1152                wxString endPointY = tokens[4];
 
 1155                bustap.
Start = 
pointCheck( startPointX, startPointY, lineNumber, fileName );
 
 1156                bustap.
End = 
pointCheck( endPointX, endPointY, lineNumber, fileName );
 
 1158                ascFile.
Bustap.push_back( bustap );
 
 1162            else if( element == 
"VERSION" )
 
 1164                wxString versionNumber = tokens[1];
 
 1165                if( versionNumber.Contains( 
'.' ) )
 
 1167                    wxString majorStr = versionNumber.BeforeFirst( 
'.' );
 
 1168                    wxString minorStr = versionNumber.AfterFirst( 
'.' );
 
 1181        ascFiles.push_back( std::move( ascFile ) );