You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

523 lines
16 KiB

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