class_library.cpp 24.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
 * Copyright (C) 2008-2011 Wayne Stambaugh <stambaughw@verizon.net>
 * Copyright (C) 2004-2011 KiCad Developers, see change_log.txt for contributors.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

26 27 28
/**
 * @file class_library.cpp
 */
29

30 31 32 33 34 35 36 37
#include <fctsys.h>
#include <gr_basic.h>
#include <macros.h>
#include <kicad_string.h>
#include <gestfich.h>
#include <eda_doc.h>
#include <wxstruct.h>
#include <richio.h>
38

39 40
#include <general.h>
#include <class_library.h>
41

42
#include <boost/foreach.hpp>
43

44
#include <wx/tokenzr.h>
45
#include <wx/regex.h>
46

47
static const wxString duplicate_name_msg =
48 49
    _(  "Library '%s' has duplicate entry name '%s'.\n"
        "This may cause some unexpected behavior when loading components into a schematic." );
50 51


52
bool operator==( const CMP_LIBRARY& aLibrary, const wxString& aName )
53
{
54 55
    // See our header class_libentry.h for function Cmp_KEEPCASE().
    return Cmp_KEEPCASE( aLibrary.GetName(), aName ) == 0;
56 57 58
}


59
bool operator!=( const CMP_LIBRARY& aLibrary, const wxString& aName )
60
{
61
    return !( aLibrary == aName );
62
}
63

64

65
bool operator<( const CMP_LIBRARY& aItem1, const CMP_LIBRARY& aItem2 )
66 67
{
    /* The cache library always is sorted to the end of the library list. */
68
    if( aItem2.IsCache() )
69
        return true;
70

71
    if( aItem1.IsCache() )
72 73
        return false;

74
    // If the sort order array isn't set, then sort alphabetically except.
75
    if( CMP_LIBRARY::GetSortOrder().IsEmpty() )
76
        return Cmp_KEEPCASE( aItem1.GetName(), aItem2.GetName() ) < 0;
77

78 79
    int i1 = CMP_LIBRARY::GetSortOrder().Index( aItem1.GetName(), false );
    int i2 = CMP_LIBRARY::GetSortOrder().Index( aItem2.GetName(), false );
80 81 82 83 84 85 86 87 88 89 90 91 92 93

    if( i1 == wxNOT_FOUND && i2 == wxNOT_FOUND )
        return true;

    if( i1 == wxNOT_FOUND && i2 != wxNOT_FOUND )
        return false;

    if( i1 != wxNOT_FOUND && i2 == wxNOT_FOUND )
        return true;

    return ( i1 - i2 ) < 0;
}


94
CMP_LIBRARY::CMP_LIBRARY( int aType, const wxFileName& aFileName )
95
{
96
    type = aType;
97 98 99 100 101 102 103
    isModified = false;
    timeStamp = 0;
    isCache = false;
    timeStamp = wxDateTime::Now();

    if( aFileName.IsOk() )
        fileName = aFileName;
104
    else
105
        fileName = wxFileName( wxT( "unnamed.lib" ) );
106 107
}

108

109
CMP_LIBRARY::~CMP_LIBRARY()
110
{
111 112
    for( LIB_ALIAS_MAP::iterator it=aliases.begin();  it!=aliases.end();  it++ )
    {
113 114 115
        LIB_ALIAS*      alias = (*it).second;
        LIB_COMPONENT*  component = alias->GetComponent();

116 117 118 119 120
        alias = component->RemoveAlias( alias );

        if( alias == NULL )
            delete component;
    }
121 122
}

123

124
void CMP_LIBRARY::GetEntryNames( wxArrayString& aNames, bool aSort, bool aMakeUpperCase )
125
{
126 127 128
    LIB_ALIAS_MAP::iterator it;

    for( it=aliases.begin();  it!=aliases.end();  it++ )
129
    {
130
        if( aMakeUpperCase )
131
        {
132
            wxString tmp = (*it).first;
133
            tmp.MakeUpper();
134
            aNames.Add( tmp );
135
        }
136
        else
137
        {
138
            aNames.Add( (*it).first );
139
        }
140 141
    }

142 143
    if( aSort )
        aNames.Sort();
144 145 146
}


