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 <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 <class_libentry.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(
229  _( "Duplicate library nickname \"%s\" found in symbol library "
230  "table file line %d" ), nickname, lineNum );
231 
232  if( !errMsg.IsEmpty() )
233  errMsg << '\n';
234 
235  errMsg << msg;
236  }
237  }
238 
239  if( !errMsg.IsEmpty() )
240  THROW_IO_ERROR( errMsg );
241 }
242 
243 
244 void SYMBOL_LIB_TABLE::Format( OUTPUTFORMATTER* aOutput, int aIndentLevel ) const
245 {
246  aOutput->Print( aIndentLevel, "(sym_lib_table\n" );
247 
248  for( LIB_TABLE_ROWS_CITER it = rows.begin(); it != rows.end(); ++it )
249  {
250  it->Format( aOutput, aIndentLevel+1 );
251  }
252 
253  aOutput->Print( aIndentLevel, ")\n" );
254 }
255 
256 
258 {
259  int hash = 0;
260  std::vector< wxString > libNames = GetLogicalLibs();
261 
262  for( const auto& libName : libNames )
263  {
264  const SYMBOL_LIB_TABLE_ROW* row = FindRow( libName );
265 
266  if( !row || !row->plugin )
267  {
268  wxFAIL;
269  continue;
270  }
271 
272  hash += row->plugin->GetModifyHash();
273  }
274 
275  hash += m_modifyHash;
276 
277  return hash;
278 }
279 
280 
281 void SYMBOL_LIB_TABLE::EnumerateSymbolLib( const wxString& aNickname, wxArrayString& aAliasNames,
282  bool aPowerSymbolsOnly )
283 {
284  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
285  wxCHECK( row && row->plugin, /* void */ );
286 
287  wxString options = row->GetOptions();
288 
289  if( aPowerSymbolsOnly )
290  row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
291 
292  row->SetLoaded( false );
293  row->plugin->EnumerateSymbolLib( aAliasNames, row->GetFullURI( true ), row->GetProperties() );
294  row->SetLoaded( true );
295 
296  if( aPowerSymbolsOnly )
297  row->SetOptions( options );
298 }
299 
300 
301 SYMBOL_LIB_TABLE_ROW* SYMBOL_LIB_TABLE::FindRow( const wxString& aNickname )
302 
303 {
304  SYMBOL_LIB_TABLE_ROW* row = dynamic_cast< SYMBOL_LIB_TABLE_ROW* >( findRow( aNickname ) );
305 
306  if( !row )
307  return nullptr;
308 
309  // We've been 'lazy' up until now, but it cannot be deferred any longer,
310  // instantiate a PLUGIN of the proper kind if it is not already in this
311  // SYMBOL_LIB_TABLE_ROW.
312  if( !row->plugin )
313  row->setPlugin( SCH_IO_MGR::FindPlugin( row->type ) );
314 
315  return row;
316 }
317 
318 
319 void SYMBOL_LIB_TABLE::LoadSymbolLib( std::vector<LIB_PART*>& aSymbolList,
320  const wxString& aNickname, bool aPowerSymbolsOnly )
321 {
322  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
323  wxCHECK( row && row->plugin, /* void */ );
324 
325  wxString options = row->GetOptions();
326 
327  if( aPowerSymbolsOnly )
328  row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
329 
330  row->SetLoaded( false );
331  row->plugin->EnumerateSymbolLib( aSymbolList, row->GetFullURI( true ), row->GetProperties() );
332  row->SetLoaded( true );
333 
334  if( aPowerSymbolsOnly )
335  row->SetOptions( options );
336 
337  // The library cannot know its own name, because it might have been renamed or moved.
338  // Therefore footprints cannot know their own library nickname when residing in
339  // a symbol library.
340  // Only at this API layer can we tell the symbol about its actual library nickname.
341  for( LIB_PART* part : aSymbolList )
342  {
343  LIB_ID id = part->GetLibId();
344 
345  id.SetLibNickname( row->GetNickName() );
346  part->SetLibId( id );
347  }
348 }
349 
350 
351 LIB_PART* SYMBOL_LIB_TABLE::LoadSymbol( const wxString& aNickname, const wxString& aSymbolName )
352 {
353  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
354 
355  if( !row || !row->plugin )
356  return nullptr;
357 
358  LIB_PART* part = row->plugin->LoadSymbol( row->GetFullURI( true ), aSymbolName,
359  row->GetProperties() );
360 
361  if( part == nullptr )
362  return part;
363 
364  // The library cannot know its own name, because it might have been renamed or moved.
365  // Therefore footprints cannot know their own library nickname when residing in
366  // a symbol library.
367  // Only at this API layer can we tell the symbol about its actual library nickname.
368  if( part )
369  {
370  LIB_ID id = part->GetLibId();
371 
372  id.SetLibNickname( row->GetNickName() );
373  part->SetLibId( id );
374  }
375 
376  return part;
377 }
378 
379 
381  const LIB_PART* aSymbol, bool aOverwrite )
382 {
383  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
384  wxCHECK( row && row->plugin, SAVE_SKIPPED );
385 
386  if( !aOverwrite )
387  {
388  // Try loading the footprint to see if it already exists, caller wants overwrite
389  // protection, which is atypical, not the default.
390 
391  wxString name = aSymbol->GetLibId().GetLibItemName();
392 
393  std::unique_ptr< LIB_PART > symbol( row->plugin->LoadSymbol( row->GetFullURI( true ),
394  name,
395  row->GetProperties() ) );
396 
397  if( symbol.get() )
398  return SAVE_SKIPPED;
399  }
400 
401  row->plugin->SaveSymbol( row->GetFullURI( true ), aSymbol, row->GetProperties() );
402 
403  return SAVE_OK;
404 }
405 
406 
407 void SYMBOL_LIB_TABLE::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
408 {
409  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
410  wxCHECK( row && row->plugin, /* void */ );
411  return row->plugin->DeleteSymbol( row->GetFullURI( true ), aSymbolName,
412  row->GetProperties() );
413 }
414 
415 
416 bool SYMBOL_LIB_TABLE::IsSymbolLibWritable( const wxString& aNickname )
417 {
418  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
419  wxCHECK( row && row->plugin, false );
420  return row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) );
421 }
422 
423 bool SYMBOL_LIB_TABLE::IsSymbolLibLoaded( const wxString& aNickname )
424 {
425  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
426  wxCHECK( row, false );
427  return row->GetIsLoaded();
428 }
429 
430 
431 void SYMBOL_LIB_TABLE::DeleteSymbolLib( const wxString& aNickname )
432 {
433  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
434  wxCHECK( row && row->plugin, /* void */ );
435  row->plugin->DeleteSymbolLib( row->GetFullURI( true ), row->GetProperties() );
436 }
437 
438 
439 void SYMBOL_LIB_TABLE::CreateSymbolLib( const wxString& aNickname )
440 {
441  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
442  wxCHECK( row && row->plugin, /* void */ );
443  row->plugin->CreateSymbolLib( row->GetFullURI( true ), row->GetProperties() );
444 }
445 
446 
448 {
449  wxString nickname = aLibId.GetLibNickname();
450  wxString name = aLibId.GetLibItemName();
451 
452  if( nickname.size() )
453  {
454  return LoadSymbol( nickname, name );
455  }
456 
457  // nickname is empty, sequentially search (alphabetically) all libs/nicks for first match:
458  else
459  {
460  std::vector<wxString> nicks = GetLogicalLibs();
461 
462  // Search each library going through libraries alphabetically.
463  for( unsigned i = 0; i < nicks.size(); ++i )
464  {
465  // FootprintLoad() returns NULL on not found, does not throw exception
466  // unless there's an IO_ERROR.
467  LIB_PART* ret = LoadSymbol( nicks[i], name );
468 
469  if( ret )
470  return ret;
471  }
472 
473  return nullptr;
474  }
475 }
476 
477 
479 {
480  return "KICAD_SYMBOL_DIR";
481 }
482 
483 
485 {
486  bool tableExists = true;
487  wxFileName fn = GetGlobalTableFileName();
488 
489  if( !fn.FileExists() )
490  {
491  tableExists = false;
492 
493  if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
494  {
496  _( "Cannot create global library table path \"%s\"." ), fn.GetPath() ) );
497  }
498 
499  // Attempt to copy the default global file table from the KiCad
500  // template folder to the user's home configuration path.
501  SEARCH_STACK ss;
502 
503  SystemDirsAppend( &ss );
504 
505  wxString templatePath =
506  Pgm().GetLocalEnvVariables().at( wxT( "KICAD_TEMPLATE_DIR" ) ).GetValue();
507 
508  if( !templatePath.IsEmpty() )
509  ss.AddPaths( templatePath, 0 );
510 
511  wxString fileName = ss.FindValidPath( global_tbl_name );
512 
513  // The fallback is to create an empty global symbol table for the user to populate.
514  if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) )
515  {
516  SYMBOL_LIB_TABLE emptyTable;
517 
518  emptyTable.Save( fn.GetFullPath() );
519  }
520  }
521 
522  aTable.Load( fn.GetFullPath() );
523 
524  return tableExists;
525 }
526 
527 
529 {
530  wxFileName fn;
531 
533  fn.SetName( global_tbl_name );
534 
535  return fn.GetFullPath();
536 }
537 
538 
540 {
541  return global_tbl_name;
542 }
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...
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:328
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.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:102
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.
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
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Function Format outputs 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
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.
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:408
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.