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-2017 Wayne Stambaugh <stambaughw@gmail.com>
5  * Copyright (C) 2016-2017 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 <kiface_i.h>
29 #include <macros.h>
30 #include <lib_id.h>
31 #include <lib_table_lexer.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 
47 
48 
50 {
51  return LIB_TABLE_ROW::operator == ( aRow ) && type == aRow.type;
52 }
53 
54 
55 void SYMBOL_LIB_TABLE_ROW::SetType( const wxString& aType )
56 {
57  type = SCH_IO_MGR::EnumFromStr( aType );
58 
59  if( SCH_IO_MGR::SCH_FILE_T( -1 ) == type )
60  type = SCH_IO_MGR::SCH_KICAD;
61 }
62 
63 
65  LIB_TABLE( aFallBackTable )
66 {
67  // not copying fall back, simply search aFallBackTable separately
68  // if "nickName not found".
69 }
70 
71 
73 {
74  return g_symbolLibraryTable;
75 }
76 
77 
79 {
80  T tok;
81  wxString errMsg; // to collect error messages
82 
83  // This table may be nested within a larger s-expression, or not.
84  // Allow for parser of that optional containing s-epression to have looked ahead.
85  if( in->CurTok() != T_sym_lib_table )
86  {
87  in->NeedLEFT();
88  if( ( tok = in->NextTok() ) != T_sym_lib_table )
90  }
91 
92  while( ( tok = in->NextTok() ) != T_RIGHT )
93  {
94  std::unique_ptr< SYMBOL_LIB_TABLE_ROW > row( new SYMBOL_LIB_TABLE_ROW );
95 
96  if( tok == T_EOF )
97  in->Expecting( T_RIGHT );
98 
99  if( tok != T_LEFT )
100  in->Expecting( T_LEFT );
101 
102  // in case there is a "row integrity" error, tell where later.
103  int lineNum = in->CurLineNumber();
104 
105  if( ( tok = in->NextTok() ) != T_lib )
106  in->Expecting( T_lib );
107 
108  // (name NICKNAME)
109  in->NeedLEFT();
110 
111  if( ( tok = in->NextTok() ) != T_name )
112  in->Expecting( T_name );
113 
114  in->NeedSYMBOLorNUMBER();
115 
116  row->SetNickName( in->FromUTF8() );
117 
118  in->NeedRIGHT();
119 
120  // After (name), remaining (lib) elements are order independent, and in
121  // some cases optional.
122  bool sawType = false;
123  bool sawOpts = false;
124  bool sawDesc = false;
125  bool sawUri = false;
126 
127  while( ( tok = in->NextTok() ) != T_RIGHT )
128  {
129  if( tok == T_EOF )
130  in->Unexpected( T_EOF );
131 
132  if( tok != T_LEFT )
133  in->Expecting( T_LEFT );
134 
135  tok = in->NeedSYMBOLorNUMBER();
136 
137  switch( tok )
138  {
139  case T_uri:
140  if( sawUri )
141  in->Duplicate( tok );
142  sawUri = true;
143  in->NeedSYMBOLorNUMBER();
144  row->SetFullURI( in->FromUTF8() );
145  break;
146 
147  case T_type:
148  if( sawType )
149  in->Duplicate( tok );
150  sawType = true;
151  in->NeedSYMBOLorNUMBER();
152  row->SetType( in->FromUTF8() );
153  break;
154 
155  case T_options:
156  if( sawOpts )
157  in->Duplicate( tok );
158  sawOpts = true;
159  in->NeedSYMBOLorNUMBER();
160  row->SetOptions( in->FromUTF8() );
161  break;
162 
163  case T_descr:
164  if( sawDesc )
165  in->Duplicate( tok );
166  sawDesc = true;
167  in->NeedSYMBOLorNUMBER();
168  row->SetDescr( in->FromUTF8() );
169  break;
170 
171  default:
172  in->Unexpected( tok );
173  }
174 
175  in->NeedRIGHT();
176  }
177 
178  if( !sawType )
179  in->Expecting( T_type );
180 
181  if( !sawUri )
182  in->Expecting( T_uri );
183 
184  // all nickNames within this table fragment must be unique, so we do not
185  // use doReplace in InsertRow(). (However a fallBack table can have a
186  // conflicting nickName and ours will supercede that one since in
187  // FindLib() we search this table before any fall back.)
188  wxString nickname = row->GetNickName(); // store it to be able to used it
189  // after row deletion if an error occurs
190  LIB_TABLE_ROW* tmp = row.release();
191 
192  if( !InsertRow( tmp ) )
193  {
194  delete tmp; // The table did not take ownership of the row.
195 
196  wxString msg = wxString::Format(
197  _( "Duplicate library nickname '%s' found in symbol library "
198  "table file line %d" ), GetChars( nickname ), lineNum );
199 
200  if( !errMsg.IsEmpty() )
201  errMsg << '\n';
202 
203  errMsg << msg;
204  }
205  }
206 
207  if( !errMsg.IsEmpty() )
208  THROW_IO_ERROR( errMsg );
209 }
210 
211 
212 void SYMBOL_LIB_TABLE::Format( OUTPUTFORMATTER* aOutput, int aIndentLevel ) const
213 {
214  aOutput->Print( aIndentLevel, "(sym_lib_table\n" );
215 
216  for( LIB_TABLE_ROWS_CITER it = rows.begin(); it != rows.end(); ++it )
217  it->Format( aOutput, aIndentLevel+1 );
218 
219  aOutput->Print( aIndentLevel, ")\n" );
220 }
221 
222 
223 void SYMBOL_LIB_TABLE::EnumerateSymbolLib( const wxString& aNickname, wxArrayString& aAliasNames )
224 {
225  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
226  wxASSERT( (SCH_PLUGIN*) row->plugin );
227  row->plugin->EnumerateSymbolLib( aAliasNames, row->GetFullURI( true ), row->GetProperties() );
228 }
229 
230 
231 const SYMBOL_LIB_TABLE_ROW* SYMBOL_LIB_TABLE::FindRow( const wxString& aNickname )
232 
233 {
234  SYMBOL_LIB_TABLE_ROW* row = dynamic_cast< SYMBOL_LIB_TABLE_ROW* >( findRow( aNickname ) );
235 
236  if( !row )
237  {
238  wxString msg = wxString::Format(
239  _( "sym-lib-table files contain no library with nickname '%s'" ),
240  GetChars( aNickname ) );
241 
242  THROW_IO_ERROR( msg );
243  }
244 
245  // We've been 'lazy' up until now, but it cannot be deferred any longer,
246  // instantiate a PLUGIN of the proper kind if it is not already in this
247  // SYMBOL_LIB_TABLE_ROW.
248  if( !row->plugin )
249  row->setPlugin( SCH_IO_MGR::FindPlugin( row->type ) );
250 
251  return row;
252 }
253 
254 
255 LIB_ALIAS* SYMBOL_LIB_TABLE::LoadSymbol( const wxString& aNickname, const wxString& aAliasName )
256 {
257  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
258  wxASSERT( (SCH_PLUGIN*) row->plugin );
259 
260  LIB_ALIAS* ret = row->plugin->LoadSymbol( row->GetFullURI( true ), aAliasName,
261  row->GetProperties() );
262 
263  // The library cannot know its own name, because it might have been renamed or moved.
264  // Therefore footprints cannot know their own library nickname when residing in
265  // a symbol library.
266  // Only at this API layer can we tell the symbol about its actual library nickname.
267  if( ret )
268  {
269  // remove "const"-ness, I really do want to set nickname without
270  // having to copy the LIB_ID and its two strings, twice each.
271  LIB_ID& id = (LIB_ID&) ret->GetPart()->GetLibId();
272 
273  // Catch any misbehaving plugin, which should be setting internal alias name properly:
274  wxASSERT( aAliasName == id.GetLibItemName().wx_str() );
275 
276  // and clearing nickname
277  wxASSERT( !id.GetLibNickname().size() );
278 
279  id.SetLibNickname( row->GetNickName() );
280  }
281 
282  return ret;
283 }
284 
285 
287  const LIB_PART* aSymbol, bool aOverwrite )
288 {
289  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
290  wxASSERT( (SCH_PLUGIN*) row->plugin );
291 
292  if( !aOverwrite )
293  {
294  // Try loading the footprint to see if it already exists, caller wants overwrite
295  // protection, which is atypical, not the default.
296 
297  wxString name = aSymbol->GetLibId().GetLibItemName();
298 
299  std::unique_ptr< LIB_ALIAS > symbol( row->plugin->LoadSymbol( row->GetFullURI( true ),
300  name,
301  row->GetProperties() ) );
302 
303  if( symbol.get() )
304  return SAVE_SKIPPED;
305  }
306 
307  row->plugin->SaveSymbol( row->GetFullURI( true ), aSymbol, row->GetProperties() );
308 
309  return SAVE_OK;
310 }
311 
312 
313 void SYMBOL_LIB_TABLE::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
314 {
315  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
316  wxASSERT( (SCH_PLUGIN*) row->plugin );
317  return row->plugin->DeleteSymbol( row->GetFullURI( true ), aSymbolName,
318  row->GetProperties() );
319 }
320 
321 
322 void SYMBOL_LIB_TABLE::DeleteAlias( const wxString& aNickname, const wxString& aAliasName )
323 {
324  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
325  wxASSERT( (SCH_PLUGIN*) row->plugin );
326  return row->plugin->DeleteAlias( row->GetFullURI( true ), aAliasName,
327  row->GetProperties() );
328 }
329 
330 
331 bool SYMBOL_LIB_TABLE::IsSymbolLibWritable( const wxString& aNickname )
332 {
333  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
334  wxASSERT( (SCH_PLUGIN*) row->plugin );
335  return row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) );
336 }
337 
338 
339 void SYMBOL_LIB_TABLE::DeleteSymbolLib( const wxString& aNickname )
340 {
341  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
342  wxASSERT( (SCH_PLUGIN*) row->plugin );
343  row->plugin->DeleteSymbolLib( row->GetFullURI( true ), row->GetProperties() );
344 }
345 
346 
347 void SYMBOL_LIB_TABLE::CreateSymbolLib( const wxString& aNickname )
348 {
349  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
350  wxASSERT( (SCH_PLUGIN*) row->plugin );
351  row->plugin->CreateSymbolLib( row->GetFullURI( true ), row->GetProperties() );
352 }
353 
354 
356 {
357  wxString nickname = aLibId.GetLibNickname();
358  wxString name = aLibId.GetLibItemName();
359 
360  if( nickname.size() )
361  {
362  return LoadSymbol( nickname, name );
363  }
364 
365  // nickname is empty, sequentially search (alphabetically) all libs/nicks for first match:
366  else
367  {
368  std::vector<wxString> nicks = GetLogicalLibs();
369 
370  // Search each library going through libraries alphabetically.
371  for( unsigned i = 0; i < nicks.size(); ++i )
372  {
373  // FootprintLoad() returns NULL on not found, does not throw exception
374  // unless there's an IO_ERROR.
375  LIB_ALIAS* ret = LoadSymbol( nicks[i], name );
376 
377  if( ret )
378  return ret;
379  }
380 
381  return NULL;
382  }
383 }
384 
385 
387 {
388  return "KICAD_SYMBOL_DIR";
389 }
390 
391 
393 {
394  bool tableExists = true;
395  wxFileName fn = GetGlobalTableFileName();
396 
397  if( !fn.FileExists() )
398  {
399  tableExists = false;
400 
401  if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
402  {
403  THROW_IO_ERROR( wxString::Format( _( "Cannot create global library table path '%s'." ),
404  GetChars( fn.GetPath() ) ) );
405  }
406 
407  // Attempt to copy the default global file table from the KiCad
408  // template folder to the user's home configuration path.
409  wxString fileName = Kiface().KifaceSearch().FindValidPath( global_tbl_name );
410 
411  // The fallback is to create an empty global symbol table for the user to populate.
412  if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) )
413  {
414  SYMBOL_LIB_TABLE emptyTable;
415 
416  emptyTable.Save( fn.GetFullPath() );
417  }
418  }
419 
420  aTable.Load( fn.GetFullPath() );
421 
422  return tableExists;
423 }
424 
425 
427 {
428  wxFileName fn;
429 
430  fn.SetPath( GetKicadConfigPath() );
431  fn.SetName( global_tbl_name );
432 
433  return fn.GetFullPath();
434 }
435 
436 
438 {
439  return global_tbl_name;
440 }
void EnumerateSymbolLib(const wxString &aNickname, wxArrayString &aAliasNames)
Return a list of symbol alias names contained within the library given by aNickname.
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.
virtual void CreateSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL)
Create a new empty symbol library at aLibraryPath.
Definition: sch_plugin.cpp:134
static const wxString & GetSymbolLibTableFileName()
static SYMBOL_LIB_TABLE & GetGlobalLibTable()
Part library alias object definition.
virtual LIB_ALIAS * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const PROPERTIES *aProperties=NULL)
Load a LIB_ALIAS object having aAliasName from the aLibraryPath containing a library format that this...
Definition: sch_plugin.cpp:101
virtual bool DeleteSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL)
Delete an existing symbol library and returns true if successful, or if library does not exist return...
Definition: sch_plugin.cpp:141
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
LIB_TABLE_T::T CurTok()
Function CurTok returns whatever NextTok() returned the last time it was called.
Class LIB_TABLE_ROW.
SYMBOL_LIB_TABLE(SYMBOL_LIB_TABLE *aFallBackTable=NULL)
Build a symbol library table by pre-pending this table fragment in front of aFallBackTable.
const 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...
void CreateSymbolLib(const wxString &aNickname)
const PROPERTIES * GetProperties() const
Function GetProperties.
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Function InsertRow.
SCH_PLUGIN::SCH_PLUGIN_RELEASER plugin
T
enum T contains all this lexer's tokens.
virtual void DeleteSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const PROPERTIES *aProperties=NULL)
Delete the entire LIB_PART associated with aAliasName from the library aLibraryPath.
Definition: sch_plugin.cpp:126
void DeleteSymbolLib(const wxString &aNickname)
static SCH_PLUGIN * FindPlugin(SCH_FILE_T aFileType)
Return a SCH_PLUGIN which the caller can use to import, export, save, or load design documents...
Definition: sch_io_mgr.cpp:48
void SetType(const wxString &aType) override
Change the schematic plugin type represented by this row.
void Unexpected(int aTok)
Function Unexpected throws an IO_ERROR exception with an input file specific error message...
Definition: dsnlexer.cpp:369
virtual void EnumerateSymbolLib(wxArrayString &aAliasNameList, const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL)
Populate a list of LIB_PART alias names contained within the library aLibraryPath.
Definition: sch_plugin.cpp:83
const LIB_ID & GetLibId() const
static const wxString GlobalPathEnvVariableName()
Return the name of the environment variable used to hold the directory of locally installed "KiCad sp...
Class OUTPUTFORMATTER is an important interface (abstract class) used to output 8 bit text in a conve...
Definition: richio.h:327
LIB_TABLE_ROWS rows
static const wxString global_tbl_name("sym-lib-table")
Class LIB_ID.
Definition: lib_id.h:56
wxString FromUTF8()
Function FromUTF8 returns the current token text as a wxString, assuming that the input byte stream i...
Definition: dsnlexer.h:498
bool IsSymbolLibWritable(const wxString &aNickname)
Return true if the library given by aNickname is writable.
const wxString GetFullURI(bool aSubstituted=false) const
Function GetFullURI.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
This file contains miscellaneous commonly used macros and functions.
bool operator==(const SYMBOL_LIB_TABLE_ROW &aRow) const
LIB_ALIAS * LoadSymbolWithOptionalNickname(const LIB_ID &aId)
Load a LIB_PART having aFootprintId with possibly an empty library nickname.
SEARCH_STACK & KifaceSearch()
Only for DSO specific 'non-library' files.
Definition: kiface_i.h:127
void NeedLEFT()
Function NeedLEFT calls NextTok() and then verifies that the token read in is a DSN_LEFT.
Definition: dsnlexer.cpp:393
Base class that schematic file and library loading and saving plugins should derive from...
Definition: sch_io_mgr.h:184
static bool LoadGlobalTable(SYMBOL_LIB_TABLE &aTable)
Load the global symbol library table into aTable.
LIB_TABLE_T::T NeedSYMBOLorNUMBER()
Function NeedSYMBOLorNUMBER calls NextTok() and then verifies that the token read in satisfies bool I...
const UTF8 & GetLibItemName() const
Function GetLibItemName.
Definition: lib_id.h:129
Class LIB_ITEM definition.
Class LIB_PART defines a library part object.
bool operator==(const LIB_TABLE_ROW &r) const
void Save(const wxString &aFileName) const
Function Save.
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)
The s-expression version of the schematic file formats.
Definition: sch_io_mgr.h:55
LIB_TABLE_ROW * findRow(const wxString &aNickname) const
Function findRow returns a LIB_TABLE_ROW if aNickname is found in this table or in any chained fallBa...
void Expecting(int aTok)
Function Expecting throws an IO_ERROR exception with an input file specific error message...
Definition: dsnlexer.cpp:353
void Load(const wxString &aFileName)
Function Load.
wxString GetKicadConfigPath()
Function GetKicadConfigPath.
Definition: common.cpp:217
LIB_PART * GetPart() const
Function GetPart gets the shared LIB_PART.
const wxString & GetNickName() const
Function GetNickName.
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:92
LIB_TABLE_ROWS::const_iterator LIB_TABLE_ROWS_CITER
LIB_TABLE_T::T NextTok()
Function NextTok returns the next token found in the input file or T_EOF when reaching the end of fil...
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
void Duplicate(int aTok)
Function Duplicate throws an IO_ERROR exception with a message saying specifically that aTok is a dup...
Definition: dsnlexer.cpp:377
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy", etc...
Definition: sch_io_mgr.cpp:92
virtual void Parse(LIB_TABLE_LEXER *aLexer) override
Function Parse.
int CurLineNumber()
Function CurLineNumber returns the current line number within my LINE_READER.
Definition: dsnlexer.h:507
The common library.
virtual bool IsSymbolLibWritable(const wxString &aLibraryPath)
Return true if the library at aLibraryPath is writable.
Definition: sch_plugin.cpp:149
const char * name
virtual void DeleteAlias(const wxString &aLibraryPath, const wxString &aAliasName, const PROPERTIES *aProperties=NULL)
Delete aAliasName from the library at aLibraryPath.
Definition: sch_plugin.cpp:118
void NeedRIGHT()
Function NeedRIGHT calls NextTok() and then verifies that the token read in is a DSN_RIGHT.
Definition: dsnlexer.cpp:401
Class LIB_TABLE_LEXER is an automatically generated class using the TokenList2DnsLexer.cmake technology, based on keywords provided by file: /home/kicad/workspace/kicad-doxygen/common/lib_table.keywords.
virtual void SaveSymbol(const wxString &aLibraryPath, const LIB_PART *aSymbol, const PROPERTIES *aProperties=NULL)
Write aSymbol to an existing library located at aLibraryPath.
Definition: sch_plugin.cpp:110
SAVE_T
The set of return values from SaveSymbol() below.
SYMBOL_LIB_TABLE g_symbolLibraryTable
The global symbol library table.
wxString FindValidPath(const wxString &aFileName) const
Definition: search_stack.h:71
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:408
const UTF8 & GetLibNickname() const
Function GetLibNickname.
Definition: lib_id.h:108
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
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.
std::vector< wxString > GetLogicalLibs()
Function GetLogicalLibs.
SCH_FILE_T
A set of file types that the SCH_IO_MGR knows about, and for which there has been a plugin written...
Definition: sch_io_mgr.h:52
C++ does not put enum values in separate namespaces unless the enum itself is in a separate namespace...
Class LIB_TABLE.