147 148 149 150 151
/**
 * Function sortFunction
 * simple function used as comparator to sort a std::vector<wxArrayString>&.
 *
 * @param aItem1 is the first comparison parameter.
152
 * @param aItem2 is the second.
153 154 155 156 157 158 159 160 161
 * @return bool - which item should be put first in the sorted list.
 */
bool sortFunction( wxArrayString aItem1, wxArrayString aItem2 )
{
    return( aItem1.Item( 0 ) < aItem2.Item( 0 ) );
}


void CMP_LIBRARY::SearchEntryNames( std::vector<wxArrayString>& aNames,
162 163 164
                                    const wxString& aNameSearch,
                                    const wxString& aKeySearch,
                                    bool aSort )
165
{
166 167
    LIB_ALIAS_MAP::iterator it;

168
    for( it = aliases.begin();  it!=aliases.end();  it++ )
169
    {
170
        if( !aKeySearch.IsEmpty() && KeyWordOk( aKeySearch, (*it).second->GetKeyWords() ) )
171 172 173 174 175 176
        {
            wxArrayString item;
            item.Add( (*it).first );
            item.Add( GetLogicalName() );
            aNames.push_back( item );
        }
177

178
        if( !aNameSearch.IsEmpty() && WildCompareString( aNameSearch,
179
                                                         (*it).second->GetName(), false ) )
180 181 182 183 184 185
        {
            wxArrayString item;
            item.Add( (*it).first );
            item.Add( GetLogicalName() );
            aNames.push_back( item );
        }
186
    }
187

188
    if( aSort )
189
        std::sort( aNames.begin(), aNames.end(), sortFunction );
190 191 192
}


193
void CMP_LIBRARY::SearchEntryNames( wxArrayString& aNames, const wxRegEx& aRe, bool aSort )
194
{
195
    if( !aRe.IsValid() )
196 197
        return;

198 199
    LIB_ALIAS_MAP::iterator it;

200
    for( it = aliases.begin();  it!=aliases.end();  it++ )
201
    {
202 203
        if( aRe.Matches( (*it).second->GetKeyWords() ) )
            aNames.Add( (*it).first );
204 205
    }

206 207
    if( aSort )
        aNames.Sort();
208 209 210
}


211
bool CMP_LIBRARY::Conflicts( LIB_COMPONENT* aComponent )
212
{
213 214 215 216
    wxCHECK_MSG( aComponent != NULL, false,
                 wxT( "Cannot test NULL component for conflicts in library " ) + GetName() );

    for( size_t i=0;  i<aComponent->m_aliases.size();  i++ )
217
    {
218 219 220 221
        LIB_ALIAS_MAP::iterator it = aliases.find( aComponent->m_aliases[i]->GetName() );

        if( it != aliases.end() )
            return true;
222
    }
223

224
    return false;
225 226 227
}


228
LIB_ALIAS* CMP_LIBRARY::FindEntry( const wxString& aName )
229
{
230
    LIB_ALIAS_MAP::iterator it = aliases.find( aName );
231 232

    if( it != aliases.end() )
233
        return (*it).second;
234 235 236 237

    return NULL;
}

238

239
LIB_ALIAS* CMP_LIBRARY::GetFirstEntry()
240
{
241
    if( aliases.size() )
242
        return (*aliases.begin()).second;
243 244 245
    else
        return NULL;
}
246

247

