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