KiCad PCB EDA Suite
symbol_lib_table.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) 2016-2019 Wayne Stambaugh <stambaughw@gmail.com>
5  * Copyright (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 
26 #include <fctsys.h>
27 #include <common.h>
28 #include <macros.h>
29 #include <lib_id.h>
30 #include <lib_table_lexer.h>
31 #include <pgm_base.h>
32 #include <search_stack.h>
34 #include <systemdirsappend.h>
35 #include <symbol_lib_table.h>
36 #include <class_libentry.h>
37 
38 #define OPT_SEP '|'
39 
40 using namespace LIB_TABLE_T;
41 
42 
43 static const wxString global_tbl_name( "sym-lib-table" );
44 
45 
46 const char* SYMBOL_LIB_TABLE::PropPowerSymsOnly = "pwr_sym_only";
47 const char* SYMBOL_LIB_TABLE::PropNonPowerSymsOnly = "non_pwr_sym_only";
48 int SYMBOL_LIB_TABLE::m_modifyHash = 1; // starts at 1 and goes up
49 
50 
55 
56 
58 {
59  return LIB_TABLE_ROW::operator == ( aRow ) && type == aRow.type;
60 }
61 
62 
63 void SYMBOL_LIB_TABLE_ROW::SetType( const wxString& aType )
64 {
65  type = SCH_IO_MGR::EnumFromStr( aType );
66 
67  if( SCH_IO_MGR::SCH_FILE_T( -1 ) == type )
68  type = SCH_IO_MGR::SCH_LEGACY;
69 
70  plugin.release();
71 }
72 
73 
75 {
76  if( !plugin )
77  {
78  wxArrayString dummyList;
79 
80  plugin.set( SCH_IO_MGR::FindPlugin( type ) );
81  SetLoaded( false );
82  plugin->EnumerateSymbolLib( dummyList, GetFullURI( true ), GetProperties() );
83  SetLoaded( true );
84  return true;
85  }
86 
87  return false;
88 }
89 
90 
92  LIB_TABLE( aFallBackTable )
93 {
94  // not copying fall back, simply search aFallBackTable separately
95  // if "nickName not found".
96 }
97 
98 
100 {
101  return g_symbolLibraryTable;
102 }
103 
104 
105 void SYMBOL_LIB_TABLE::Parse( LIB_TABLE_LEXER* in )
106 {
107  T tok;
108  wxString errMsg; // to collect error messages
109 
110  // This table may be nested within a larger s-expression, or not.
111  // Allow for parser of that optional containing s-epression to have looked ahead.
112  if( in->CurTok() != T_sym_lib_table )
113  {
114  in->NeedLEFT();
115  if( ( tok = in->NextTok() ) != T_sym_lib_table )
116  in->Expecting( T_sym_lib_table );
117  }
118 
119  while( ( tok = in->NextTok() ) != T_RIGHT )
120  {
121  std::unique_ptr< SYMBOL_LIB_TABLE_ROW > row( new SYMBOL_LIB_TABLE_ROW );
122 
123  if( tok == T_EOF )
124  in->Expecting( T_RIGHT );
125 
126  if( tok != T_LEFT )
127  in->Expecting( T_LEFT );
128 
129  // in case there is a "row integrity" error, tell where later.
130  int lineNum = in->CurLineNumber();
131 
132  if( ( tok = in->NextTok() ) != T_lib )
133  in->Expecting( T_lib );
134 
135  // (name NICKNAME)
136  in->NeedLEFT();
137 
138  if( ( tok = in->NextTok() ) != T_name )
139  in->Expecting( T_name );
140 
141  in->NeedSYMBOLorNUMBER();
142 
143  row->SetNickName( in->FromUTF8() );
144 
145  in->NeedRIGHT();
146 
147  // After (name), remaining (lib) elements are order independent, and in
148  // some cases optional.
149  bool sawType = false;
150  bool sawOpts = false;
151  bool sawDesc = false;
152  bool sawUri = false;
153  bool sawDisabled = false;
154 
155  while( ( tok = in->NextTok() ) != T_RIGHT )
156  {
157  if( tok == T_EOF )
158  in->Unexpected( T_EOF );
159 
160  if( tok != T_LEFT )
161  in->Expecting( T_LEFT );
162 
163  tok = in->NeedSYMBOLorNUMBER();
164 
165  switch( tok )
166  {
167  case T_uri:
168  if( sawUri )
169  in->Duplicate( tok );
170  sawUri = true;
171  in->NeedSYMBOLorNUMBER();
172  row->SetFullURI( in->FromUTF8() );
173  break;
174 
175  case T_type:
176  if( sawType )
177  in->Duplicate( tok );
178  sawType = true;
179  in->NeedSYMBOLorNUMBER();
180  row->SetType( in->FromUTF8() );
181  break;
182 
183  case T_options:
184  if( sawOpts )
185  in->Duplicate( tok );
186  sawOpts = true;
187  in->NeedSYMBOLorNUMBER();
188  row->SetOptions( in->FromUTF8() );
189  break;
190 
191  case T_descr:
192  if( sawDesc )
193  in->Duplicate( tok );
194  sawDesc = true;
195  in->NeedSYMBOLorNUMBER();
196  row->SetDescr( in->FromUTF8() );
197  break;
198 
199  case T_disabled:
200  if( sawDisabled )
201  in->Duplicate( tok );
202  sawDisabled = true;
203  row->SetEnabled( false );
204  break;
205 
206  default:
207  in->Unexpected( tok );
208  }
209 
210  in->NeedRIGHT();
211  }
212 
213  if( !sawType )
214  in->Expecting( T_type );
215 
216  if( !sawUri )
217  in->Expecting( T_uri );
218 
219  // all nickNames within this table fragment must be unique, so we do not
220  // use doReplace in InsertRow(). (However a fallBack table can have a
221  // conflicting nickName and ours will supercede that one since in
222  // FindLib() we search this table before any fall back.)
223  wxString nickname = row->GetNickName(); // store it to be able to used it
224  // after row deletion if an error occurs
225  LIB_TABLE_ROW* tmp = row.release();
226 
227  if( !InsertRow( tmp ) )
228  {
229  delete tmp; // The table did not take ownership of the row.
230 
231  wxString msg = wxString::Format(
232  _( "Duplicate library nickname \"%s\" found in symbol library "
233  "table file line %d" ), GetChars( nickname ), lineNum );
234 
235  if( !errMsg.IsEmpty() )
236  errMsg << '\n';
237 
238  errMsg << msg;
239  }
240  }
241 
242  if( !errMsg.IsEmpty() )
243  THROW_IO_ERROR( errMsg );
244 }
245 
246 
247 void SYMBOL_LIB_TABLE::Format( OUTPUTFORMATTER* aOutput, int aIndentLevel ) const
248 {
249  aOutput->Print( aIndentLevel, "(sym_lib_table\n" );
250 
251  for( LIB_TABLE_ROWS_CITER it = rows.begin(); it != rows.end(); ++it )
252  {
253  it->Format( aOutput, aIndentLevel+1 );
254  }
255 
256  aOutput->Print( aIndentLevel, ")\n" );
257 }
258 
259 
261 {
262  int hash = 0;
263  std::vector< wxString > libNames = GetLogicalLibs();
264 
265  for( const auto& libName : libNames )
266  {
267  const SYMBOL_LIB_TABLE_ROW* row = FindRow( libName );
268 
269  if( !row || !row->plugin )
270  {
271  wxFAIL;
272  continue;
273  }
274 
275  hash += row->plugin->GetModifyHash();
276  }
277 
278  hash += m_modifyHash;
279 
280  return hash;
281 }
282 
283 
284 void SYMBOL_LIB_TABLE::EnumerateSymbolLib( const wxString& aNickname, wxArrayString& aAliasNames,
285  bool aPowerSymbolsOnly )
286 {
287  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
288  wxCHECK( row && row->plugin, /* void */ );
289 
290  wxString options = row->GetOptions();
291 
292  if( aPowerSymbolsOnly )
293  row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
294 
295  row->SetLoaded( false );
296  row->plugin->EnumerateSymbolLib( aAliasNames, row->GetFullURI( true ), row->GetProperties() );
297  row->SetLoaded( true );
298 
299  if( aPowerSymbolsOnly )
300  row->SetOptions( options );
301 }
302 
303 
304 SYMBOL_LIB_TABLE_ROW* SYMBOL_LIB_TABLE::FindRow( const wxString& aNickname )
305 
306 {
307  SYMBOL_LIB_TABLE_ROW* row = dynamic_cast< SYMBOL_LIB_TABLE_ROW* >( findRow( aNickname ) );
308 
309  if( !row )
310  return nullptr;
311 
312  // We've been 'lazy' up until now, but it cannot be deferred any longer,
313  // instantiate a PLUGIN of the proper kind if it is not already in this
314  // SYMBOL_LIB_TABLE_ROW.
315  if( !row->plugin )
316  row->setPlugin( SCH_IO_MGR::FindPlugin( row->type ) );
317 
318  return row;
319 }
320 
321 
322 void SYMBOL_LIB_TABLE::LoadSymbolLib( std::vector<LIB_PART*>& aSymbolList,
323  const wxString& aNickname, bool aPowerSymbolsOnly )
324 {
325  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
326  wxCHECK( row && row->plugin, /* void */ );
327 
328  wxString options = row->GetOptions();
329 
330  if( aPowerSymbolsOnly )
331  row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
332 
333  row->SetLoaded( false );
334  row->plugin->EnumerateSymbolLib( aSymbolList, row->GetFullURI( true ), row->GetProperties() );
335  row->SetLoaded( true );
336 
337  if( aPowerSymbolsOnly )
338  row->SetOptions( options );
339 
340  // The library cannot know its own name, because it might have been renamed or moved.
341  // Therefore footprints cannot know their own library nickname when residing in
342  // a symbol library.
343  // Only at this API layer can we tell the symbol about its actual library nickname.
344  for( LIB_PART* part : aSymbolList )
345  {
346  LIB_ID id = part->GetLibId();
347 
348  id.SetLibNickname( row->GetNickName() );
349  part->SetLibId( id );
350  }
351 }
352 
353 
354 LIB_PART* SYMBOL_LIB_TABLE::LoadSymbol( const wxString& aNickname, const wxString& aSymbolName )
355 {
356  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
357 
358  if( !row || !row->plugin )
359  return nullptr;
360 
361  LIB_PART* part = row->plugin->LoadSymbol( row->GetFullURI( true ), aSymbolName,
362  row->GetProperties() );
363 
364  if( part == nullptr )
365  return part;
366 
367  // The library cannot know its own name, because it might have been renamed or moved.
368  // Therefore footprints cannot know their own library nickname when residing in
369  // a symbol library.
370  // Only at this API layer can we tell the symbol about its actual library nickname.
371  if( part )
372  {
373  LIB_ID id = part->GetLibId();
374 
375  id.SetLibNickname( row->GetNickName() );
376  part->SetLibId( id );
377  }
378 
379  return part;
380 }
381 
382 
384  const LIB_PART* aSymbol, bool aOverwrite )
385 {
386  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
387  wxCHECK( row && row->plugin, SAVE_SKIPPED );
388 
389  if( !aOverwrite )
390  {
391  // Try loading the footprint to see if it already exists, caller wants overwrite
392  // protection, which is atypical, not the default.
393 
394  wxString name = aSymbol->GetLibId().GetLibItemName();
395 
396  std::unique_ptr< LIB_PART > symbol( row->plugin->LoadSymbol( row->GetFullURI( true ),
397  name,
398  row->GetProperties() ) );
399 
400  if( symbol.get() )
401  return SAVE_SKIPPED;
402  }
403 
404  row->plugin->SaveSymbol( row->GetFullURI( true ), aSymbol, row->GetProperties() );
405 
406  return SAVE_OK;
407 }
408 
409 
410 void SYMBOL_LIB_TABLE::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
411 {
412  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
413  wxCHECK( row && row->plugin, /* void */ );
414  return row->plugin->DeleteSymbol( row->GetFullURI( true ), aSymbolName,
415  row->GetProperties() );
416 }
417 
418 
419 bool SYMBOL_LIB_TABLE::IsSymbolLibWritable( const wxString& aNickname )
420 {
421  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
422  wxCHECK( row && row->plugin, false );
423  return row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) );
424 }
425 
426 bool SYMBOL_LIB_TABLE::IsSymbolLibLoaded( const wxString& aNickname )
427 {
428  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
429  wxCHECK( row, false );
430  return row->GetIsLoaded();
431 }
432 
433 
434 void SYMBOL_LIB_TABLE::DeleteSymbolLib( const wxString& aNickname )
435 {
436  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
437  wxCHECK( row && row->plugin, /* void */ );
438  row->plugin->DeleteSymbolLib( row->GetFullURI( true ), row->GetProperties() );
439 }
440 
441 
442 void SYMBOL_LIB_TABLE::CreateSymbolLib( const wxString& aNickname )
443 {
444  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
445  wxCHECK( row && row->plugin, /* void */ );
446  row->plugin->CreateSymbolLib( row->GetFullURI( true ), row->GetProperties() );
447 }
448 
449 
451 {
452  wxString nickname = aLibId.GetLibNickname();
453  wxString name = aLibId.GetLibItemName();
454 
455  if( nickname.size() )
456  {
457  return LoadSymbol( nickname, name );
458  }
459 
460  // nickname is empty, sequentially search (alphabetically) all libs/nicks for first match:
461  else
462  {
463  std::vector<wxString> nicks = GetLogicalLibs();
464 
465  // Search each library going through libraries alphabetically.
466  for( unsigned i = 0; i < nicks.size(); ++i )
467  {
468  // FootprintLoad() returns NULL on not found, does not throw exception
469  // unless there's an IO_ERROR.
470  LIB_PART* ret = LoadSymbol( nicks[i], name );
471 
472  if( ret )
473  return ret;
474  }
475 
476  return nullptr;
477  }
478 }
479 
480 
482 {
483  return "KICAD_SYMBOL_DIR";
484 }
485 
486 
488 {
489  bool tableExists = true;
490  wxFileName fn = GetGlobalTableFileName();
491 
492  if( !fn.FileExists() )
493  {
494  tableExists = false;
495 
496  if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
497  {
498  THROW_IO_ERROR( wxString::Format( _( "Cannot create global library table path \"%s\"." ),
499  GetChars( fn.GetPath() ) ) );
500  }
501 
502  // Attempt to copy the default global file table from the KiCad
503  // template folder to the user's home configuration path.
504  SEARCH_STACK ss;
505 
506  SystemDirsAppend( &ss );
507 
508  wxString templatePath =
509  Pgm().GetLocalEnvVariables().at( wxT( "KICAD_TEMPLATE_DIR" ) ).GetValue();
510 
511  if( !templatePath.IsEmpty() )
512  ss.AddPaths( templatePath, 0 );
513 
514  wxString fileName = ss.FindValidPath( global_tbl_name );
515 
516  // The fallback is to create an empty global symbol table for the user to populate.
517  if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) )
518  {
519  SYMBOL_LIB_TABLE emptyTable;
520 
521  emptyTable.Save( fn.GetFullPath() );
522  }
523  }
524 
525  aTable.Load( fn.GetFullPath() );
526 
527  return tableExists;
528 }
529 
530 
532 {
533  wxFileName fn;
534 
536  fn.SetName( global_tbl_name );
537 
538  return fn.GetFullPath();
539 }
540 
541 
543 {
544  return global_tbl_name;
545 }
SAVE_T SaveSymbol(const wxString &aNickname, const LIB_PART *aSymbol, bool aOverwrite=true)
Write aSymbol to an existing library given by aNickname.
static const wxString & GetSymbolLibTableFileName()
static SYMBOL_LIB_TABLE & GetGlobalLibTable()
void EnumerateSymbolLib(const wxString &aNickname, wxArrayString &aAliasNames, bool aPowerSymbolsOnly=false)
Return a list of symbol alias names contained within the library given by aNickname.
SYMBOL_LIB_TABLE_ROW * FindRow(const wxString &aNickName)
Return an SYMBOL_LIB_TABLE_ROW if aNickName is found in this table or in any chained fallBack table f...
wxString FindValidPath(const wxString &aFileName) const
Definition: search_stack.h:73
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
const wxString & GetOptions() const
Return the options string, which may hold a password or anything else needed to instantiate the under...
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
LIB_ID GetLibId() const override
Hold a record identifying a library accessed by the appropriate plug in object in the LIB_TABLE.
SYMBOL_LIB_TABLE(SYMBOL_LIB_TABLE *aFallBackTable=NULL)
Build a symbol library table by pre-pending this table fragment in front of aFallBackTable.
void CreateSymbolLib(const wxString &aNickname)
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
SCH_PLUGIN::SCH_PLUGIN_RELEASER plugin
void DeleteSymbolLib(const wxString &aNickname)
void SetType(const wxString &aType) override
Change the schematic plugin type represented by this row.
LIB_PART * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_PART having aName from the library given by aNickname.
static const wxString GlobalPathEnvVariableName()
Return the name of the environment variable used to hold the directory of locally installed "KiCad sp...
System directories search utilities.
OUTPUTFORMATTER is an important interface (abstract class) used to output 8 bit text in a convenient ...
Definition: richio.h:327
SEARCH_STACK looks for files in a number of places.
Definition: search_stack.h:41
LIB_TABLE_ROWS rows
static const wxString global_tbl_name("sym-lib-table")
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
bool IsSymbolLibWritable(const wxString &aNickname)
Return true if the library given by aNickname is writable.
bool operator==(const LIB_TABLE_ROW &r) const
bool GetIsLoaded() const
bool IsSymbolLibLoaded(const wxString &aNickname)
Return true if the library given by aNickname was successfully loaded.
This file contains miscellaneous commonly used macros and functions.
bool operator==(const SYMBOL_LIB_TABLE_ROW &aRow) const
const wxString GetFullURI(bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
void SetLoaded(bool aLoaded)
Mark the row as being a loaded library.
const wxString & GetNickName() const
static bool LoadGlobalTable(SYMBOL_LIB_TABLE &aTable)
Load the global symbol library table into aTable.
bool Refresh()
Attempt to reload the library.
void LoadSymbolLib(std::vector< LIB_PART * > &aAliasList, const wxString &aNickname, bool aPowerSymbolsOnly=false)
Define a library symbol object.
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:97
void SystemDirsAppend(SEARCH_STACK *aSearchStack)
Function SystemDirsAppend appends system places to aSearchStack in a platform specific way,...
virtual void Format(OUTPUTFORMATTER *aOutput, int aIndentLevel) const override
Generate the table in s-expression format to aOutput with an indention level of aIndentLevel.
void setPlugin(SCH_PLUGIN *aPlugin)
void Load(const wxString &aFileName)
Load the library table using the path defined by aFileName aFallBackTable.
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
int SetLibNickname(const UTF8 &aNickname)
Override the logical library name portion of the LIB_ID to aNickname.
Definition: lib_id.cpp:193
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:153
see class PGM_BASE
LIB_TABLE_ROWS::const_iterator LIB_TABLE_ROWS_CITER
const char * name
Definition: DXF_plotter.cpp:60
void DeleteSymbol(const wxString &aNickname, const wxString &aSymbolName)
Deletes the aSymbolName from the library given by aNickname.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the #SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy",...
Definition: sch_io_mgr.cpp:110
#define _(s)
Definition: 3d_actions.cpp:33
LIB_TABLE_ROW * findRow(const wxString &aNickname) const
Return a LIB_TABLE_ROW if aNickname is found in this table or in any chained fallBack table fragment,...
static int m_modifyHash
helper for GetModifyHash()
virtual void Parse(LIB_TABLE_LEXER *aLexer) override
Parse the #LIB_TABLE_LEXER s-expression library table format into the appropriate LIB_TABLE_ROW objec...
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
The common library.
void SetOptions(const wxString &aOptions)
Change the library options strings.
SAVE_T
The set of return values from SaveSymbol() below.
static const char * PropNonPowerSymsOnly
const PROPERTIES * GetProperties() const
Return the constant PROPERTIES for this library (LIB_TABLE_ROW).
LIB_PART * LoadSymbolWithOptionalNickname(const LIB_ID &aId)
Load a LIB_PART having aFootprintId with possibly an empty library nickname.
SYMBOL_LIB_TABLE g_symbolLibraryTable
The global symbol library table.
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:404
void SetLibId(const LIB_ID &aLibId)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
static wxString GetGlobalTableFileName()
Fetch the global symbol library table file name.
static const char * PropPowerSymsOnly
void AddPaths(const wxString &aPaths, int aIndex=-1)
Function AddPaths insert or append path(s)
std::vector< wxString > GetLogicalLibs()
Return the logical library names, all of them that are pertinent to a look up done on this LIB_TABLE.
Manage LIB_TABLE_ROW records (rows), and can be searched based on library nickname.