248
LIB_COMPONENT* CMP_LIBRARY::FindComponent( const wxString& aName )
249
{
250

251 252 253 254 255 256 257 258 259 260 261 262
#if 0 && defined(DEBUG)
    if( !aName.Cmp( wxT( "TI_STELLARIS_BOOSTERPACK" ) ) )
    {
        int breakhere = 1;
        (void) breakhere;
    }
#endif

    LIB_COMPONENT*  component = NULL;
    LIB_ALIAS*      entry = FindEntry( aName );

    if( entry )
263
        component = entry->GetComponent();
264

265 266 267 268
    return component;
}


269
bool CMP_LIBRARY::AddAlias( LIB_ALIAS* aAlias )
270
{
271 272 273 274 275 276 277 278 279
    wxASSERT( aAlias );

#if 0 && defined(DEBUG)
    if( !aAlias->GetName().Cmp( wxT( "TI_STELLARIS_BOOSTERPACK" ) ) )
    {
        int breakhere = 1;
        (void) breakhere;
    }
#endif
280

281 282 283
    LIB_ALIAS_MAP::iterator it = aliases.find( aAlias->GetName() );

    if( it != aliases.end() )
284 285 286 287
    {
        wxString msg;

        msg.Printf( _( "Cannot add duplicate alias <%s> to library <%s>." ),
288 289
                    GetChars( aAlias->GetName() ),
                    GetChars( fileName.GetName() ) );
290
        return false;
291 292
    }

293 294
    aliases[ aAlias->GetName() ] = aAlias;
    isModified = true;
295
    return true;
296 297 298
}


299
LIB_COMPONENT* CMP_LIBRARY::AddComponent( LIB_COMPONENT* aComponent )
300
{
301
    if( !aComponent )
302
        return NULL;
303

304 305
    // Conflict detection: See if already existing aliases exist,
    // and if yes, ask user for continue or abort
306 307 308
    // Special case: if the library is the library cache of the project,
    // old aliases are always removed to avoid conflict,
    //      and user is not prompted )
309
    if( Conflicts( aComponent ) && !IsCache() )
310
    {
311 312 313 314
        wxFAIL_MSG( wxT( "Cannot add component <" ) + aComponent->GetName() +
                    wxT( "> to library <" ) + GetName() + wxT( "> due to name conflict." ) );
        return NULL;
    }
315

316
    LIB_COMPONENT* newCmp = new LIB_COMPONENT( *aComponent, this );
317

318
    for( size_t i = 0; i < newCmp->m_aliases.size(); i++ )
319
    {
320
        wxString aliasname = newCmp->m_aliases[i]->GetName();
321
        LIB_ALIAS* alias = FindAlias( aliasname );
322

323
        if( alias != NULL )
324
            RemoveEntry( alias );
325

326
        aliases[ aliasname ] = newCmp->m_aliases[i];
327 328
    }

329
    isModified = true;
330

331 332 333
    return newCmp;
}

334

335
LIB_ALIAS* CMP_LIBRARY::RemoveEntry( LIB_ALIAS* aEntry )
336
{
337
    wxCHECK_MSG( aEntry != NULL, NULL, wxT( "NULL pointer cannot be removed from library." ) );
338

339
    LIB_ALIAS_MAP::iterator it = aliases.find( aEntry->GetName() );
340

341 342
    if( it == aliases.end() )
        return NULL;
343

344
    // If the entry pointer doesn't match the name it is mapped to in the library, we
345
    // have done something terribly wrong.
346 347 348
    wxCHECK_MSG( (*it).second == aEntry, NULL,
                 wxT( "Pointer mismatch while attempting to remove entry <" ) +
                 aEntry->GetName() + wxT( "> from library <" ) + GetName() + wxT( ">." ) );
349

350 351 352
    LIB_ALIAS* alias = (LIB_ALIAS*) aEntry;
    LIB_COMPONENT* component = alias->GetComponent();
    alias = component->RemoveAlias( alias );
353

354
    if( alias == NULL )
355
    {
356
        delete component;
357

358 359 360 361
        if( aliases.size() > 1 )
        {
            LIB_ALIAS_MAP::iterator next = it;
            next++;
362

363 364
            if( next == aliases.end() )
                next = aliases.begin();
365

366 367
            alias = (*next).second;
        }
368 369
    }

370 371
    aliases.erase( it );
    isModified = true;
372

373
    return alias;
374 375 376
}


