1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 2004-2021 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 /**
27  * @file symbol_library.h
28  * @brief Definition for symbol library class.
29  */
30 
31 #ifndef SYMBOL_LIBRARY_H
32 #define SYMBOL_LIBRARY_H
33 
34 #include <map>
35 #include <mutex>
36 #include <boost/ptr_container/ptr_vector.hpp>
37 #include <wx/filename.h>
38 
39 #include <sch_io_mgr.h>
40 #include <project.h>
41 
42 class LIB_SYMBOL;
43 class LIB_ID;
44 class LINE_READER;
45 class OUTPUTFORMATTER;
46 class SCH_LEGACY_PLUGIN;
47 class SCH_PLUGIN;
48 
49 
50 #define DOC_EXT           "dcm"
51 
52 /*
53  * Symbol Library version and file header  macros.
54  */
55 #define LIB_VERSION_MAJOR 2
56 #define LIB_VERSION_MINOR 4
57 
58 /* Must be the first line of symbol library (.lib) files. */
59 #define LIBFILE_IDENT     "EESchema-LIBRARY Version"
60 
61 #define LIB_VERSION( major, minor ) ( major * 100 + minor )
62 
63 #define IS_LIB_CURRENT_VERSION( major, minor )              \
64     (                                                       \
65         LIB_VERSION( major1, minor1 ) ==                    \
66         LIB_VERSION( LIB_VERSION_MAJOR, LIB_VERSION_MINOR)  \
67     )
68 
69 /*
70  * Library versions 2.4 and lower use the old separate library (.lib) and
71  * document (.dcm) files.  Symbol libraries after 2.4 merged the library
72  * and document files into a single library file.  This macro checks if the
73  * library version supports the old format
74  */
75 #define USE_OLD_DOC_FILE_FORMAT( major, minor )                 \
76     ( LIB_VERSION( major, minor ) <= LIB_VERSION( 2, 4 ) )
77 
78 enum class SCH_LIB_TYPE
79 {
80     LT_EESCHEMA,
81     LT_SYMBOL
82 };
83 
84 // Helper class to filter a list of libraries, and/or a list of SYMBOL_LIB
85 // in dialogs
86 class SCHLIB_FILTER
87 {
88 public:
SCHLIB_FILTER()89     SCHLIB_FILTER()
90     {
91         m_filterPowerSymbols = false;
92         m_forceLoad = false;
93     }
94 
95     /**
96      * add a lib name to the allowed libraries
97      */
AddLib(const wxString & aLibName)98     void AddLib( const wxString& aLibName )
99     {
100         m_allowedLibs.Add( aLibName );
101         m_forceLoad = false;
102     }
103 
104 
105     /**
106      * add a lib name to the allowed libraries
107      */
LoadFrom(const wxString & aLibName)108     void LoadFrom( const wxString& aLibName )
109     {
110         m_allowedLibs.Clear();
111         m_allowedLibs.Add( aLibName );
112         m_forceLoad = true;
113     }
114 
115     /**
116      * Clear the allowed libraries list (allows all libs)
117      */
ClearLibList()118     void ClearLibList()
119     {
120         m_allowedLibs.Clear();
121         m_forceLoad = false;
122     }
123 
124     /**
125      * Set the filtering of power symbols
126      */
FilterPowerSymbols(bool aFilterEnable)127     void FilterPowerSymbols( bool aFilterEnable )
128     {
129         m_filterPowerSymbols = aFilterEnable;
130     }
131 
132     // Accessors
133 
134     /**
135      * @return true if the filtering of power symbols is on
136      */
GetFilterPowerSymbols()137     bool GetFilterPowerSymbols() const { return m_filterPowerSymbols; }
138 
139 
140     /**
141      * @return am wxArrayString of the names of allowed libs
142      */
GetAllowedLibList()143     const wxArrayString& GetAllowedLibList() const { return m_allowedLibs; }
144 
145     /**
146      * @return the name of the lib to use to load a symbol, or an a empty string
147      * Useful to load (in lib editor or lib viewer) a symbol from a given library
148      */
GetLibSource()149     const wxString& GetLibSource() const
150     {
151         static wxString dummy;
152 
153         if( m_forceLoad && m_allowedLibs.GetCount() > 0 )
154             return m_allowedLibs[0];
155         else
156             return dummy;
157     }
158 
159 private:
160     wxArrayString m_allowedLibs;        ///< a list of lib names to list some libraries
161                                         ///< if empty: no filter
162     bool          m_filterPowerSymbols; ///< true to filter (show only) power symbols
163     bool          m_forceLoad;          // When true, load a symbol lib from the lib
164                                         // which is given in m_allowedLibs[0]
165 };
166 
167 
168 /* Helpers for creating a list of symbol libraries. */
169 class SYMBOL_LIB;
170 class wxRegEx;
171 
172 /**
173  * LIB_SYMBOL map sorting.
174  */
175 struct LibSymbolMapSort
176 {
operatorLibSymbolMapSort177     bool operator() ( const wxString& aItem1, const wxString& aItem2 ) const
178     {
179         return aItem1 < aItem2;
180     }
181 };
182 
183 /// Symbol map used by symbol library object.
184 
185 typedef std::map< wxString, LIB_SYMBOL*, LibSymbolMapSort > LIB_SYMBOL_MAP;
186 typedef boost::ptr_vector< SYMBOL_LIB >                     SYMBOL_LIBS_BASE;
187 
188 
189 /**
190  * A collection of #SYMBOL_LIB objects.
191  *
192  * It extends from PROJECT::_ELEM so it can be hung in the PROJECT.  It does not use any
193  * UI calls, but rather simply throws an IO_ERROR when there is a problem.
194  */
195 class SYMBOL_LIBS : public SYMBOL_LIBS_BASE, public PROJECT::_ELEM
196 {
197 public:
Type()198     KICAD_T Type() override { return SYMBOL_LIBS_T; }
199 
200     static int        s_modify_generation;         ///< helper for GetModifyHash()
201     static std::mutex s_generationMutex;
202 
SYMBOL_LIBS()203     SYMBOL_LIBS()
204     {
205         IncrementModifyGeneration();
206     }
207 
IncrementModifyGeneration()208     static void IncrementModifyGeneration()
209     {
210         std::lock_guard<std::mutex> mut( SYMBOL_LIBS::s_generationMutex );
211         ++SYMBOL_LIBS::s_modify_generation;
212     }
213 
GetModifyGeneration()214     static int GetModifyGeneration()
215     {
216         std::lock_guard<std::mutex> mut( SYMBOL_LIBS::s_generationMutex );
217         return SYMBOL_LIBS::s_modify_generation;
218     }
219 
220     /// Return the modification hash for all libraries.  The value returned
221     /// changes on every library modification.
222     int GetModifyHash();
223 
224     /**
225      * Allocate and adds a symbol library to the library list.
226      *
227      * @param aFileName is the file name object of symbol library.
228      * @throw IO_ERROR if there's any problem loading.
229      */
230     SYMBOL_LIB* AddLibrary( const wxString& aFileName );
231 
232     /**
233      * Insert a symbol library into the library list.
234      *
235      * @param aFileName is the file name object of symbol library.
236      * @param aIterator is an iterator to insert library in front of.
237      * @return the new SYMBOL_LIB, which remains owned by this SYMBOL_LIBS container.
238      * @throw IO_ERROR if there's any problem loading.
239      */
240     SYMBOL_LIB* AddLibrary( const wxString& aFileName, SYMBOL_LIBS::iterator& aIterator );
241 
242     /**
243      * Load all of the project's libraries into this container, which should
244      * be cleared before calling it.
245      *
246      * @note This method is only to be used when loading legacy projects.  All further symbol
247      *       library access should be done via the symbol library table.
248      */
249     void LoadAllLibraries( PROJECT* aProject, bool aShowProgress=true );
250 
251     /**
252      * Save or load the names of the currently configured symbol libraries (without paths).
253      */
254     static void LibNamesAndPaths( PROJECT* aProject, bool doSave,
255                                   wxString* aPaths, wxArrayString* aNames = nullptr );
256 
257     /**
258      * Return the name of the cache library after potentially fixing it from
259      * an older naming scheme.  That is, the old file is renamed if needed.
260      *
261      * @param aFullProjectFilename is the *.pro filename with absolute path.
262      */
263     static const wxString CacheName( const wxString& aFullProjectFilename );
264 
265     /**
266      * Find a symbol library by \a aName.
267      *
268      * @param aName is the library file name without path or extension to find.
269      * @return the symbol library if found, otherwise NULL.
270      */
271     SYMBOL_LIB* FindLibrary( const wxString& aName );
272 
273     SYMBOL_LIB* FindLibraryByFullFileName( const wxString& aFullFileName );
274 
275     SYMBOL_LIB* GetCacheLibrary();
276 
277     /**
278      * Return the list of symbol library file names without path and extension.
279      *
280      * @param aSorted sort the list of name if true.  Otherwise use the library load order.
281      * @return the list of library names.
282      */
283     wxArrayString GetLibraryNames( bool aSorted = true );
284 
285     /**
286      * Search all libraries in the list for a symbol.
287      *
288      * A symbol object will always be returned.  If the entry found
289      * is an alias.  The root symbol will be found and returned.
290      *
291      * @param aLibId is the #LIB_ID of the symbol to search for.
292      * @param aLibraryName is the name of the library to search for symbol.
293      * @return the symbol object if found, otherwise NULL.
294      */
295     LIB_SYMBOL* FindLibSymbol( const LIB_ID& aLibId, const wxString& aLibraryName = wxEmptyString );
296 
297     /**
298      * Search all libraries in the list for a #LIB_SYMBOL using a case insensitive comparison.
299      *
300      * Helper function used in dialog to find all candidates.
301      * During a long time, eeschema was using a case insensitive search.
302      * Therefore, for old schematics (<= 2013), or libs, for some symbols,
303      * the chip name (name of alias in lib) can be broken.
304      * This function can be used to display a list of candidates, in symbol properties dialog.
305      *
306      * @param aEntryName is the name of entries to search for (case insensitive).
307      * @param aLibraryName is the name of the library to search.
308      * @param aCandidates is a std::vector to store candidates.
309      */
310     void FindLibraryNearEntries( std::vector<LIB_SYMBOL*>& aCandidates, const wxString& aEntryName,
311                                  const wxString& aLibraryName = wxEmptyString );
312 
GetLibraryCount()313     int GetLibraryCount() { return size(); }
314 };
315 
316 
317 /**
318  * Object used to load, save, search, and otherwise manipulate symbol library files.
319  *
320  * @warning This code is obsolete with the exception of the cache library.  All other
321  *          symbol library I/O is managed by the #SCH_IO_MGR object.
322  */
323 class SYMBOL_LIB
324 {
325 public:
326     SYMBOL_LIB( SCH_LIB_TYPE aType, const wxString& aFileName,
327               SCH_IO_MGR::SCH_FILE_T aPluginType = SCH_IO_MGR::SCH_LEGACY );
328     ~SYMBOL_LIB();
329 
330     /**
331      * @return a magic number that changes if the library has changed
332      */
GetModHash()333     int GetModHash() const { return m_mod_hash; }
334 
GetPluginType()335     SCH_IO_MGR::SCH_FILE_T GetPluginType() const { return m_pluginType; }
336 
337     void SetPluginType( SCH_IO_MGR::SCH_FILE_T aPluginType );
338 
339     void Create( const wxString& aFileName = wxEmptyString );
340 
SetFileName(const wxString & aFileName)341     void SetFileName( const wxString& aFileName ) { fileName = aFileName; }
342 
IsModified()343     bool IsModified() const
344     {
345         return isModified;
346     }
347 
348     bool IsCache() const;
349 
350     void SetCache();
351 
352     bool IsBuffering() const;
353 
354     void EnableBuffering( bool aEnable = true );
355 
356     void Save( bool aSaveDocFile = true );
357 
358     /**
359      * @return true if current user does not have write access to the library file.
360      */
IsReadOnly()361     bool IsReadOnly() const { return !fileName.IsFileWritable(); }
362 
363     /**
364      * Load a string array with the names of all the entries in this library.
365      *
366      * @param aNames is the array to place entry names into.
367      */
368     void GetSymbolNames( wxArrayString& aNames ) const;
369 
370     /**
371      * Load a vector with all the entries in this library.
372      *
373      * @param aSymbols is a vector to receive the aliases.
374      */
375     void GetSymbols( std::vector<LIB_SYMBOL*>& aSymbols ) const;
376 
377     /**
378      * Find #LIB_SYMBOL by \a aName.
379      *
380      * @param aName is the name of the symbol, case sensitive.
381      * @return LIB_SYMBOL pointer symbol if found, else NULL.
382      */
383     LIB_SYMBOL* FindSymbol( const wxString& aName ) const;
384 
385     LIB_SYMBOL* FindSymbol( const LIB_ID& aLibId ) const;
386 
387     /**
388      * Add \a aSymbol entry to library.
389      *
390      * @note A #LIB_SYMBOL can have an alias list so these alias will be added in library.
391      *       and the any existing duplicate aliases will be removed from the library.
392      *
393      * @param aSymbol is the symbol to add, caller retains ownership, a clone is added.
394      */
395     void AddSymbol( LIB_SYMBOL* aSymbol );
396 
397     /**
398      * Safely remove \a aEntry from the library and return the next entry.
399      *
400      * The next entry returned depends on the entry being removed.  If the entry being
401      * remove also removes the symbol, then the next entry from the list is returned.
402      * If the entry being used only removes an alias from a symbol, then the next alias
403      * of the symbol is returned.
404      *
405      * @param aEntry is the entry to remove from library.
406      * @return The next entry in the library or NULL if the library is empty.
407      */
408     LIB_SYMBOL* RemoveSymbol( LIB_SYMBOL* aEntry );
409 
410     /**
411      * Replace an existing symbol entry in the library.
412      *
413      * @note A symbol can have an alias list so these aliases will be added in library and
414      *       previously existing alias removed.
415      *
416      * @param aOldSymbol is the symbol to replace.
417      * @param aNewSymbol is the new symbol.
418      */
419     LIB_SYMBOL* ReplaceSymbol( LIB_SYMBOL* aOldSymbol, LIB_SYMBOL* aNewSymbol );
420 
421     /**
422      * Return the file name without path or extension.
423      *
424      * @return the name of library file.
425      */
GetName()426     const wxString GetName() const            { return fileName.GetName(); }
427 
428     /**
429      * Return the full file library name with path and extension.
430      *
431      * @return the full library file name with path and extension.
432      */
GetFullFileName()433     wxString GetFullFileName() const          { return fileName.GetFullPath(); }
434 
435     /**
436      * Return the logical name of the library.
437      *
438      * @return The logical name of this library.
439      */
GetLogicalName()440     const wxString GetLogicalName() const
441     {
442         /*  for now is the filename without path or extension.
443 
444             Technically the library should not know its logical name!
445             This will eventually come out of a pair of lookup tables using a
446             reverse lookup using the full name or library pointer as a key.
447             Search will be by project lookup table and then user lookup table if
448             not found.
449         */
450         return fileName.GetName();
451     }
452 
453 
454     /**
455      * Allocate and load a symbol library file.
456      *
457      * @param aFileName is the file name of the symbol library to load.
458      * @return SYMBOL_LIB* is the allocated and loaded SYMBOL_LIB, which is owned by the caller.
459      * @throw IO_ERROR if there's any problem loading the library.
460      */
461     static SYMBOL_LIB* LoadLibrary( const wxString& aFileName );
462 
463 private:
464     SCH_LIB_TYPE    type;           ///< Library type indicator.
465     wxFileName      fileName;       ///< Library file name.
466     wxDateTime      timeStamp;      ///< Library save time and date.
467     int             versionMajor;   ///< Library major version number.
468     int             versionMinor;   ///< Library minor version number.
469     wxString        header;         ///< first line of loaded library.
470     bool            isModified;     ///< Library modification status.
471     int             m_mod_hash;     ///< incremented each time library is changed.
472 
473     SCH_IO_MGR::SCH_FILE_T        m_pluginType;
474     std::unique_ptr< SCH_PLUGIN > m_plugin;
475     std::unique_ptr< PROPERTIES > m_properties;   ///< Library properties
476 };
477 
478 
479 /**
480  * Case insensitive library name comparison.
481  */
482 bool operator==( const SYMBOL_LIB& aLibrary, const wxString& aName );
483 bool operator!=( const SYMBOL_LIB& aLibrary, const wxString& aName );
484 
485 #endif  //  SYMBOL_LIBRARY_H
486