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  wxFAIL_MSG( "sym-lib-table files contain no library with nickname " + aNickname );
290  return nullptr;
291  }
292 
293  // We've been 'lazy' up until now, but it cannot be deferred any longer,
294  // instantiate a PLUGIN of the proper kind if it is not already in this
295  // SYMBOL_LIB_TABLE_ROW.
296  if( !row->plugin )
297  row->setPlugin( SCH_IO_MGR::FindPlugin( row->type ) );
298 
299  return row;
300 }
301 
302 
303 void SYMBOL_LIB_TABLE::LoadSymbolLib( std::vector<LIB_PART*>& aSymbolList,
304  const wxString& aNickname, bool aPowerSymbolsOnly )
305 {
306  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
307  wxCHECK( row && row->plugin, /* void */ );
308 
309  wxString options = row->GetOptions();
310 
311  if( aPowerSymbolsOnly )
312  row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
313 
314  row->plugin->EnumerateSymbolLib( aSymbolList, row->GetFullURI( true ), row->GetProperties() );
315 
316  if( aPowerSymbolsOnly )
317  row->SetOptions( options );
318 
319  // The library cannot know its own name, because it might have been renamed or moved.
320  // Therefore footprints cannot know their own library nickname when residing in
321  // a symbol library.
322  // Only at this API layer can we tell the symbol about its actual library nickname.
323  for( LIB_PART* part : aSymbolList )
324  {
325  LIB_ID id = part->GetLibId();
326 
327  id.SetLibNickname( row->GetNickName() );
328  part->SetLibId( id );
329  }
330 }
331 
332 
333 LIB_PART* SYMBOL_LIB_TABLE::LoadSymbol( const wxString& aNickname, const wxString& aSymbolName )
334 {
335  SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
336  wxCHECK( row && row->plugin, nullptr );
337 
338  LIB_PART* part = row->plugin->LoadSymbol( row->GetFullURI( true ), aSymbolName,
339  row->GetProperties() );
340 
341  if( part == nullptr )
342  return part;
343 
344  // The library cannot know its own name, because it might have been renamed or moved.
345  // Therefore footprints cannot know their own library nickname when residing in
346  // a symbol library.
347  // Only at this API layer can we tell the symbol about its actual library nickname.
348  if( part )
349  {
350  LIB_ID id = part->GetLibId();
351 
352  id.SetLibNickname( row->GetNickName() );
353  part->SetLibId( id );
354  }
355 
356  return part;
357 }
358 
359 
361  const LIB_PART* aSymbol, bool aOverwrite )
362 {
363  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
364  wxCHECK( row && row->plugin, SAVE_SKIPPED );
365 
366  if( !aOverwrite )
367  {
368  // Try loading the footprint to see if it already exists, caller wants overwrite
369  // protection, which is atypical, not the default.
370 
371  wxString name = aSymbol->GetLibId().GetLibItemName();
372 
373  std::unique_ptr< LIB_PART > symbol( row->plugin->LoadSymbol( row->GetFullURI( true ),
374  name,
375  row->GetProperties() ) );
376 
377  if( symbol.get() )
378  return SAVE_SKIPPED;
379  }
380 
381  row->plugin->SaveSymbol( row->GetFullURI( true ), aSymbol, row->GetProperties() );
382 
383  return SAVE_OK;
384 }
385 
386 
387 void SYMBOL_LIB_TABLE::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
388 {
389  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
390  wxCHECK( row && row->plugin, /* void */ );
391  return row->plugin->DeleteSymbol( row->GetFullURI( true ), aSymbolName,
392  row->GetProperties() );
393 }
394 
395 
396 bool SYMBOL_LIB_TABLE::IsSymbolLibWritable( const wxString& aNickname )
397 {
398  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
399  wxCHECK( row && row->plugin, false );
400  return row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) );
401 }
402 
403 
404 void SYMBOL_LIB_TABLE::DeleteSymbolLib( const wxString& aNickname )
405 {
406  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
407  wxCHECK( row && row->plugin, /* void */ );
408  row->plugin->DeleteSymbolLib( row->GetFullURI( true ), row->GetProperties() );
409 }
410 
411 
412 void SYMBOL_LIB_TABLE::CreateSymbolLib( const wxString& aNickname )
413 {
414  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
415  wxCHECK( row && row->plugin, /* void */ );
416  row->plugin->CreateSymbolLib( row->GetFullURI( true ), row->GetProperties() );
417 }
418 
419 
421 {
422  wxString nickname = aLibId.GetLibNickname();
423  wxString name = aLibId.GetLibItemName();
424 
425  if( nickname.size() )
426  {
427  return LoadSymbol( nickname, name );
428  }
429 
430  // nickname is empty, sequentially search (alphabetically) all libs/nicks for first match:
431  else
432  {
433  std::vector<wxString> nicks = GetLogicalLibs();
434 
435  // Search each library going through libraries alphabetically.
436  for( unsigned i = 0; i < nicks.size(); ++i )
437  {
438  // FootprintLoad() returns NULL on not found, does not throw exception
439  // unless there's an IO_ERROR.
440  LIB_PART* ret = LoadSymbol( nicks[i], name );
441 
442  if( ret )
443  return ret;
444  }
445 
446  return nullptr;
447  }
448 }
449 
450 
452 {
453  return "KICAD_SYMBOL_DIR";
454 }
455 
456 
458 {
459  bool tableExists = true;
460  wxFileName fn = GetGlobalTableFileName();
461 
462  if( !fn.FileExists() )
463  {
464  tableExists = false;
465 
466  if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
467  {
468  THROW_IO_ERROR( wxString::Format( _( "Cannot create global library table path \"%s\"." ),
469  GetChars( fn.GetPath() ) ) );
470  }
471 
472  // Attempt to copy the default global file table from the KiCad
473  // template folder to the user's home configuration path.
474  SEARCH_STACK ss;
475 
476  SystemDirsAppend( &ss );
477 
478  wxString templatePath =
479  Pgm().GetLocalEnvVariables().at( wxT( "KICAD_TEMPLATE_DIR" ) ).GetValue();
480 
481  if( !templatePath.IsEmpty() )
482  ss.AddPaths( templatePath, 0 );
483 
484  wxString fileName = ss.FindValidPath( global_tbl_name );
485 
486  // The fallback is to create an empty global symbol table for the user to populate.
487  if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) )
488  {
489  SYMBOL_LIB_TABLE emptyTable;
490 
491  emptyTable.Save( fn.GetFullPath() );
492  }
493  }
494 
495  aTable.Load( fn.GetFullPath() );
496 
497  return tableExists;
498 }
499 
500 
502 {
503  wxFileName fn;
504 
505  fn.SetPath( GetKicadConfigPath() );
506  fn.SetName( global_tbl_name );
507 
508  return fn.GetFullPath();
509 }
510 
511 
513 {
514  return global_tbl_name;
515 }
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:98
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
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...
const wxString & GetNickName() const
static bool LoadGlobalTable(SYMBOL_LIB_TABLE &aTable)
Load the global symbol library table into aTable.
Class LIB_PIN definition.
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,...
#define THROW_IO_ERROR(msg)
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:242
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: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: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
#define _(s)
Definition: 3d_actions.cpp:31
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)
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.