377 378
LIB_COMPONENT* CMP_LIBRARY::ReplaceComponent( LIB_COMPONENT* aOldComponent,
                                              LIB_COMPONENT* aNewComponent )
379
{
380 381
    wxASSERT( aOldComponent != NULL );
    wxASSERT( aNewComponent != NULL );
382

383 384 385 386 387
    /* Remove the old root component.  The component will automatically be deleted
     * when all it's aliases are deleted.  Do not place any code that accesses
     * aOldComponent inside this loop that gets evaluated after the last alias is
     * removed in RemoveEntry().  Failure to heed this warning will result in a
     * segfault.
388
     */
389 390 391
    size_t i = aOldComponent->m_aliases.size();

    while( i != 0 )
392
    {
393
        i -= 1;
394
        RemoveEntry( aOldComponent->m_aliases[ i ] );
395
    }
396

397 398 399
    LIB_COMPONENT* newCmp = new LIB_COMPONENT( *aNewComponent, this );

    // Add new aliases to library alias map.
400
    for( i = 0; i < newCmp->m_aliases.size(); i++ )
401
    {
402
        aliases[ newCmp->m_aliases[ i ]->GetName() ] = newCmp->m_aliases[ i ];
403 404
    }

405
    isModified = true;
406

407 408 409 410
    return newCmp;
}


411
LIB_ALIAS* CMP_LIBRARY::GetNextEntry( const wxString& aName )
412
{
413 414
    if( aliases.empty() )
        return NULL;
415

416
    LIB_ALIAS_MAP::iterator it = aliases.find( aName );
417 418

    it++;
419

420 421
    if( it == aliases.end() )
        it = aliases.begin();
422

423
    return (*it).second;
424 425 426
}


427
LIB_ALIAS* CMP_LIBRARY::GetPreviousEntry( const wxString& aName )
428
{
429 430
    if( aliases.empty() )
        return NULL;
431

432
    LIB_ALIAS_MAP::iterator it = aliases.find( aName );
433

434 435 436 437
    if( it == aliases.begin() )
        it = aliases.end();

    it--;
438

439
    return (*it).second;
440 441
}

442

