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