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.

548 lines
16 KiB

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