443
bool CMP_LIBRARY::Load( wxString& aErrorMsg )
444
{
445
    FILE*          file;
446
    char*          line;
447
    LIB_COMPONENT* libEntry;
448
    wxString       msg;
449

450
    if( fileName.GetFullPath().IsEmpty() )
451
    {
452
        aErrorMsg = _( "The component library file name is not set." );
453 454 455
        return false;
    }

456
    file = wxFopen( fileName.GetFullPath(), wxT( "rt" ) );
457

458
    if( file == NULL )
459
    {
460
        aErrorMsg = _( "The file could not be opened." );
461 462 463
        return false;
    }

464 465 466
    FILE_LINE_READER reader( file, fileName.GetFullPath() );

    if( !reader.ReadLine() )
467
    {
468
        aErrorMsg = _( "The file is empty!" );
469 470 471 472
        return false;
    }

    /* There is no header if this is a symbol library. */
473
    if( type == LIBRARY_TYPE_EESCHEMA )
474 475 476
    {
        wxString tmp;

477 478
        line = reader.Line();

479
        header = FROM_UTF8( line );
480

481
        wxStringTokenizer tkn( header );
482 483 484 485 486 487

        /*
         * The file header (first line) in library versions 2.0 and lower
         * apparently started with EESchema-LIB.  Sometime after 2.0, it
         * was changed to EESchema-LIBRARY.  Therefore, the test for
         * EESchema-LIB will work in both cases.  Don't change this unless
488
         * backwards compatibility is no longer required.
489 490 491 492
         */
        if( !tkn.HasMoreTokens()
            || !tkn.GetNextToken().Upper().StartsWith(wxT( "EESCHEMA-LIB" ) ) )
        {
493
            aErrorMsg = _( "The file is NOT an Eeschema library!" );
494 495 496 497 498
            return false;
        }

        if( !tkn.HasMoreTokens() )
        {
499
            aErrorMsg = _( "The file header is missing version and time stamp information." );
500 501 502 503 504
            return false;
        }

        if( tkn.GetNextToken() != wxT( "Version" ) || !tkn.HasMoreTokens() )
        {
505
            aErrorMsg = wxT( "The file header version information is invalid." );
506 507 508 509 510 511 512 513 514 515 516
            return false;
        }

        long major, minor;
        wxStringTokenizer vers( tkn.GetNextToken(), wxT( "." ) );

        if( !vers.HasMoreTokens() || !vers.GetNextToken().ToLong( &major )
            || major < 1L || !vers.HasMoreTokens()
            || !vers.GetNextToken().ToLong( & minor ) || minor < 0L
            || minor > 99 )
        {
517
#if 0   // Note for developers:
518 519
        // Not sure this warning is very useful: old designs *must* be always loadable
            wxLogWarning( wxT( "The component library <%s> header version \
520
number is invalid.\n\nIn future versions of Eeschema this library may not \
521 522
load correctly.  To resolve this problem open the library in the library \
editor and save it.  If this library is the project cache library, save \
523
the current schematic." ),
524
                          GetChars( GetName() ) );
525
#endif
526 527 528
        }
        else
        {
529 530
            versionMajor = (int) major;
            versionMinor = (int) minor;
531 532 533
        }
    }

534
    while( reader.ReadLine() )
535
    {
536 537
        line = reader.Line();

538
        if( type == LIBRARY_TYPE_EESCHEMA && strnicmp( line, "$HEADER", 7 ) == 0 )
539
        {
540
            if( !LoadHeader( reader ) )
541
            {
542
                aErrorMsg = _( "An error occurred attempting to read the header." );
543 544 545 546 547 548
                return false;
            }

            continue;
        }

549
        if( strnicmp( line, "DEF", 3 ) == 0 )
550 551
        {
            /* Read one DEF/ENDDEF part entry from library: */
552
            libEntry = new LIB_COMPONENT( wxEmptyString, this );
553

554
            if( libEntry->Load( reader, msg ) )
555
            {
556 557 558
                /* Check for duplicate entry names and warn the user about
                 * the potential conflict.
                 */
559
                if( FindEntry( libEntry->GetName() ) != NULL )
560
                {
561
                    wxString msg( wxGetTranslation( duplicate_name_msg ) );
charras's avatar
charras committed
562
                    wxLogWarning( msg,
563 564
                                  GetChars( fileName.GetName() ),
                                  GetChars( libEntry->GetName() ) );
565 566
                }

567
                LoadAliases( libEntry );
568 569 570
            }
            else
            {
571
                wxLogWarning( _( "Library <%s> component load error %s." ),
572
                              GetChars( fileName.GetName() ),
573
                              GetChars( msg ) );
574
                msg.Clear();
575
                delete libEntry;
576 577 578 579 580 581 582 583
            }
        }
    }

    return true;
}


584
void CMP_LIBRARY::LoadAliases( LIB_COMPONENT* component )
585
{
586
    wxCHECK_RET( component != NULL,
587
                 wxT( "Cannot load aliases of NULL component object.  Bad programmer!" ) );
588

589
    for( size_t i = 0; i < component->m_aliases.size(); i++ )
590
    {
591
        if( FindEntry( component->m_aliases[i]->GetName() ) != NULL )
592
        {
593
            wxString msg( wxGetTranslation( duplicate_name_msg ) );
charras's avatar
charras committed
594
            wxLogError( msg,
595
                        GetChars( fileName.GetName() ),
596
                        GetChars( component->m_aliases[i]->GetName() ) );
597 598
        }

599
        aliases[ component->m_aliases[i]->GetName() ] = component->m_aliases[i];
600 601 602 603
    }
}


604
bool CMP_LIBRARY::LoadHeader( LINE_READER& aLineReader )
605
{
606
    char* line, * text, * data;
607

608
    while( aLineReader.ReadLine() )
609
    {
610 611 612
        line = (char*) aLineReader;

        text = strtok( line, " \t\r\n" );
613
        data = strtok( NULL, " \t\r\n" );
614

615
        if( stricmp( text, "TimeStamp" ) == 0 )
616
            timeStamp = atol( data );
617

618
        if( stricmp( text, "$ENDHEADER" ) == 0 )
619
            return true;
620
    }
621

622
    return false;
623 624
}

625

626
bool CMP_LIBRARY::LoadDocs( wxString& aErrorMsg )
627
{
628
    int        lineNumber = 0;
629
    char       line[8000], * name, * text;
630 631 632 633
    LIB_ALIAS* entry;
    FILE*      file;
    wxString   msg;
    wxFileName fn = fileName;
634 635 636

    fn.SetExt( DOC_EXT );

637
    file = wxFopen( fn.GetFullPath(), wxT( "rt" ) );
638

639
    if( file == NULL )
640
    {
641 642
        aErrorMsg.Printf( _( "Could not open component document library file <%s>." ),
                          GetChars( fn.GetFullPath() ) );
643 644 645
        return false;
    }

646
    if( GetLine( file, line, &lineNumber, sizeof(line) ) == NULL )
647
    {
648 649 650
        aErrorMsg.Printf( _( "Component document library file <%s> is empty." ),
                          GetChars( fn.GetFullPath() ) );
        fclose( file );
651 652 653
        return false;
    }

654
    if( strnicmp( line, DOCFILE_IDENT, 10 ) != 0 )
655
    {
656 657 658
        aErrorMsg.Printf( _( "File <%s> is not a valid component library document file." ),
                          GetChars( fn.GetFullPath() ) );
        fclose( file );
659 660 661
        return false;
    }

662
    while( GetLine( file, line, &lineNumber, sizeof(line) ) )
663
    {
664
        if( strncmp( line, "$CMP", 4 ) != 0 )
665
        {
666
            aErrorMsg.Printf( wxT( "$CMP command expected in line %d, aborted." ), lineNumber );
667
            fclose( file );
668 669 670 671
            return false;
        }

        /* Read one $CMP/$ENDCMP part entry from library: */
672
        name = strtok( line + 5, "\n\r" );
673

674
        wxString cmpname = FROM_UTF8( name );
675

676
        entry = FindEntry( cmpname );
677

678
        while( GetLine( file, line, &lineNumber, sizeof(line) ) )
679
        {
680
            if( strncmp( line, "$ENDCMP", 7 ) == 0 )
681
                break;
682

683
            text = strtok( line + 2, "\n\r" );
684

685
            if( entry )
686
            {
687 688 689
                switch( line[0] )
                {
                case 'D':
690
                    entry->SetDescription( FROM_UTF8( text ) );
691
                    break;
692

693
                case 'K':
694
                    entry->SetKeyWords( FROM_UTF8( text ) );
695
                    break;
696

697
                case 'F':
698
                    entry->SetDocFileName( FROM_UTF8( text ) );
699 700
                    break;
                }
701 702 703 704
            }
        }
    }

705
    fclose( file );
706 707 708 709
    return true;
}


710
bool CMP_LIBRARY::Save( OUTPUTFORMATTER& aFormatter )
711
{
712
    if( isModified )
713
    {
714
        timeStamp = GetNewTimeStamp();
715
        isModified = false;
716 717 718 719
    }

    bool success = true;

720
    try
721
    {
722
        SaveHeader( aFormatter );
723

724 725 726 727
        for( LIB_ALIAS_MAP::iterator it=aliases.begin();  it!=aliases.end();  it++ )
        {
            if( !(*it).second->IsRoot() )
                continue;
728

729
            (*it).second->GetComponent()->Save( aFormatter );
730
        }
731

732
        aFormatter.Print( 0, "#\n#End Library\n" );
733 734 735 736 737
    }
    catch( IO_ERROR ioe )
    {
        success = false;
    }
738 739 740 741 742

    return success;
}


743
bool CMP_LIBRARY::SaveDocs( OUTPUTFORMATTER& aFormatter )
744
{
745
    bool success = true;
746

747
    try
748
    {
749
        aFormatter.Print( 0, "%s\n", DOCFILE_IDENT );
750

751
        for( LIB_ALIAS_MAP::iterator it=aliases.begin();  it!=aliases.end();  it++ )
752
        {
753 754
            if ( !(*it).second->SaveDoc( aFormatter ) )
                success = false;
755 756
        }

757
        aFormatter.Print( 0, "#\n#End Doc Library\n" );
758
    }
759
    catch( IO_ERROR ioe )
760
    {
761
        success = false;
762
    }
763

764 765 766 767
    return success;
}


768
bool CMP_LIBRARY::SaveHeader( OUTPUTFORMATTER& aFormatter )
769
{
770 771
    aFormatter.Print( 0, "%s %d.%d\n", LIBFILE_IDENT,
                      LIB_VERSION_MAJOR, LIB_VERSION_MINOR );
772

773
    aFormatter.Print( 0, "#encoding utf-8\n");
774

775
#if 0
776 777 778 779
    aFormatter.Print( 0, "$HEADER\n" );
    aFormatter.Print( 0, "TimeStamp %8.8lX\n", m_TimeStamp );
    aFormatter.Print( 0, "Parts %d\n", aliases.size() );
    aFormatter.Print( 0, "$ENDHEADER\n" ) != 1 );
780
#endif
781 782

    return true;
783 784 785
}


