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 Wayne Stambaugh <stambaughw@gmail.com>
5  * Copyright (C) 2016-2021 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 <lib_id.h>
27 #include <lib_table_lexer.h>
28 #include <pgm_base.h>
29 #include <search_stack.h>
31 #include <systemdirsappend.h>
32 #include <symbol_lib_table.h>
33 #include <lib_symbol.h>
34 
35 #define OPT_SEP '|'
36 
37 using namespace LIB_TABLE_T;
38 
39 
40 static const wxString global_tbl_name( "sym-lib-table" );
41 
42 
43 const char* SYMBOL_LIB_TABLE::PropPowerSymsOnly = "pwr_sym_only";
44 const char* SYMBOL_LIB_TABLE::PropNonPowerSymsOnly = "non_pwr_sym_only";
45 int SYMBOL_LIB_TABLE::m_modifyHash = 1; // starts at 1 and goes up
46 
47 
52 
53 
55 {
56  return LIB_TABLE_ROW::operator == ( aRow ) && type == aRow.type;
57 }
58 
59 
60 void SYMBOL_LIB_TABLE_ROW::SetType( const wxString& aType )
61 {
62  type = SCH_IO_MGR::EnumFromStr( aType );
63 
64  if( SCH_IO_MGR::SCH_FILE_T( -1 ) == type )
65  type = SCH_IO_MGR::SCH_LEGACY;
66 
67  plugin.release();
68 }
69 
70 
72 {
73  if( !plugin )
74  {
75  wxArrayString dummyList;
76 
77  plugin.set( SCH_IO_MGR::FindPlugin( type ) );
78  SetLoaded( false );
79  plugin->EnumerateSymbolLib( dummyList, GetFullURI( true ), GetProperties() );
80  SetLoaded( true );
81  return true;
82  }
83 
84  return false;
85 }
86 
87 
89  LIB_TABLE( aFallBackTable )
90 {
91  // not copying fall back, simply search aFallBackTable separately
92  // if "nickName not found".
93 }
94 
95 
97 {
98  return g_symbolLibraryTable;
99 }
100 
101 
102 void SYMBOL_LIB_TABLE::Parse( LIB_TABLE_LEXER* in )
103 {
104  T tok;
105  wxString errMsg; // to collect error messages
106 
107  // This table may be nested within a larger s-expression, or not.
108  // Allow for parser of that optional containing s-epression to have looked ahead.
109  if( in->CurTok() != T_sym_lib_table )
110  {
111  in->NeedLEFT();
112  if( ( tok = in->NextTok() ) != T_sym_lib_table )
113  in->Expecting( T_sym_lib_table );
114  }
115 
116  while( ( tok = in->NextTok() ) != T_RIGHT )
117  {
118  std::unique_ptr< SYMBOL_LIB_TABLE_ROW > row = std::make_unique<SYMBOL_LIB_TABLE_ROW>();
119 
120  if( tok == T_EOF )
121  in->Expecting( T_RIGHT );
122 
123  if( tok != T_LEFT )
124  in->Expecting( T_LEFT );
125 
126  // in case there is a "row integrity" error, tell where later.
127  int lineNum = in->CurLineNumber();
128 
129  if( ( tok = in->NextTok() ) != T_lib )
130  in->Expecting( T_lib );
131 
132  // (name NICKNAME)
133  in->NeedLEFT();
134 
135  if( ( tok = in->NextTok() ) != T_name )
136  in->Expecting( T_name );
137 
138  in->NeedSYMBOLorNUMBER();
139 
140  row->SetNickName( in->FromUTF8() );
141 
142  in->NeedRIGHT();
143 
144  // After (name), remaining (lib) elements are order independent, and in
145  // some cases optional.
146  bool sawType = false;
147  bool sawOpts = false;
148  bool sawDesc = false;
149  bool sawUri = false;
150  bool sawDisabled = false;
151 
152  while( ( tok = in->NextTok() ) != T_RIGHT )
153  {
154  if( tok == T_EOF )
155  in->Unexpected( T_EOF );
156 
157  if( tok != T_LEFT )
158  in->Expecting( T_LEFT );
159 
160  tok = in->NeedSYMBOLorNUMBER();
161 
162  switch( tok )
163  {
164  case T_uri:
165  if( sawUri )
166  in->Duplicate( tok );
167  sawUri = true;
168  in->NeedSYMBOLorNUMBER();
169  row->SetFullURI( in->FromUTF8() );
170  break;
171 
172  case T_type:
173  if( sawType )
174  in->Duplicate( tok );
175  sawType = true;
176  in->NeedSYMBOLorNUMBER();
177  row->SetType( in->FromUTF8() );
178  break;
179 
180  case T_options:
181  if( sawOpts )
182  in->Duplicate( tok );
183  sawOpts = true;
184  in->NeedSYMBOLorNUMBER();
185  row->SetOptions( in->FromUTF8() );
186  break;
187 
188  case T_descr:
189  if( sawDesc )
190  in->Duplicate( tok );
191  sawDesc = true;
192  in->NeedSYMBOLorNUMBER();
193  row->SetDescr( in->FromUTF8() );
194  break;
195 
196  case T_disabled:
197  if( sawDisabled )
198  in->Duplicate( tok );
199  sawDisabled = true;
200  row->SetEnabled( false );
201  break;
202 
203  default:
204  in->Unexpected( tok );
205  }
206 
207  in->NeedRIGHT();
208  }
209 
210  if( !sawType )
211  in->Expecting( T_type );
212 
213  if( !sawUri )
214  in->Expecting( T_uri );
215 
216  // all nickNames within this table fragment must be unique, so we do not
217  // use doReplace in InsertRow(). (However a fallBack table can have a
218  // conflicting nickName and ours will supercede that one since in
219  // FindLib() we search this table before any fall back.)
220  wxString nickname = row->GetNickName(); // store it to be able to used it
221  // after row deletion if an error occurs
222  LIB_TABLE_ROW* tmp = row.release();
223 
224  if( !InsertRow( tmp ) )
225  {
226  delete tmp; // The table did not take ownership of the row.
227 
228  wxString msg = wxString::Format( _( "Duplicate library nickname '%s' found in symbol "
229  "library table file line %d" ),
230  nickname,
231  lineNum );
232 
233  if( !errMsg.IsEmpty() )
234  errMsg << '\n';
235 
236  errMsg << msg;
237  }
238  }
239 
240  if( !errMsg.IsEmpty() )
241  THROW_IO_ERROR( errMsg );
242 }
243 
244 
245 void SYMBOL_LIB_TABLE::Format( OUTPUTFORMATTER* aOutput, int aIndentLevel ) const
246 {
247  aOutput->Print( aIndentLevel, "(sym_lib_table\n" );
248 
249  for( LIB_TABLE_ROWS_CITER it = rows.begin(); it != rows.end(); ++it )
250  {
251  it->Format( aOutput, aIndentLevel+1 );
252  }
253 
254  aOutput->Print( aIndentLevel, ")\n" );
255 }
256 
257 
259 {
260  int hash = 0;
261  std::vector< wxString > libNames = GetLogicalLibs();
262 
263  for( const auto& libName : libNames )
264  {
265  const SYMBOL_LIB_TABLE_ROW* row = FindRow( libName, true );
266 
267  if( !row || !row->plugin )
268  {
269  wxFAIL;
270  continue;
271  }
272 
273  hash += row->plugin->GetModifyHash();
274  }
275 
276  hash += m_modifyHash;
277 
278  return hash;
279 }
280 
281 
282 void SYMBOL_LIB_TABLE::EnumerateSymbolLib( const wxString& aNickname, wxArrayString& aAliasNames,
283  bool aPowerSymbolsOnly )
284 {
285  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname, true );
286  wxCHECK( row && row->plugin, /* void */ );
287 
288  wxString options = row->GetOptions();
289 
290  if( aPowerSymbolsOnly )
291  row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
292 
293  row->SetLoaded( false );
294  row->plugin->EnumerateSymbolLib( aAliasNames, row->GetFullURI( true ), row->GetProperties() );
295  row->SetLoaded( true );
296 
297  if( aPowerSymbolsOnly )
298  row->SetOptions( options );
299 }
300 
301 
302 SYMBOL_LIB_TABLE_ROW* SYMBOL_LIB_TABLE::FindRow( const wxString& aNickname, bool aCheckIfEnabled )
303 {
304  SYMBOL_LIB_TABLE_ROW* row =
305  dynamic_cast< SYMBOL_LIB_TABLE_ROW* >( findRow( aNickname, aCheckIfEnabled ) );
306 
307  if( !row )
308  return nullptr;
309 
310  // We've been 'lazy' up until now, but it cannot be deferred any longer,
311  // instantiate a PLUGIN of the proper kind if it is not already in this
312  // SYMBOL_LIB_TABLE_ROW.
313  if( !row->plugin )
314  row->setPlugin( SCH_IO_MGR::FindPlugin( row->type ) );
315 
316  return row;
317 }
318 
319 
320 void SYMBOL_LIB_TABLE::LoadSymbolLib( std::vector<LIB_PART*>& aSymbolList,
321  const wxString& aNickname, bool aPowerSymbolsOnly )
322 {
323  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname, true );
324  wxCHECK( row && row->plugin, /* void */ );
325 
326  wxString options = row->GetOptions();
327 
328  if( aPowerSymbolsOnly )
329  row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
330 
331  row->SetLoaded( false );
332  row->plugin->EnumerateSymbolLib( aSymbolList, row->GetFullURI( true ), row->GetProperties() );
333  row->SetLoaded( true );
334 
335  if( aPowerSymbolsOnly )
336  row->SetOptions( options );
337 
338  // The library cannot know its own name, because it might have been renamed or moved.
339  // Therefore footprints cannot know their own library nickname when residing in
340  // a symbol library.
341  // Only at this API layer can we tell the symbol about its actual library nickname.
342  for( LIB_PART* part : aSymbolList )
343  {
344  LIB_ID id = part->GetLibId();
345 
346  id.SetLibNickname( row->GetNickName() );
347  part->SetLibId( id );
348  }
349 }
350 
351 
352 LIB_PART* SYMBOL_LIB_TABLE::LoadSymbol( const wxString& aNickname, const wxString& aSymbolName )
353 {
354  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname, true );
355 
356  if( !row || !row->plugin )
357  return nullptr;
358 
359  LIB_PART* part = row->plugin->LoadSymbol( row->GetFullURI( true ), aSymbolName,
360  row->GetProperties() );
361 
362  if( part == nullptr )
363  return part;
364 
365  // The library cannot know its own name, because it might have been renamed or moved.
366  // Therefore footprints cannot know their own library nickname when residing in
367  // a symbol library.
368  // Only at this API layer can we tell the symbol about its actual library nickname.
369  if( part )
370  {
371  LIB_ID id = part->GetLibId();
372 
373  id.SetLibNickname( row->GetNickName() );
374  part->SetLibId( id );
375  }
376 
377  return part;
378 }
379 
380 
382  const LIB_PART* aSymbol, bool aOverwrite )
383 {
384  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname, true );
385  wxCHECK( row && row->plugin, SAVE_SKIPPED );
386 
387  if( !row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) ) )
388  return SAVE_SKIPPED;
389 
390  if( !aOverwrite )
391  {
392  // Try loading the footprint to see if it already exists, caller wants overwrite
393  // protection, which is atypical, not the default.
394 
395  wxString name = aSymbol->GetLibId().GetLibItemName();
396 
397  std::unique_ptr< LIB_PART > symbol( row->plugin->LoadSymbol( row->GetFullURI( true ),
398  name,
399  row->GetProperties() ) );
400 
401  if( symbol.get() )
402  return SAVE_SKIPPED;
403  }
404 
405  try
406  {
407  row->plugin->SaveSymbol( row->GetFullURI( true ), aSymbol, row->GetProperties() );
408  }
409  catch( const IO_ERROR& )
410  {
411  return SAVE_SKIPPED;
412  }
413 
414  return SAVE_OK;
415 }
416 
417 
418 void SYMBOL_LIB_TABLE::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
419 {
420  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname, true );
421  wxCHECK( row && row->plugin, /* void */ );
422  return row->plugin->DeleteSymbol( row->GetFullURI( true ), aSymbolName,
423  row->GetProperties() );
424 }
425 
426 
427 bool SYMBOL_LIB_TABLE::IsSymbolLibWritable( const wxString& aNickname )
428 {
429  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname, true );
430  wxCHECK( row && row->plugin, false );
431  return row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) );
432 }
433 
434 bool SYMBOL_LIB_TABLE::IsSymbolLibLoaded( const wxString& aNickname )
435 {
436  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname, true );
437  wxCHECK( row, false );
438  return row->GetIsLoaded();
439 }
440 
441 
442 void SYMBOL_LIB_TABLE::DeleteSymbolLib( const wxString& aNickname )
443 {
444  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname, true );
445  wxCHECK( row && row->plugin, /* void */ );
446  row->plugin->DeleteSymbolLib( row->GetFullURI( true ), row->GetProperties() );
447 }
448 
449 
450 void SYMBOL_LIB_TABLE::CreateSymbolLib( const wxString& aNickname )
451 {
452  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname, true );
453  wxCHECK( row && row->plugin, /* void */ );
454  row->plugin->CreateSymbolLib( row->GetFullURI( true ), row->GetProperties() );
455 }
456 
457 
459 {
460  wxString nickname = aLibId.GetLibNickname();
461  wxString name = aLibId.GetLibItemName();
462 
463  if( nickname.size() )
464  {
465  return LoadSymbol( nickname, name );
466  }
467 
468  // nickname is empty, sequentially search (alphabetically) all libs/nicks for first match:
469  else
470  {
471  std::vector<wxString> nicks = GetLogicalLibs();
472 
473  // Search each library going through libraries alphabetically.
474  for( unsigned i = 0; i < nicks.size(); ++i )
475  {
476  // FootprintLoad() returns NULL on not found, does not throw exception
477  // unless there's an IO_ERROR.
478  LIB_PART* ret = LoadSymbol( nicks[i], name );
479 
480  if( ret )
481  return ret;
482  }
483 
484  return nullptr;
485  }
486 }
487 
488 
490 {
491  return "KICAD6_SYMBOL_DIR";
492 }
493 
494 
496 {
497  bool tableExists = true;
498  wxFileName fn = GetGlobalTableFileName();
499 
500  if( !fn.FileExists() )
501  {
502  tableExists = false;
503 
504  if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
505  {
507  _( "Cannot create global library table path \"%s\"." ), fn.GetPath() ) );
508  }
509 
510  // Attempt to copy the default global file table from the KiCad
511  // template folder to the user's home configuration path.
512  SEARCH_STACK ss;
513 
514  SystemDirsAppend( &ss );
515 
516  wxString templatePath =
517  Pgm().GetLocalEnvVariables().at( wxT( "KICAD6_TEMPLATE_DIR" ) ).GetValue();
518 
519  if( !templatePath.IsEmpty() )
520  ss.AddPaths( templatePath, 0 );
521 
522  wxString fileName = ss.FindValidPath( global_tbl_name );
523 
524  // The fallback is to create an empty global symbol table for the user to populate.
525  if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) )
526  {
527  SYMBOL_LIB_TABLE emptyTable;
528 
529  emptyTable.Save( fn.GetFullPath() );
530  }
531  }
532 
533  aTable.Load( fn.GetFullPath() );
534 
535  return tableExists;
536 }
537 
538 
540 {
541  wxFileName fn;
542 
544  fn.SetName( global_tbl_name );
545 
546  return fn.GetFullPath();
547 }
548 
549 
551 {
552  return global_tbl_name;
553 }
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.
wxString FindValidPath(const wxString &aFileName) const
Definition: search_stack.h:70
const UTF8 & GetLibItemName() const
Definition: lib_id.h:106
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...
LIB_ID GetLibId() const override
Definition: lib_symbol.h:131
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.
An interface used to output 8 bit text in a convenient way.
Definition: richio.h:306
Look for files in a number of paths.
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.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
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.
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.
Definition: lib_symbol.h:93
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:92
void SystemDirsAppend(SEARCH_STACK *aSearchStack)
Append system places to aSearchStack in a platform specific way and pertinent to KiCad programs.
LIB_TABLE_ROW * findRow(const wxString &aNickname, bool aCheckIfEnabled=false) const
Return a LIB_TABLE_ROW if aNickname is found in this table or in any chained fallBack table fragment,...
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
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
see class PGM_BASE
LIB_TABLE_ROWS::const_iterator LIB_TABLE_ROWS_CITER
const char * name
Definition: DXF_plotter.cpp:59
void DeleteSymbol(const wxString &aNickname, const wxString &aSymbolName)
Deletes the aSymbolName from the library given by aNickname.
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:116
#define _(s)
Definition: 3d_actions.cpp:33
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.
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.
SYMBOL_LIB_TABLE_ROW * FindRow(const wxString &aNickName, bool aCheckIfEnabled=false)
Return an SYMBOL_LIB_TABLE_ROW if aNickName is found in this table or in any chained fallBack table f...
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition: richio.cpp:408
void SetLibId(const LIB_ID &aLibId)
Definition: lib_symbol.h:132
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
#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)
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.