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 
82  // This table may be nested within a larger s-expression, or not.
83  // Allow for parser of that optional containing s-epression to have looked ahead.
84  if( in->CurTok() != T_sym_lib_table )
85  {
86  in->NeedLEFT();
87  if( ( tok = in->NextTok() ) != T_sym_lib_table )
89  }
90 
91  while( ( tok = in->NextTok() ) != T_RIGHT )
92  {
93  std::unique_ptr< SYMBOL_LIB_TABLE_ROW > row( new SYMBOL_LIB_TABLE_ROW );
94 
95  if( tok == T_EOF )
96  in->Expecting( T_RIGHT );
97 
98  if( tok != T_LEFT )
99  in->Expecting( T_LEFT );
100 
101  // in case there is a "row integrity" error, tell where later.
102  int lineNum = in->CurLineNumber();
103  int offset = in->CurOffset();
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  if( !InsertRow( row.release() ) )
189  {
190  wxString msg = wxString::Format(
191  _( "'%s' is a duplicate symbol library nickname" ),
192  GetChars( row->GetNickName() ) );
193  THROW_PARSE_ERROR( msg, in->CurSource(), in->CurLine(), lineNum, offset );
194  }
195  }
196 }
197 
198 
199 void SYMBOL_LIB_TABLE::Format( OUTPUTFORMATTER* aOutput, int aIndentLevel ) const
200 {
201  aOutput->Print( aIndentLevel, "(sym_lib_table\n" );
202 
203  for( LIB_TABLE_ROWS_CITER it = rows.begin(); it != rows.end(); ++it )
204  it->Format( aOutput, aIndentLevel+1 );
205 
206  aOutput->Print( aIndentLevel, ")\n" );
207 }
208 
209 
210 void SYMBOL_LIB_TABLE::EnumerateSymbolLib( const wxString& aNickname, wxArrayString& aAliasNames )
211 {
212  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
213  wxASSERT( (SCH_PLUGIN*) row->plugin );
214  row->plugin->EnumerateSymbolLib( aAliasNames, row->GetFullURI( true ), row->GetProperties() );
215 }
216 
217 
218 const SYMBOL_LIB_TABLE_ROW* SYMBOL_LIB_TABLE::FindRow( const wxString& aNickname )
219  throw( IO_ERROR )
220 {
221  SYMBOL_LIB_TABLE_ROW* row = dynamic_cast< SYMBOL_LIB_TABLE_ROW* >( findRow( aNickname ) );
222 
223  if( !row )
224  {
225  wxString msg = wxString::Format(
226  _( "sym-lib-table files contain no library with nickname '%s'" ),
227  GetChars( aNickname ) );
228 
229  THROW_IO_ERROR( msg );
230  }
231 
232  // We've been 'lazy' up until now, but it cannot be deferred any longer,
233  // instantiate a PLUGIN of the proper kind if it is not already in this
234  // SYMBOL_LIB_TABLE_ROW.
235  if( !row->plugin )
236  row->setPlugin( SCH_IO_MGR::FindPlugin( row->type ) );
237 
238  return row;
239 }
240 
241 
242 LIB_ALIAS* SYMBOL_LIB_TABLE::LoadSymbol( const wxString& aNickname, const wxString& aAliasName )
243 {
244  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
245  wxASSERT( (SCH_PLUGIN*) row->plugin );
246 
247  LIB_ALIAS* ret = row->plugin->LoadSymbol( row->GetFullURI( true ), aAliasName,
248  row->GetProperties() );
249 
250  // The library cannot know its own name, because it might have been renamed or moved.
251  // Therefore footprints cannot know their own library nickname when residing in
252  // a symbol library.
253  // Only at this API layer can we tell the symbol about its actual library nickname.
254  if( ret )
255  {
256  // remove "const"-ness, I really do want to set nickname without
257  // having to copy the LIB_ID and its two strings, twice each.
258  LIB_ID& id = (LIB_ID&) ret->GetPart()->GetLibId();
259 
260  // Catch any misbehaving plugin, which should be setting internal alias name properly:
261  wxASSERT( aAliasName == FROM_UTF8( id.GetLibItemName() ) );
262 
263  // and clearing nickname
264  wxASSERT( !id.GetLibNickname().size() );
265 
266  id.SetLibNickname( TO_UTF8( row->GetNickName() ) );
267  }
268 
269  return ret;
270 }
271 
272 
274  const LIB_PART* aSymbol, bool aOverwrite )
275 {
276  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
277  wxASSERT( (SCH_PLUGIN*) row->plugin );
278 
279  if( !aOverwrite )
280  {
281  // Try loading the footprint to see if it already exists, caller wants overwrite
282  // protection, which is atypical, not the default.
283 
284  wxString name = FROM_UTF8( aSymbol->GetLibId().GetLibItemName() );
285 
286  std::unique_ptr< LIB_ALIAS > symbol( row->plugin->LoadSymbol( row->GetFullURI( true ),
287  name,
288  row->GetProperties() ) );
289 
290  if( symbol.get() )
291  return SAVE_SKIPPED;
292  }
293 
294  row->plugin->SaveSymbol( row->GetFullURI( true ), aSymbol, row->GetProperties() );
295 
296  return SAVE_OK;
297 }
298 
299 
300 void SYMBOL_LIB_TABLE::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
301 {
302  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
303  wxASSERT( (SCH_PLUGIN*) row->plugin );
304  return row->plugin->DeleteSymbol( row->GetFullURI( true ), aSymbolName,
305  row->GetProperties() );
306 }
307 
308 
309 void SYMBOL_LIB_TABLE::DeleteAlias( const wxString& aNickname, const wxString& aAliasName )
310 {
311  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
312  wxASSERT( (SCH_PLUGIN*) row->plugin );
313  return row->plugin->DeleteAlias( row->GetFullURI( true ), aAliasName,
314  row->GetProperties() );
315 }
316 
317 
318 bool SYMBOL_LIB_TABLE::IsSymbolLibWritable( const wxString& aNickname )
319 {
320  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
321  wxASSERT( (SCH_PLUGIN*) row->plugin );
322  return row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) );
323 }
324 
325 
326 void SYMBOL_LIB_TABLE::DeleteSymbolLib( const wxString& aNickname )
327 {
328  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
329  wxASSERT( (SCH_PLUGIN*) row->plugin );
330  row->plugin->DeleteSymbolLib( row->GetFullURI( true ), row->GetProperties() );
331 }
332 
333 
334 void SYMBOL_LIB_TABLE::CreateSymbolLib( const wxString& aNickname )
335 {
336  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
337  wxASSERT( (SCH_PLUGIN*) row->plugin );
338  row->plugin->CreateSymbolLib( row->GetFullURI( true ), row->GetProperties() );
339 }
340 
341 
343  throw( IO_ERROR, PARSE_ERROR, boost::interprocess::lock_exception )
344 {
345  wxString nickname = FROM_UTF8( aLibId.GetLibNickname() );
346  wxString name = FROM_UTF8( aLibId.GetLibItemName() );
347 
348  if( nickname.size() )
349  {
350  return LoadSymbol( nickname, name );
351  }
352 
353  // nickname is empty, sequentially search (alphabetically) all libs/nicks for first match:
354  else
355  {
356  std::vector<wxString> nicks = GetLogicalLibs();
357 
358  // Search each library going through libraries alphabetically.
359  for( unsigned i = 0; i < nicks.size(); ++i )
360  {
361  // FootprintLoad() returns NULL on not found, does not throw exception
362  // unless there's an IO_ERROR.
363  LIB_ALIAS* ret = LoadSymbol( nicks[i], name );
364 
365  if( ret )
366  return ret;
367  }
368 
369  return NULL;
370  }
371 }
372 
373 
375 {
376  return "KICAD_SYMBOL_DIR";
377 }
378 
379 
381  throw (IO_ERROR, PARSE_ERROR, boost::interprocess::lock_exception )
382 {
383  bool tableExists = true;
384  wxFileName fn = GetGlobalTableFileName();
385 
386  if( !fn.FileExists() )
387  {
388  tableExists = false;
389 
390  if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
391  {
392  THROW_IO_ERROR( wxString::Format( _( "Cannot create global library table path '%s'." ),
393  GetChars( fn.GetPath() ) ) );
394  }
395 
396  // Attempt to copy the default global file table from the KiCad
397  // template folder to the user's home configuration path.
398  wxString fileName = Kiface().KifaceSearch().FindValidPath( global_tbl_name );
399 
400  // The fallback is to create an empty global symbol table for the user to populate.
401  if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) )
402  {
403  SYMBOL_LIB_TABLE emptyTable;
404 
405  emptyTable.Save( fn.GetFullPath() );
406  }
407  }
408 
409  aTable.Load( fn.GetFullPath() );
410 
411  return tableExists;
412 }
413 
414 
416 {
417  wxFileName fn;
418 
419  fn.SetPath( GetKicadConfigPath() );
420  fn.SetName( global_tbl_name );
421 
422  return fn.GetFullPath();
423 }
424 
425 
427 {
428  return global_tbl_name;
429 }
void EnumerateSymbolLib(const wxString &aNickname, wxArrayString &aAliasNames)
Function EnumerateSymbolLib.
LIB_ALIAS * LoadSymbol(const wxString &aNickname, const wxString &aAliasName)
Function LoadSymbol.
SAVE_T SaveSymbol(const wxString &aNickname, const LIB_PART *aSymbol, bool aOverwrite=true)
Function SaveSymbol.
virtual void CreateSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL)
Function CreateSymbolLib.
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)
Function LoadSymbol.
Definition: sch_plugin.cpp:101
virtual bool DeleteSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL)
Function DeleteSymbolLib.
Definition: sch_plugin.cpp:141
Class SYMBOL_LIB_TABLE_ROW.
LIB_TABLE_T::T CurTok()
Function CurTok returns whatever NextTok() returned the last time it was called.
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
SYMBOL_LIB_TABLE(SYMBOL_LIB_TABLE *aFallBackTable=NULL)
Constructor SYMBOL_LIB_TABLE.
const SYMBOL_LIB_TABLE_ROW * FindRow(const wxString &aNickName)
Function FindRow.
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)
Function DeleteSymbol.
Definition: sch_plugin.cpp:126
void DeleteSymbolLib(const wxString &aNickname)
static SCH_PLUGIN * FindPlugin(SCH_FILE_T aFileType)
Function FindPlugin returns 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
Function SetType.
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)
Function EnumerateSymbolLib.
Definition: sch_plugin.cpp:83
const LIB_ID & GetLibId() const
static const wxString GlobalPathEnvVariableName()
Function GlobalPathEnvVarVariableName.
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)
Function IsSymbolLibWritable.
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.
void DeleteSymbol(const wxString &aNickname, const wxString &aSymboltName)
Function DeleteSymbol.
const wxString & CurSource()
Function CurFilename returns the current LINE_READER source.
Definition: dsnlexer.h:528
bool operator==(const SYMBOL_LIB_TABLE_ROW &aRow) const
LIB_ALIAS * LoadSymbolWithOptionalNickname(const LIB_ID &aId)
Function LoadSymboldWithOptionalNickname loads a LIB_PART having aFootprintId with possibly an empty ...
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
SEARCH_STACK & KifaceSearch()
Only for DSO specific 'non-library' files.
Definition: kiface_i.h:125
void NeedLEFT()
Function NeedLEFT calls NextTok() and then verifies that the token read in is a DSN_LEFT.
Definition: dsnlexer.cpp:393
Class SCH_PLUGIN is a base class that SCHEMATIC loading and saving plugins should derive from...
Definition: sch_io_mgr.h:187
static bool LoadGlobalTable(SYMBOL_LIB_TABLE &aTable)
Function LoadGlobalTable.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:133
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.
int CurOffset()
Function CurOffset returns the byte offset within the current line, using a 1 based index...
Definition: dsnlexer.h:538
Class LIB_PART defines a library part object.
bool operator==(const LIB_TABLE_ROW &r) const
void Save(const wxString &aFileName) const
Function Save.
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
virtual void Format(OUTPUTFORMATTER *aOutput, int aIndentLevel) const override
Function Format.
void setPlugin(SCH_PLUGIN *aPlugin)
The s-expression version of the schematic file formats.
Definition: sch_io_mgr.h:56
void Expecting(int aTok)
Function Expecting throws an IO_ERROR exception with an input file specific error message...
Definition: dsnlexer.cpp:353
wxString GetKicadConfigPath()
Function GetKicadConfigPath.
Definition: common.cpp:217
LIB_PART * GetPart() const
Function GetPart gets the shared LIB_PART.
const char * CurLine()
Function CurLine returns the current line of text, from which the CurText() would return its token...
Definition: dsnlexer.h:517
const wxString & GetNickName() const
Function GetNickName.
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller's report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:94
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 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)
Function EnumFromStr returns the SCH_FILE_T from the corresponding plugin type name: "kicad"...
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)
Function IsSymbolLibWritable returns 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)
Function DeleteAlias.
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)
Function SaveSymbol.
Definition: sch_plugin.cpp:110
SAVE_T
Enum SAVE_T.
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
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
static wxString GetGlobalTableFileName()
Function GetGlobalTableFileName.
void DeleteAlias(const wxString &aNickname, const wxString &aAliasName)
Function DeleteAlias.
SCH_FILE_T
Enum SCH_FILE_T is a set of file types that the SCH_IO_MGR knows about, and for which there has been ...
Definition: sch_io_mgr.h:53
C++ does not put enum values in separate namespaces unless the enum itself is in a separate namespace...
Class LIB_TABLE.