786 787 788
/*
 * The static library list and list management methods.
 */
789 790
CMP_LIBRARY_LIST CMP_LIBRARY::libraryList;
wxArrayString CMP_LIBRARY::libraryListSortOrder;
791 792


793
CMP_LIBRARY* CMP_LIBRARY::LoadLibrary( const wxFileName& aFileName, wxString& aErrorMsg )
794
{
795 796
    CMP_LIBRARY* lib = NULL;

797
    lib = new CMP_LIBRARY( LIBRARY_TYPE_EESCHEMA, aFileName );
798 799 800

    wxBusyCursor ShowWait;

801
    if( !lib->Load( aErrorMsg ) )
802 803 804 805 806
    {
        delete lib;
        return NULL;
    }

807 808
    if( USE_OLD_DOC_FILE_FORMAT( lib->versionMajor, lib->versionMinor ) )
        lib->LoadDocs( aErrorMsg );
809 810 811 812 813

    return lib;
}


814
bool CMP_LIBRARY::AddLibrary( const wxFileName& aFileName, wxString& aErrorMsg )
815 816 817 818
{
    CMP_LIBRARY* lib;

    /* Don't reload the library if it is already loaded. */
819
    lib = FindLibrary( aFileName.GetName() );
820 821 822 823

    if( lib != NULL )
        return true;

824
    lib = LoadLibrary( aFileName, aErrorMsg );
825 826 827 828

    if( lib == NULL )
        return false;

829
    libraryList.push_back( lib );
830 831 832 833 834

    return true;
}


