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 wxChar global_tbl_name[] = wxT( "sym-lib-table" );
41 
42 
44 
45 
47 {
48  return LIB_TABLE_ROW::operator == ( aRow ) && type == aRow.type;
49 }
50 
51 
52 void SYMBOL_LIB_TABLE_ROW::SetType( const wxString& aType )
53 {
54  type = SCH_IO_MGR::EnumFromStr( aType );
55 
56  if( SCH_IO_MGR::SCH_FILE_T( -1 ) == type )
57  type = SCH_IO_MGR::SCH_KICAD;
58 }
59 
60 
62  LIB_TABLE( aFallBackTable )
63 {
64  // not copying fall back, simply search aFallBackTable separately
65  // if "nickName not found".
66 }
67 
68 
70 {
71  T tok;
72 
73  // This table may be nested within a larger s-expression, or not.
74  // Allow for parser of that optional containing s-epression to have looked ahead.
75  if( in->CurTok() != T_sym_lib_table )
76  {
77  in->NeedLEFT();
78  if( ( tok = in->NextTok() ) != T_sym_lib_table )
80  }
81 
82  while( ( tok = in->NextTok() ) != T_RIGHT )
83  {
84  std::unique_ptr< SYMBOL_LIB_TABLE_ROW > row( new SYMBOL_LIB_TABLE_ROW );
85 
86  if( tok == T_EOF )
87  in->Expecting( T_RIGHT );
88 
89  if( tok != T_LEFT )
90  in->Expecting( T_LEFT );
91 
92  // in case there is a "row integrity" error, tell where later.
93  int lineNum = in->CurLineNumber();
94  int offset = in->CurOffset();
95 
96  if( ( tok = in->NextTok() ) != T_lib )
97  in->Expecting( T_lib );
98 
99  // (name NICKNAME)
100  in->NeedLEFT();
101 
102  if( ( tok = in->NextTok() ) != T_name )
103  in->Expecting( T_name );
104 
105  in->NeedSYMBOLorNUMBER();
106 
107  row->SetNickName( in->FromUTF8() );
108 
109  in->NeedRIGHT();
110 
111  // After (name), remaining (lib) elements are order independent, and in
112  // some cases optional.
113  bool sawType = false;
114  bool sawOpts = false;
115  bool sawDesc = false;
116  bool sawUri = false;
117 
118  while( ( tok = in->NextTok() ) != T_RIGHT )
119  {
120  if( tok == T_EOF )
121  in->Unexpected( T_EOF );
122 
123  if( tok != T_LEFT )
124  in->Expecting( T_LEFT );
125 
126  tok = in->NeedSYMBOLorNUMBER();
127 
128  switch( tok )
129  {
130  case T_uri:
131  if( sawUri )
132  in->Duplicate( tok );
133  sawUri = true;
134  in->NeedSYMBOLorNUMBER();
135  row->SetFullURI( in->FromUTF8() );
136  break;
137 
138  case T_type:
139  if( sawType )
140  in->Duplicate( tok );
141  sawType = true;
142  in->NeedSYMBOLorNUMBER();
143  row->SetType( in->FromUTF8() );
144  break;
145 
146  case T_options:
147  if( sawOpts )
148  in->Duplicate( tok );
149  sawOpts = true;
150  in->NeedSYMBOLorNUMBER();
151  row->SetOptions( in->FromUTF8() );
152  break;
153 
154  case T_descr:
155  if( sawDesc )
156  in->Duplicate( tok );
157  sawDesc = true;
158  in->NeedSYMBOLorNUMBER();
159  row->SetDescr( in->FromUTF8() );
160  break;
161 
162  default:
163  in->Unexpected( tok );
164  }
165 
166  in->NeedRIGHT();
167  }
168 
169  if( !sawType )
170  in->Expecting( T_type );
171 
172  if( !sawUri )
173  in->Expecting( T_uri );
174 
175  // all nickNames within this table fragment must be unique, so we do not
176  // use doReplace in InsertRow(). (However a fallBack table can have a
177  // conflicting nickName and ours will supercede that one since in
178  // FindLib() we search this table before any fall back.)
179  if( !InsertRow( row.release() ) )
180  {
181  wxString msg = wxString::Format(
182  _( "'%s' is a duplicate symbol library nickname" ),
183  GetChars( row->GetNickName() ) );
184  THROW_PARSE_ERROR( msg, in->CurSource(), in->CurLine(), lineNum, offset );
185  }
186  }
187 }
188 
189 
190 void SYMBOL_LIB_TABLE::Format( OUTPUTFORMATTER* aOutput, int aIndentLevel ) const
191 {
192  aOutput->Print( aIndentLevel, "(sym_lib_table\n" );
193 
194  for( LIB_TABLE_ROWS_CITER it = rows.begin(); it != rows.end(); ++it )
195  it->Format( aOutput, aIndentLevel+1 );
196 
197  aOutput->Print( aIndentLevel, ")\n" );
198 }
199 
200 
201 void SYMBOL_LIB_TABLE::EnumerateSymbolLib( const wxString& aNickname, wxArrayString& aAliasNames )
202 {
203  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
204  wxASSERT( (SCH_PLUGIN*) row->plugin );
205  row->plugin->EnumerateSymbolLib( aAliasNames, row->GetFullURI( true ), row->GetProperties() );
206 }
207 
208 
209 const SYMBOL_LIB_TABLE_ROW* SYMBOL_LIB_TABLE::FindRow( const wxString& aNickname )
210  throw( IO_ERROR )
211 {
212  SYMBOL_LIB_TABLE_ROW* row = dynamic_cast< SYMBOL_LIB_TABLE_ROW* >( findRow( aNickname ) );
213 
214  if( !row )
215  {
216  wxString msg = wxString::Format(
217  _( "sym-lib-table files contain no library with nickname '%s'" ),
218  GetChars( aNickname ) );
219 
220  THROW_IO_ERROR( msg );
221  }
222 
223  // We've been 'lazy' up until now, but it cannot be deferred any longer,
224  // instantiate a PLUGIN of the proper kind if it is not already in this
225  // SYMBOL_LIB_TABLE_ROW.
226  if( !row->plugin )
227  row->setPlugin( SCH_IO_MGR::FindPlugin( row->type ) );
228 
229  return row;
230 }
231 
232 
233 LIB_ALIAS* SYMBOL_LIB_TABLE::LoadSymbol( const wxString& aNickname, const wxString& aAliasName )
234 {
235  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
236  wxASSERT( (SCH_PLUGIN*) row->plugin );
237 
238  LIB_ALIAS* ret = row->plugin->LoadSymbol( row->GetFullURI( true ), aAliasName,
239  row->GetProperties() );
240 
241  // The library cannot know its own name, because it might have been renamed or moved.
242  // Therefore footprints cannot know their own library nickname when residing in
243  // a symbol library.
244  // Only at this API layer can we tell the symbol about its actual library nickname.
245  if( ret )
246  {
247  // remove "const"-ness, I really do want to set nickname without
248  // having to copy the LIB_ID and its two strings, twice each.
249  LIB_ID& id = (LIB_ID&) ret->GetPart()->GetLibId();
250 
251  // Catch any misbehaving plugin, which should be setting internal alias name properly:
252  wxASSERT( aAliasName == (wxString) id.GetLibItemName() );
253 
254  // and clearing nickname
255  wxASSERT( !id.GetLibNickname().size() );
256 
257  id.SetLibNickname( row->GetNickName() );
258  }
259 
260  return ret;
261 }
262 
263 
265  const LIB_PART* aSymbol, bool aOverwrite )
266 {
267  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
268  wxASSERT( (SCH_PLUGIN*) row->plugin );
269 
270  if( !aOverwrite )
271  {
272  // Try loading the footprint to see if it already exists, caller wants overwrite
273  // protection, which is atypical, not the default.
274 
275  wxString name = aSymbol->GetLibId().GetLibItemName();
276 
277  std::unique_ptr< LIB_ALIAS > symbol( row->plugin->LoadSymbol( row->GetFullURI( true ),
278  name,
279  row->GetProperties() ) );
280 
281  if( symbol.get() )
282  return SAVE_SKIPPED;
283  }
284 
285  row->plugin->SaveSymbol( row->GetFullURI( true ), aSymbol, row->GetProperties() );
286 
287  return SAVE_OK;
288 }
289 
290 
291 void SYMBOL_LIB_TABLE::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
292 {
293  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
294  wxASSERT( (SCH_PLUGIN*) row->plugin );
295  return row->plugin->DeleteSymbol( row->GetFullURI( true ), aSymbolName,
296  row->GetProperties() );
297 }
298 
299 
300 void SYMBOL_LIB_TABLE::DeleteAlias( const wxString& aNickname, const wxString& aAliasName )
301 {
302  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
303  wxASSERT( (SCH_PLUGIN*) row->plugin );
304  return row->plugin->DeleteAlias( row->GetFullURI( true ), aAliasName,
305  row->GetProperties() );
306 }
307 
308 
309 bool SYMBOL_LIB_TABLE::IsSymbolLibWritable( const wxString& aNickname )
310 {
311  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
312  wxASSERT( (SCH_PLUGIN*) row->plugin );
313  return row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) );
314 }
315 
316 
317 void SYMBOL_LIB_TABLE::DeleteSymbolLib( const wxString& aNickname )
318 {
319  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
320  wxASSERT( (SCH_PLUGIN*) row->plugin );
321  row->plugin->DeleteSymbolLib( row->GetFullURI( true ), row->GetProperties() );
322 }
323 
324 
325 void SYMBOL_LIB_TABLE::CreateSymbolLib( const wxString& aNickname )
326 {
327  const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
328  wxASSERT( (SCH_PLUGIN*) row->plugin );
329  row->plugin->CreateSymbolLib( row->GetFullURI( true ), row->GetProperties() );
330 }
331 
332 
334  throw( IO_ERROR, PARSE_ERROR, boost::interprocess::lock_exception )
335 {
336  wxString nickname = aLibId.GetLibNickname();
337  wxString name = aLibId.GetLibItemName();
338 
339  if( nickname.size() )
340  {
341  return LoadSymbol( nickname, name );
342  }
343 
344  // nickname is empty, sequentially search (alphabetically) all libs/nicks for first match:
345  else
346  {
347  std::vector<wxString> nicks = GetLogicalLibs();
348 
349  // Search each library going through libraries alphabetically.
350  for( unsigned i = 0; i < nicks.size(); ++i )
351  {
352  // FootprintLoad() returns NULL on not found, does not throw exception
353  // unless there's an IO_ERROR.
354  LIB_ALIAS* ret = LoadSymbol( nicks[i], name );
355 
356  if( ret )
357  return ret;
358  }
359 
360  return NULL;
361  }
362 }
363 
364 
366 {
367  return "KICAD_SYSTEM_SYMBOLS";
368 }
369 
370 
372  throw (IO_ERROR, PARSE_ERROR, boost::interprocess::lock_exception )
373 {
374  bool tableExists = true;
375  wxFileName fn = GetGlobalTableFileName();
376 
377  if( !fn.FileExists() )
378  {
379  tableExists = false;
380 
381  if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
382  {
383  THROW_IO_ERROR( wxString::Format( _( "Cannot create global library table path '%s'." ),
384  GetChars( fn.GetPath() ) ) );
385  }
386 
387  // Attempt to copy the default global file table from the KiCad
388  // template folder to the user's home configuration path.
389  wxString fileName = Kiface().KifaceSearch().FindValidPath( global_tbl_name );
390 
391  // The fallback is to create an empty global symbol table for the user to populate.
392  if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) )
393  {
394  SYMBOL_LIB_TABLE emptyTable;
395 
396  emptyTable.Save( fn.GetFullPath() );
397  }
398  }
399 
400  aTable.Load( fn.GetFullPath() );
401 
402  return tableExists;
403 }
404 
405 
407 {
408  wxFileName fn;
409 
410  fn.SetPath( GetKicadConfigPath() );
411  fn.SetName( global_tbl_name );
412 
413  return fn.GetFullPath();
414 }
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
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.
LIB_TABLE_ROWS::const_iterator LIB_TABLE_ROWS_CITER
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
static SYMBOL_LIB_TABLE m_globalLibTable
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:370
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
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.
static const wxChar global_tbl_name[]
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 ...
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:394
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:354
wxString GetKicadConfigPath()
Function GetKicadConfigPath.
Definition: common.cpp:317
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_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:378
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
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:402
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.
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.