KiCad PCB EDA Suite
lib_table_base.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) 2010-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2012-2017 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 2012-2017 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 
27 #include <wx/filename.h>
28 
29 #include <set>
30 
31 #include <fctsys.h>
32 #include <common.h>
33 #include <macros.h>
34 #include <kiface_i.h>
35 #include <lib_table_lexer.h>
36 #include <lib_table_base.h>
37 
38 
39 #define OPT_SEP '|'
40 
41 
42 using namespace LIB_TABLE_T;
43 
44 
46 {
47  return aRow.clone();
48 }
49 
50 
52 {
53  properties.reset( aProperties );
54 }
55 
56 
57 void LIB_TABLE_ROW::SetFullURI( const wxString& aFullURI )
58 {
59  uri_user = aFullURI;
60 
61 #if !FP_LATE_ENVVAR
62  uri_expanded = FP_LIB_TABLE::ExpandSubstitutions( aFullURI );
63 #endif
64 }
65 
66 
67 const wxString LIB_TABLE_ROW::GetFullURI( bool aSubstituted ) const
68 {
69  if( aSubstituted )
70  {
71 #if !FP_LATE_ENVVAR // early expansion
72  return uri_expanded;
73 
74 #else // late expansion
75  return LIB_TABLE::ExpandSubstitutions( uri_user );
76 #endif
77  }
78 
79  return uri_user;
80 }
81 
82 
83 void LIB_TABLE_ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const
84 {
85  // In Kicad, we save path and file names using the Unix notation (separator = '/')
86  // So ensure separator is always '/' is saved URI string
87  wxString uri = GetFullURI();
88  uri.Replace( '\\', '/' );
89 
90  out->Print( nestLevel, "(lib (name %s)(type %s)(uri %s)(options %s)(descr %s))\n",
91  out->Quotew( GetNickName() ).c_str(),
92  out->Quotew( GetType() ).c_str(),
93  out->Quotew( uri ).c_str(),
94  out->Quotew( GetOptions() ).c_str(),
95  out->Quotew( GetDescr() ).c_str()
96  );
97 }
98 
99 
100 void LIB_TABLE_ROW::Parse( std::unique_ptr< LIB_TABLE_ROW >& aRow, LIB_TABLE_LEXER* in )
101 {
102  /*
103  * (lib (name NICKNAME)(descr DESCRIPTION)(type TYPE)(full_uri FULL_URI)(options OPTIONS))
104  *
105  * Elements after (name) are order independent.
106  */
107 
108  T tok = in->NextTok();
109 
110  if( tok != T_lib )
111  in->Expecting( T_lib );
112 
113  // (name NICKNAME)
114  in->NeedLEFT();
115 
116  if( ( tok = in->NextTok() ) != T_name )
117  in->Expecting( T_name );
118 
119  in->NeedSYMBOLorNUMBER();
120 
121  aRow->SetNickName( in->FromUTF8() );
122 
123  in->NeedRIGHT();
124 
125  // After (name), remaining (lib) elements are order independent, and in
126  // some cases optional.
127  bool sawType = false;
128  bool sawOpts = false;
129  bool sawDesc = false;
130  bool sawUri = false;
131 
132  while( ( tok = in->NextTok() ) != T_RIGHT )
133  {
134  if( tok == T_EOF )
135  in->Unexpected( T_EOF );
136 
137  if( tok != T_LEFT )
138  in->Expecting( T_LEFT );
139 
140  tok = in->NeedSYMBOLorNUMBER();
141 
142  switch( tok )
143  {
144  case T_uri:
145  if( sawUri )
146  in->Duplicate( tok );
147  sawUri = true;
148  in->NeedSYMBOLorNUMBER();
149  // Saved path and file names use the Unix notation (separator = '/')
150  // However old files, and files edited by hands can use the woindows
151  // separator. Force the unix notation
152  // (It works on windows, and moreover, wxFileName and wxDir takes care to that
153  // on windows)
154  // moreover, URLs use the '/' as separator
155  {
156  wxString uri = in->FromUTF8();
157  uri.Replace( '\\', '/' );
158  aRow->SetFullURI( uri );
159  }
160  break;
161 
162  case T_type:
163  if( sawType )
164  in->Duplicate( tok );
165  sawType = true;
166  in->NeedSYMBOLorNUMBER();
167  aRow->SetType( in->FromUTF8() );
168  break;
169 
170  case T_options:
171  if( sawOpts )
172  in->Duplicate( tok );
173  sawOpts = true;
174  in->NeedSYMBOLorNUMBER();
175  aRow->SetOptions( in->FromUTF8() );
176  break;
177 
178  case T_descr:
179  if( sawDesc )
180  in->Duplicate( tok );
181  sawDesc = true;
182  in->NeedSYMBOLorNUMBER();
183  aRow->SetDescr( in->FromUTF8() );
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 
200 
202 {
203  return nickName == r.nickName
204  && uri_user == r.uri_user
205  && options == r.options
206  && description == r.description;
207 }
208 
209 
210 void LIB_TABLE_ROW::SetOptions( const wxString& aOptions )
211 {
212  options = aOptions;
213 
214  // set PROPERTIES* from options
215  setProperties( LIB_TABLE::ParseOptions( TO_UTF8( aOptions ) ) );
216 }
217 
218 
219 LIB_TABLE::LIB_TABLE( LIB_TABLE* aFallBackTable ) :
220  fallBack( aFallBackTable )
221 {
222  // not copying fall back, simply search aFallBackTable separately
223  // if "nickName not found".
224 }
225 
226 
228 {
229  // *fallBack is not owned here.
230 }
231 
232 
233 bool LIB_TABLE::IsEmpty( bool aIncludeFallback )
234 {
235  if( !aIncludeFallback || !fallBack )
236  return rows.empty();
237 
238  return rows.empty() && fallBack->IsEmpty( true );
239 }
240 
241 
242 const wxString LIB_TABLE::GetDescription( const wxString& aNickname )
243 {
244  // use "no exception" form of find row:
245  const LIB_TABLE_ROW* row = findRow( aNickname );
246 
247  if( row )
248  return row->GetDescr();
249  else
250  return wxEmptyString;
251 }
252 
253 
254 LIB_TABLE_ROW* LIB_TABLE::findRow( const wxString& aNickName ) const
255 {
256  LIB_TABLE* cur = (LIB_TABLE*) this;
257 
258  do
259  {
260  cur->ensureIndex();
261 
262  INDEX_CITER it = cur->nickIndex.find( aNickName );
263 
264  if( it != cur->nickIndex.end() )
265  {
266  return &cur->rows[it->second]; // found
267  }
268 
269  // not found, search fall back table(s), if any
270  } while( ( cur = cur->fallBack ) != 0 );
271 
272  return NULL; // not found
273 }
274 
275 
276 const LIB_TABLE_ROW* LIB_TABLE::FindRowByURI( const wxString& aURI )
277 {
278  LIB_TABLE* cur = this;
279 
280  do
281  {
282  cur->ensureIndex();
283 
284  for( unsigned i = 0; i < cur->rows.size(); i++ )
285  {
286  wxString uri = cur->rows[i].GetFullURI( true );
287 
288  if( wxFileName::GetPathSeparator() == wxChar( '\\' ) && uri.Find( wxChar( '/' ) ) >= 0 )
289  uri.Replace( "/", "\\" );
290 
291  if( (wxFileName::IsCaseSensitive() && uri == aURI)
292  || (!wxFileName::IsCaseSensitive() && uri.Upper() == aURI.Upper() ) )
293  {
294  return &cur->rows[i]; // found
295  }
296  }
297 
298  // not found, search fall back table(s), if any
299  } while( ( cur = cur->fallBack ) != 0 );
300 
301  return NULL; // not found
302 }
303 
304 
305 std::vector<wxString> LIB_TABLE::GetLogicalLibs()
306 {
307  // Only return unique logical library names. Use std::set::insert() to
308  // quietly reject any duplicates, which can happen when encountering a duplicate
309  // nickname from one of the fall back table(s).
310 
311  std::set< wxString > unique;
312  std::vector< wxString > ret;
313  const LIB_TABLE* cur = this;
314 
315  do
316  {
317  for( LIB_TABLE_ROWS_CITER it = cur->rows.begin(); it!=cur->rows.end(); ++it )
318  {
319  unique.insert( it->GetNickName() );
320  }
321 
322  } while( ( cur = cur->fallBack ) != 0 );
323 
324  ret.reserve( unique.size() );
325 
326  // return a sorted, unique set of nicknames in a std::vector<wxString> to caller
327  for( std::set< wxString >::const_iterator it = unique.begin(); it!=unique.end(); ++it )
328  {
329  ret.push_back( *it );
330  }
331 
332  return ret;
333 }
334 
335 
336 bool LIB_TABLE::InsertRow( LIB_TABLE_ROW* aRow, bool doReplace )
337 {
338  ensureIndex();
339 
340  INDEX_CITER it = nickIndex.find( aRow->GetNickName() );
341 
342  if( it == nickIndex.end() )
343  {
344  rows.push_back( aRow );
345  nickIndex.insert( INDEX_VALUE( aRow->GetNickName(), rows.size() - 1 ) );
346  return true;
347  }
348 
349  if( doReplace )
350  {
351  rows.replace( it->second, aRow );
352  return true;
353  }
354 
355  return false;
356 }
357 
358 
359 void LIB_TABLE::Load( const wxString& aFileName )
360  throw( IO_ERROR )
361 {
362  // It's OK if footprint library tables are missing.
363  if( wxFileName::IsFileReadable( aFileName ) )
364  {
365  FILE_LINE_READER reader( aFileName );
366  LIB_TABLE_LEXER lexer( &reader );
367 
368  Parse( &lexer );
369  }
370 }
371 
372 
373 void LIB_TABLE::Save( const wxString& aFileName ) const
374  throw( IO_ERROR, boost::interprocess::lock_exception )
375 {
376  FILE_OUTPUTFORMATTER sf( aFileName );
377  Format( &sf, 0 );
378 }
379 
380 
381 size_t LIB_TABLE::GetEnvVars( wxArrayString& aEnvVars ) const
382 {
383  const LIB_TABLE* cur = this;
384 
385  do
386  {
387  for( unsigned i = 0; i < cur->rows.size(); i++ )
388  {
389  wxString uri = cur->rows[i].GetFullURI( false );
390 
391  int start = uri.Find( "${" );
392 
393  if( start == wxNOT_FOUND )
394  continue;
395 
396  int end = uri.Find( '}' );
397 
398  if( end == wxNOT_FOUND || end < start+2 )
399  continue;
400 
401  wxString envVar = uri.Mid( start+2, end - (start+2) );
402 
403  if( aEnvVars.Index( envVar, false ) == wxNOT_FOUND )
404  aEnvVars.Add( envVar );
405  }
406 
407  // not found, search fall back table(s), if any
408  } while( ( cur = cur->fallBack ) != 0 );
409 
410  return aEnvVars.GetCount();
411 }
412 
413 
414 PROPERTIES* LIB_TABLE::ParseOptions( const std::string& aOptionsList )
415 {
416  if( aOptionsList.size() )
417  {
418  const char* cp = &aOptionsList[0];
419  const char* end = cp + aOptionsList.size();
420 
421  PROPERTIES props;
422  std::string pair;
423 
424  // Parse all name=value pairs
425  while( cp < end )
426  {
427  pair.clear();
428 
429  // Skip leading white space.
430  while( cp < end && isspace( *cp ) )
431  ++cp;
432 
433  // Find the end of pair/field
434  while( cp < end )
435  {
436  if( *cp == '\\' && cp + 1 < end && cp[1] == OPT_SEP )
437  {
438  ++cp; // skip the escape
439  pair += *cp++; // add the separator
440  }
441  else if( *cp == OPT_SEP )
442  {
443  ++cp; // skip the separator
444  break; // process the pair
445  }
446  else
447  pair += *cp++;
448  }
449 
450  // stash the pair
451  if( pair.size() )
452  {
453  // first equals sign separates 'name' and 'value'.
454  size_t eqNdx = pair.find( '=' );
455 
456  if( eqNdx != pair.npos )
457  {
458  std::string name = pair.substr( 0, eqNdx );
459  std::string value = pair.substr( eqNdx + 1 );
460  props[name] = value;
461  }
462  else
463  props[pair] = ""; // property is present, but with no value.
464  }
465  }
466 
467  if( props.size() )
468  return new PROPERTIES( props );
469  }
470 
471  return NULL;
472 }
473 
474 
476 {
477  UTF8 ret;
478 
479  if( aProperties )
480  {
481  for( PROPERTIES::const_iterator it = aProperties->begin(); it != aProperties->end(); ++it )
482  {
483  const std::string& name = it->first;
484 
485  const UTF8& value = it->second;
486 
487  if( ret.size() )
488  ret += OPT_SEP;
489 
490  ret += name;
491 
492  // the separation between name and value is '='
493  if( value.size() )
494  {
495  ret += '=';
496 
497  for( std::string::const_iterator si = value.begin(); si != value.end(); ++si )
498  {
499  // escape any separator in the value.
500  if( *si == OPT_SEP )
501  ret += '\\';
502 
503  ret += *si;
504  }
505  }
506  }
507  }
508 
509  return ret;
510 }
511 
512 
513 const wxString LIB_TABLE::ExpandSubstitutions( const wxString& aString )
514 {
515  return ExpandEnvVarSubstitutions( aString );
516 }
Class UTF8 is an 8 bit std::string that is assuredly encoded in UTF8, and supplies special conversion...
Definition: utf8.h:53
void ensureIndex()
Class LIB_TABLE_ROW.
std::vector< PROPERTY > PROPERTIES
Definition: specctra.h:184
void Format(OUTPUTFORMATTER *out, int nestLevel) const
Function Format.
size_t GetEnvVars(wxArrayString &aEnvVars) const
Search the paths all of the LIB_TABLE_ROWS of the LIB_TABLE and add all of the environment variable s...
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Function InsertRow.
LIB_TABLE_ROW * clone() const
T
enum T contains all this lexer's tokens.
static const wxString ExpandSubstitutions(const wxString &aString)
Function ExpandSubstitutions.
INDEX::const_iterator INDEX_CITER
void setProperties(PROPERTIES *aProperties)
void Unexpected(int aTok)
Function Unexpected throws an IO_ERROR exception with an input file specific error message...
Definition: dsnlexer.cpp:369
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
wxString FromUTF8()
Function FromUTF8 returns the current token text as a wxString, assuming that the input byte stream i...
Definition: dsnlexer.h:498
Class PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
LIB_TABLE * fallBack
const wxString GetFullURI(bool aSubstituted=false) const
Function GetFullURI.
static UTF8 FormatOptions(const PROPERTIES *aProperties)
Function FormatOptions.
This file contains miscellaneous commonly used macros and functions.
INDEX::value_type INDEX_VALUE
virtual ~LIB_TABLE()
wxString description
#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
void NeedLEFT()
Function NeedLEFT calls NextTok() and then verifies that the token read in is a DSN_LEFT.
Definition: dsnlexer.cpp:393
static PROPERTIES * ParseOptions(const std::string &aOptionsList)
Function ParseOptions.
Class FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:180
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Function ExpandEnvVarSubstitutions replaces any environment variable references with their values...
Definition: common.cpp:254
LIB_TABLE_ROW * new_clone(const LIB_TABLE_ROW &aRow)
Function new_clone.
LIB_TABLE_T::T NeedSYMBOLorNUMBER()
Function NeedSYMBOLorNUMBER calls NextTok() and then verifies that the token read in satisfies bool I...
const wxString GetDescription(const wxString &aNickname)
Function GetDescription.
const LIB_TABLE_ROW * FindRowByURI(const wxString &aURI)
Function FindRowByURI.
bool operator==(const LIB_TABLE_ROW &r) const
void Save(const wxString &aFileName) const
Function Save.
std::string Quotew(const wxString &aWrapee)
Definition: richio.cpp:486
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.
const wxString & GetDescr() const
Function GetDescr.
const wxString & GetNickName() const
Function GetNickName.
void SetFullURI(const wxString &aFullURI)
Function SetFullURI.
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
wxString options
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
The common library.
const char * name
static void Parse(std::unique_ptr< LIB_TABLE_ROW > &aRow, LIB_TABLE_LEXER *in)
Class FILE_OUTPUTFORMATTER may be used for text file output.
Definition: richio.h:492
LIB_TABLE(LIB_TABLE *aFallBackTable=NULL)
Constructor LIB_TABLE builds a library table by pre-pending this table fragment in front of aFallBack...
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.
void SetOptions(const wxString &aOptions)
Function SetOptions.
wxString nickName
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:408
wxString uri_user
what user entered from UI or loaded from disk
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
INDEX nickIndex
this particular key is the nickName within each row.
bool IsEmpty(bool aIncludeFallback=true)
Function IsEmpty.
std::vector< wxString > GetLogicalLibs()
Function GetLogicalLibs.
#define OPT_SEP
options separator character
C++ does not put enum values in separate namespaces unless the enum itself is in a separate namespace...
Class LIB_TABLE.