835 836
bool CMP_LIBRARY::AddLibrary( const wxFileName& aFileName, wxString& aErrorMsg,
                              CMP_LIBRARY_LIST::iterator& aIterator )
837 838 839 840
{
    CMP_LIBRARY* lib;

    /* Don't reload the library if it is already loaded. */
841
    lib = FindLibrary( aFileName.GetName() );
842 843 844 845

    if( lib != NULL )
        return true;

846
    lib = LoadLibrary( aFileName, aErrorMsg );
847 848 849 850

    if( lib == NULL )
        return false;

851 852
    if( aIterator >= libraryList.begin() && aIterator < libraryList.end() )
        libraryList.insert( aIterator, lib );
853
    else
854
        libraryList.push_back( lib );
855 856 857 858 859

    return true;
}


860
void CMP_LIBRARY::RemoveLibrary( const wxString& aName )
861
{
862
    if( aName.IsEmpty() )
863 864 865 866
        return;

    CMP_LIBRARY_LIST::iterator i;

867
    for( i = libraryList.begin(); i < libraryList.end(); i++ )
868
    {
869
        if( i->GetName().CmpNoCase( aName ) == 0 )
870
        {
871
            CMP_LIBRARY::libraryList.erase( i );
872 873 874 875 876 877
            return;
        }
    }
}


