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.

543 lines
16 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2016-2019 Wayne Stambaugh <stambaughw@gmail.com>
  5. * Copyright (C) 2016-2019 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 <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. 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 );
  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 );
  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 )
  228. {
  229. SYMBOL_LIB_TABLE_ROW* row = dynamic_cast< SYMBOL_LIB_TABLE_ROW* >( findRow( aNickname ) );
  230. if( !row )
  231. return nullptr;
  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. return row;
  238. }
  239. void SYMBOL_LIB_TABLE::LoadSymbolLib( std::vector<LIB_PART*>& aSymbolList,
  240. const wxString& aNickname, bool aPowerSymbolsOnly )
  241. {
  242. SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
  243. wxCHECK( row && row->plugin, /* void */ );
  244. wxString options = row->GetOptions();
  245. if( aPowerSymbolsOnly )
  246. row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
  247. row->SetLoaded( false );
  248. row->plugin->EnumerateSymbolLib( aSymbolList, row->GetFullURI( true ), row->GetProperties() );
  249. row->SetLoaded( true );
  250. if( aPowerSymbolsOnly )
  251. row->SetOptions( options );
  252. // The library cannot know its own name, because it might have been renamed or moved.
  253. // Therefore footprints cannot know their own library nickname when residing in
  254. // a symbol library.
  255. // Only at this API layer can we tell the symbol about its actual library nickname.
  256. for( LIB_PART* part : aSymbolList )
  257. {
  258. LIB_ID id = part->GetLibId();
  259. id.SetLibNickname( row->GetNickName() );
  260. part->SetLibId( id );
  261. }
  262. }
  263. LIB_PART* SYMBOL_LIB_TABLE::LoadSymbol( const wxString& aNickname, const wxString& aSymbolName )
  264. {
  265. SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
  266. if( !row || !row->plugin )
  267. return nullptr;
  268. LIB_PART* part = row->plugin->LoadSymbol( row->GetFullURI( true ), aSymbolName,
  269. row->GetProperties() );
  270. if( part == nullptr )
  271. return part;
  272. // The library cannot know its own name, because it might have been renamed or moved.
  273. // Therefore footprints cannot know their own library nickname when residing in
  274. // a symbol library.
  275. // Only at this API layer can we tell the symbol about its actual library nickname.
  276. if( part )
  277. {
  278. LIB_ID id = part->GetLibId();
  279. id.SetLibNickname( row->GetNickName() );
  280. part->SetLibId( id );
  281. }
  282. return part;
  283. }
  284. SYMBOL_LIB_TABLE::SAVE_T SYMBOL_LIB_TABLE::SaveSymbol( const wxString& aNickname,
  285. const LIB_PART* aSymbol, bool aOverwrite )
  286. {
  287. const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
  288. wxCHECK( row && row->plugin, SAVE_SKIPPED );
  289. if( !aOverwrite )
  290. {
  291. // Try loading the footprint to see if it already exists, caller wants overwrite
  292. // protection, which is atypical, not the default.
  293. wxString name = aSymbol->GetLibId().GetLibItemName();
  294. std::unique_ptr< LIB_PART > symbol( row->plugin->LoadSymbol( row->GetFullURI( true ),
  295. name,
  296. row->GetProperties() ) );
  297. if( symbol.get() )
  298. return SAVE_SKIPPED;
  299. }
  300. row->plugin->SaveSymbol( row->GetFullURI( true ), aSymbol, row->GetProperties() );
  301. return SAVE_OK;
  302. }
  303. void SYMBOL_LIB_TABLE::DeleteSymbol( const wxString& aNickname, const wxString& aSymbolName )
  304. {
  305. const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
  306. wxCHECK( row && row->plugin, /* void */ );
  307. return row->plugin->DeleteSymbol( row->GetFullURI( true ), aSymbolName,
  308. row->GetProperties() );
  309. }
  310. bool SYMBOL_LIB_TABLE::IsSymbolLibWritable( const wxString& aNickname )
  311. {
  312. const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
  313. wxCHECK( row && row->plugin, false );
  314. return row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) );
  315. }
  316. bool SYMBOL_LIB_TABLE::IsSymbolLibLoaded( const wxString& aNickname )
  317. {
  318. const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
  319. wxCHECK( row, false );
  320. return row->GetIsLoaded();
  321. }
  322. void SYMBOL_LIB_TABLE::DeleteSymbolLib( const wxString& aNickname )
  323. {
  324. const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
  325. wxCHECK( row && row->plugin, /* void */ );
  326. row->plugin->DeleteSymbolLib( row->GetFullURI( true ), row->GetProperties() );
  327. }
  328. void SYMBOL_LIB_TABLE::CreateSymbolLib( const wxString& aNickname )
  329. {
  330. const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
  331. wxCHECK( row && row->plugin, /* void */ );
  332. row->plugin->CreateSymbolLib( row->GetFullURI( true ), row->GetProperties() );
  333. }
  334. LIB_PART* SYMBOL_LIB_TABLE::LoadSymbolWithOptionalNickname( const LIB_ID& aLibId )
  335. {
  336. wxString nickname = aLibId.GetLibNickname();
  337. wxString name = aLibId.GetLibItemName();
  338. if( nickname.size() )
  339. {
  340. return LoadSymbol( nickname, name );
  341. }
  342. // nickname is empty, sequentially search (alphabetically) all libs/nicks for first match:
  343. else
  344. {
  345. std::vector<wxString> nicks = GetLogicalLibs();
  346. // Search each library going through libraries alphabetically.
  347. for( unsigned i = 0; i < nicks.size(); ++i )
  348. {
  349. // FootprintLoad() returns NULL on not found, does not throw exception
  350. // unless there's an IO_ERROR.
  351. LIB_PART* ret = LoadSymbol( nicks[i], name );
  352. if( ret )
  353. return ret;
  354. }
  355. return nullptr;
  356. }
  357. }
  358. const wxString SYMBOL_LIB_TABLE::GlobalPathEnvVariableName()
  359. {
  360. return "KICAD6_SYMBOL_DIR";
  361. }
  362. bool SYMBOL_LIB_TABLE::LoadGlobalTable( SYMBOL_LIB_TABLE& aTable )
  363. {
  364. bool tableExists = true;
  365. wxFileName fn = GetGlobalTableFileName();
  366. if( !fn.FileExists() )
  367. {
  368. tableExists = false;
  369. if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
  370. {
  371. THROW_IO_ERROR( wxString::Format(
  372. _( "Cannot create global library table path \"%s\"." ), fn.GetPath() ) );
  373. }
  374. // Attempt to copy the default global file table from the KiCad
  375. // template folder to the user's home configuration path.
  376. SEARCH_STACK ss;
  377. SystemDirsAppend( &ss );
  378. wxString templatePath =
  379. Pgm().GetLocalEnvVariables().at( wxT( "KICAD6_TEMPLATE_DIR" ) ).GetValue();
  380. if( !templatePath.IsEmpty() )
  381. ss.AddPaths( templatePath, 0 );
  382. wxString fileName = ss.FindValidPath( global_tbl_name );
  383. // The fallback is to create an empty global symbol table for the user to populate.
  384. if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) )
  385. {
  386. SYMBOL_LIB_TABLE emptyTable;
  387. emptyTable.Save( fn.GetFullPath() );
  388. }
  389. }
  390. aTable.Load( fn.GetFullPath() );
  391. return tableExists;
  392. }
  393. wxString SYMBOL_LIB_TABLE::GetGlobalTableFileName()
  394. {
  395. wxFileName fn;
  396. fn.SetPath( SETTINGS_MANAGER::GetUserSettingsPath() );
  397. fn.SetName( global_tbl_name );
  398. return fn.GetFullPath();
  399. }
  400. const wxString& SYMBOL_LIB_TABLE::GetSymbolLibTableFileName()
  401. {
  402. return global_tbl_name;
  403. }