/**********************************************************/ /* libclass.cpp */ /**********************************************************/ #include "fctsys.h" #include "gr_basic.h" #include "common.h" #include "kicad_string.h" #include "confirm.h" #include "gestfich.h" #include "eda_doc.h" #include "program.h" #include "libcmp.h" #include "general.h" #include "protos.h" #include "class_library.h" void FreeLibraryEntry( LibCmpEntry* Entry ) { SAFE_DELETE( Entry ); } bool operator==( const LibraryStruct& lib, const wxChar* name ) { return lib.m_Name.CmpNoCase( name ) == 0; } bool operator!=( const LibraryStruct& lib, const wxChar* name ) { return !( lib == name ); } LibraryStruct::LibraryStruct( int type, const wxString& name, const wxString& fullname ) { m_Type = type; /* type indicator */ m_Name = name; /* Name of library loaded. */ m_FullFileName = fullname; /* File name (with path) of library loaded. */ m_NumOfParts = 0; /* Number of parts this library has. */ m_Pnext = NULL; /* Point to next library in chain. */ m_Entries = NULL; m_Modified = FALSE; /* flag indicateur d'edition */ m_TimeStamp = 0; m_Flags = 0; m_IsLibCache = FALSE; m_DateTime = wxDateTime::Now(); } LibraryStruct::LibraryStruct( const wxChar* fileName ) { if( fileName == NULL ) m_fileName = wxT( "unnamed.lib" ); else m_fileName = fileName; } LibraryStruct::~LibraryStruct() { if( m_Entries ) PQFreeFunc( m_Entries, ( void( * ) ( void* ) )FreeLibraryEntry ); } void LibraryStruct::GetEntryNames( wxArrayString& names, bool sort ) { LibCmpEntry* entry = ( LibCmpEntry* ) PQFirst( &m_Entries, false ); while( entry != NULL ) { names.Add( entry->m_Name.m_Text ); entry = ( LibCmpEntry* ) PQNext( m_Entries, entry, NULL ); } if( sort ) names.Sort(); } void LibraryStruct::SearchEntryNames( wxArrayString& names, const wxString& nameSearch, const wxString& keySearch, bool sort ) { LibCmpEntry* Entry; Entry = (LibCmpEntry*) PQFirst( &m_Entries, false ); while( Entry ) { if( !keySearch.IsEmpty() && KeyWordOk( keySearch, Entry->m_KeyWord ) ) names.Add( Entry->m_Name.m_Text ); if( !nameSearch.IsEmpty() && WildCompareString( nameSearch, Entry->m_Name.m_Text, false ) ) names.Add( Entry->m_Name.m_Text ); Entry = (LibCmpEntry*) PQNext( m_Entries, Entry, NULL ); } } LibCmpEntry* LibraryStruct::FindEntry( const wxChar* name ) { static LibCmpEntry tmp( ALIAS, wxEmptyString ); tmp.m_Name.m_Text = name; PQCompFunc( ( PQCompFuncType ) LibraryEntryCompare ); return ( LibCmpEntry* ) PQFind( m_Entries, &tmp ); } LibCmpEntry* LibraryStruct::FindEntry( const wxChar* name, LibrEntryType type ) { LibCmpEntry* entry = FindEntry( name ); if( entry != NULL && entry->Type != ROOT && type == ROOT ) { EDA_LibCmpAliasStruct* alias = ( EDA_LibCmpAliasStruct* ) entry; const wxChar* rootname = alias->m_RootName.GetData(); PQCompFunc( (PQCompFuncType) LibraryEntryCompare ); entry = (LibCmpEntry*) PQFirst( &m_Entries, false ); while( entry ) { if( entry->m_Name.m_Text.CmpNoCase( rootname ) == 0 && entry->Type == ROOT ) break; entry = (LibCmpEntry*) PQNext( m_Entries, entry, NULL ); } } return entry; } EDA_LibComponentStruct* LibraryStruct::AddComponent( EDA_LibComponentStruct* cmp ) { wxASSERT( cmp != NULL ); EDA_LibCmpAliasStruct* Alias; EDA_LibComponentStruct* newCmp = CopyLibEntryStruct( cmp ); if( newCmp == NULL ) return NULL; newCmp->m_AliasList.Clear(); PQCompFunc( (PQCompFuncType) LibraryEntryCompare ); PQInsert( &m_Entries, (void*) newCmp ); m_NumOfParts++; m_Modified = 1; for( unsigned ii = 0; ii < cmp->m_AliasList.GetCount(); ii += ALIAS_NEXT ) { wxString aliasname = cmp->m_AliasList[ii + ALIAS_NAME]; newCmp->m_AliasList.Add( aliasname ); Alias = new EDA_LibCmpAliasStruct( aliasname, newCmp->m_Name.m_Text ); Alias->m_Doc = cmp->m_AliasList[ii + ALIAS_DOC]; Alias->m_KeyWord = cmp->m_AliasList[ii + ALIAS_KEYWORD]; Alias->m_DocFile = cmp->m_AliasList[ii + ALIAS_DOC_FILENAME]; PQInsert( &m_Entries, (void*) Alias ); m_NumOfParts++; } return newCmp; } void LibraryStruct::RemoveEntry( LibCmpEntry* entry ) { wxASSERT( entry != NULL ); EDA_LibComponentStruct* Root; EDA_LibCmpAliasStruct* Alias; PQCompFunc( (PQCompFuncType) LibraryEntryCompare ); m_Modified = 1; if( entry->Type == ALIAS ) { Alias = (EDA_LibCmpAliasStruct*) entry; Root = ( EDA_LibComponentStruct* ) FindEntry( Alias->m_RootName, ROOT ); /* Remove alias name from the root component alias list */ if( Root == NULL ) { wxLogWarning( wxT( "No root component found for alias <%s> in " \ "library <%s>." ), ( const wxChar* ) entry->m_Name.m_Text, ( const wxChar* ) m_Name ); } else { int index = Root->m_AliasList.Index( entry->m_Name.m_Text, false ); if( index == wxNOT_FOUND ) wxLogWarning( wxT( "Alias <%s> not found in component <%s> \ alias list in library <%s>" ), ( const wxChar* ) entry->m_Name.m_Text, ( const wxChar* ) Root->m_Name.m_Text, ( const wxChar* ) m_Name ); else Root->m_AliasList.RemoveAt( index ); } /* Effacement memoire pour cet alias */ PQDelete( &m_Entries, (void*) Alias ); SAFE_DELETE( Alias ); if( m_NumOfParts > 0 ) m_NumOfParts--; return; } Root = ( EDA_LibComponentStruct* ) entry; /* Entry is a component with no aliases so removal is simple */ if( Root->m_AliasList.GetCount() == 0 ) { PQDelete( &m_Entries, (void*) Root ); SAFE_DELETE( Root ); if( m_NumOfParts > 0 ) m_NumOfParts--; return; } /* Entry is a component with alias * We must change the first alias to a "root" component, and for all the * aliases we must change the root component (which is deleted) by the * first alias */ wxString AliasName = Root->m_AliasList[0]; /* The root component is not really deleted, it is renamed with the first * alias name */ Alias = (EDA_LibCmpAliasStruct*) FindEntry( AliasName, ALIAS ); if( Alias == NULL || Alias->Type == ROOT ) { wxLogWarning( wxT( "Alias <%s> for component <%s> not found in \ library <%s>" ), ( const wxChar* ) AliasName, ( const wxChar* ) Root->m_Name.m_Text, ( const wxChar* ) m_Name ); } else { if( m_NumOfParts > 0 ) m_NumOfParts--; /* remove the root component from library */ PQDelete( &m_Entries, Root ); /* remove the first alias from library*/ PQDelete( &m_Entries, Alias ); /* remove the first alias name from alias list: */ Root->m_AliasList.RemoveAt( 0 ); /* change the old name. New name for "root" is the name of the first * alias */ entry->m_Name.m_Text = AliasName; entry->m_Doc = Alias->m_Doc; entry->m_KeyWord = Alias->m_KeyWord; FreeLibraryEntry( ( LibCmpEntry* ) Alias ); /* root component (renamed) placed in library */ PQInsert( &m_Entries, entry ); } /* Change the "RootName", for other aliases */ for( unsigned ii = 0; ii < Root->m_AliasList.GetCount(); ii++ ) { AliasName = Root->m_AliasList[ii]; Alias = (EDA_LibCmpAliasStruct*) FindEntry( AliasName, ALIAS ); if( Alias == NULL ) { // Should not occurs. If happens, this is an error (or bug) wxLogWarning( wxT( "Alias <%s> for component <%s> not found in \ library <%s>." ), ( const wxChar* ) AliasName, ( const wxChar* ) Root->m_Name.m_Text, ( const wxChar* ) m_Name ); continue; } if( Alias->Type != ALIAS ) { // Should not occurs. If happens, this is an error (or bug) wxLogWarning( wxT( "Entry <%s> for component <%s> in library \ <%s> is not an alias." ), ( const wxChar* ) AliasName, ( const wxChar* ) Root->m_Name.m_Text, ( const wxChar* ) m_Name ); continue; } Alias->m_RootName = entry->m_Name.m_Text; } } LibCmpEntry* LibraryStruct::GetNextEntry( const wxChar* name ) { PQCompFunc( (PQCompFuncType) LibraryEntryCompare ); LibCmpEntry* entry = (LibCmpEntry*) PQFirst( &m_Entries, false ); while( entry ) { if( entry->m_Name.m_Text.CmpNoCase( name ) == 0 ) { entry = (LibCmpEntry*) PQNext( m_Entries, entry, NULL ); break; } entry = (LibCmpEntry*) PQNext( m_Entries, entry, NULL ); } if( entry == NULL ) entry = (LibCmpEntry*) PQFirst( &m_Entries, false ); return entry; } LibCmpEntry* LibraryStruct::GetPreviousEntry( const wxChar* name ) { LibCmpEntry* previousEntry = NULL; PQCompFunc( (PQCompFuncType) LibraryEntryCompare ); LibCmpEntry* entry = (LibCmpEntry*) PQFirst( &m_Entries, false ); while( entry ) { if( entry->m_Name.m_Text.CmpNoCase( name ) == 0 ) { if( previousEntry ) break; } previousEntry = entry; entry = (LibCmpEntry*) PQNext( m_Entries, entry, NULL ); } return previousEntry; } bool LibraryStruct::WriteHeader( FILE* file ) { char BufLine[1024]; bool succes = false; DateAndTime( BufLine ); if( fprintf( file, "%s %d.%d Date: %s\n", LIBFILE_IDENT, LIB_VERSION_MAJOR, LIB_VERSION_MINOR, BufLine ) < 0 ) succes = false; #if 0 if( ( fprintf( file, "$HEADER\n" ) < 0 ) || ( fprintf( file, "TimeStamp %8.8lX\n", m_TimeStamp ) < 0 ) || ( fprintf( file, "Parts %d\n", m_NumOfParts ) != 2 ) || ( fprintf( file, "$ENDHEADER\n" ) != 1 ) ) succes = false; #endif return succes; } bool LibraryStruct::Load( wxString& errMsg ) { FILE* f; int LineNum = 0; char Line[1024]; EDA_LibComponentStruct* LibEntry; wxString msg; if( m_FullFileName.IsEmpty() ) { errMsg = _( "library file name not set" ); return false; } f = wxFopen( m_FullFileName, wxT( "rt" ) ); if( f == NULL ) { errMsg = _( "could not open file" ); return false; } m_NumOfParts = 0; if( GetLine( f, Line, &LineNum, sizeof( Line ) ) == NULL ) { errMsg = _( "file is empty!" ); return false; } if( strnicmp( Line, LIBFILE_IDENT, 10 ) != 0 ) { errMsg = _( "file is NOT an EESCHEMA library!" ); return false; } PQInit( &m_Entries ); PQCompFunc( (PQCompFuncType) LibraryEntryCompare ); /* There is no header if this is a symbol library. */ if( m_Type == LIBRARY_TYPE_EESCHEMA ) m_Header = CONV_FROM_UTF8( Line ); while( GetLine( f, Line, &LineNum, sizeof( Line ) ) ) { if( m_Type == LIBRARY_TYPE_EESCHEMA && strnicmp( Line, "$HEADER", 7 ) == 0 ) { if( !ReadHeader( f, &LineNum ) ) { errMsg = _( "header read error" ); return false; } continue; } if( strnicmp( Line, "DEF", 3 ) == 0 ) { /* Read one DEF/ENDDEF part entry from library: */ LibEntry = new EDA_LibComponentStruct( NULL ); if( LibEntry->Load( f, Line, &LineNum, msg ) ) { /* If we are here, this part is O.k. - put it in: */ m_NumOfParts += 1; PQInsert( &m_Entries, LibEntry ); InsertAliases( &m_Entries, LibEntry ); } else { wxLogWarning( wxT( "Library <%s> component load error %s." ), (const wxChar*) m_Name, (const wxChar*) msg ); msg.Clear(); delete LibEntry; } } } return true; } void LibraryStruct::InsertAliases( PriorQue** PQ, EDA_LibComponentStruct* component ) { wxASSERT( component != NULL && PQ != NULL ); EDA_LibCmpAliasStruct* AliasEntry; unsigned ii; for( ii = 0; ii < component->m_AliasList.GetCount(); ii++ ) { AliasEntry = new EDA_LibCmpAliasStruct( component->m_AliasList[ii], component->m_Name.m_Text ); PQInsert( PQ, AliasEntry ); m_NumOfParts += 1; } } bool LibraryStruct::ReadHeader( FILE* libfile, int* LineNum ) { char Line[1024], * text, * data; while( GetLine( libfile, Line, LineNum, sizeof(Line) ) ) { text = strtok( Line, " \t\r\n" ); data = strtok( NULL, " \t\r\n" ); if( stricmp( text, "TimeStamp" ) == 0 ) m_TimeStamp = atol( data ); if( stricmp( text, "$ENDHEADER" ) == 0 ) return TRUE; } return FALSE; } bool LibraryStruct::SaveLibrary( const wxString& FullFileName ) { FILE* libfile, *docfile; wxString msg; wxFileName libFileName = FullFileName; wxFileName backupFileName = FullFileName; wxFileName docFileName = FullFileName; /* the old .lib file is renamed .bak */ if( libFileName.FileExists() ) { backupFileName.SetExt( wxT( "bak" ) ); wxRemoveFile( backupFileName.GetFullPath() ); if( !wxRenameFile( libFileName.GetFullPath(), backupFileName.GetFullPath() ) ) { msg = wxT( "Failed to rename old lib file " ) + backupFileName.GetFullPath(); DisplayError( NULL, msg ); } } docFileName.SetExt( DOC_EXT ); /* L'ancien fichier doc lib est renomme en .bck */ if( wxFileExists( docFileName.GetFullPath() ) ) { backupFileName = docFileName; backupFileName.SetExt( wxT( "bck" ) ); wxRemoveFile( backupFileName.GetFullPath() ); if( !wxRenameFile( docFileName.GetFullPath(), backupFileName.GetFullPath() ) ) { msg = wxT( "Failed to save old doc lib file " ) + backupFileName.GetFullPath(); DisplayError( NULL, msg ); } } libfile = wxFopen( libFileName.GetFullPath(), wxT( "wt" ) ); if( libfile == NULL ) { msg = wxT( "Failed to create Lib File " ) + libFileName.GetFullPath(); DisplayError( NULL, msg ); return false; } docfile = wxFopen( docFileName.GetFullPath(), wxT( "wt" ) ); if( docfile == NULL ) { msg = wxT( "Failed to create DocLib File " ) + docFileName.GetFullPath(); DisplayError( NULL, msg ); } m_Modified = 0; /* Creation de l'entete de la librairie */ m_TimeStamp = GetTimeStamp(); WriteHeader( libfile ); /* Sauvegarde des composant: */ char Line[256]; fprintf( docfile, "%s Date: %s\n", DOCFILE_IDENT, DateAndTime( Line ) ); bool success = true; LibCmpEntry* entry = ( LibCmpEntry* ) PQFirst( &m_Entries, false ); while( entry != NULL ) { if ( entry->Type == ROOT ) { EDA_LibComponentStruct* component = ( EDA_LibComponentStruct* ) entry; if ( ! component->Save( libfile ) ) success = false; } if ( docfile ) { if ( ! entry->SaveDoc( docfile ) ) success = false; } entry = ( LibCmpEntry* ) PQNext( m_Entries, entry, NULL ); } fprintf( libfile, "#\n#End Library\n" ); if ( docfile ) fprintf( docfile, "#\n#End Doc Library\n" ); fclose( libfile ); fclose( docfile ); return success; } wxString LibraryStruct::GetName() { return m_Name; }