878 879 880 881 882 883 884 885 886 887 888
bool CMP_LIBRARY::LibraryExists( const CMP_LIBRARY* aLibptr )
{
    BOOST_FOREACH( CMP_LIBRARY& lib, libraryList )
    {
        if( &lib == aLibptr )
            return true;
    }

    return false;
}

889

890
CMP_LIBRARY* CMP_LIBRARY::FindLibrary( const wxString& aName )
891
{
892
    BOOST_FOREACH( CMP_LIBRARY& lib, libraryList )
893
    {
894
        if( lib == aName )
895 896 897 898 899 900
            return &lib;
    }

    return NULL;
}

901 902

wxArrayString CMP_LIBRARY::GetLibraryNames( bool aSorted )
903
{
904
    wxArrayString cacheNames;
905 906
    wxArrayString names;

907
    BOOST_FOREACH( CMP_LIBRARY& lib, CMP_LIBRARY::libraryList )
908
    {
909
        if( lib.isCache && aSorted )
910
            cacheNames.Add( lib.GetName() );
911 912 913 914 915
        else
            names.Add( lib.GetName() );
    }

    /* Even sorted, the cache library is always at the end of the list. */
916
    if( aSorted )
917 918
        names.Sort();

919 920
    for( unsigned int i = 0; i<cacheNames.Count(); i++ )
        names.Add( cacheNames.Item( i ) );
921 922 923 924 925

    return names;
}


926 927
LIB_COMPONENT* CMP_LIBRARY::FindLibraryComponent( const wxString& aName,
                                                  const wxString& aLibraryName )
928 929 930
{
    LIB_COMPONENT* component = NULL;

931
    BOOST_FOREACH( CMP_LIBRARY& lib, libraryList )
932
    {
933
        if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
934 935
            continue;

936
        component = lib.FindComponent( aName );
937 938 939 940 941 942 943 944 945

        if( component != NULL )
            break;
    }

    return component;
}


946
LIB_ALIAS* CMP_LIBRARY::FindLibraryEntry( const wxString& aName, const wxString& aLibraryName )
947
{
948
    LIB_ALIAS* entry = NULL;
949

950
    BOOST_FOREACH( CMP_LIBRARY& lib, libraryList )
951
    {
952
        if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
953 954
            continue;

955
        entry = lib.FindEntry( aName );
956 957 958 959 960 961 962 963 964

        if( entry != NULL )
            break;
    }

    return entry;
}


965
void CMP_LIBRARY::RemoveCacheLibrary()
966 967 968
{
    CMP_LIBRARY_LIST::iterator i;

969
    for( i = libraryList.begin(); i < libraryList.end(); i++ )
970
    {
971 972
        if( i->isCache )
            libraryList.erase( i-- );
973
    }
974
}