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.

341 lines
9.2 KiB

15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2010-2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2010 KiCad Developers, see change_log.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 <set>
  25. #include <assert.h>
  26. #include <sch_lib_table_lexer.h>
  27. #include <sch_lpid.h>
  28. #include <sch_lib_table.h>
  29. #include <sch_dir_lib_source.h>
  30. using namespace SCH;
  31. using namespace LT; // tokens, enum T for LIB_TABLE
  32. LIB_TABLE::LIB_TABLE( LIB_TABLE* aFallBackTable ) :
  33. fallBack( aFallBackTable )
  34. {
  35. // not copying fall back, simply search aFallBackTable separately
  36. // if "logicalName not found".
  37. }
  38. void LIB_TABLE::Parse( SCH_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR )
  39. {
  40. /* grammar:
  41. (lib_table
  42. (lib (logical LOGICAL)(type TYPE)(full_uri FULL_URI)(options OPTIONS))
  43. (lib (logical LOGICAL)(type TYPE)(full_uri FULL_URI)(options OPTIONS))
  44. (lib (logical LOGICAL)(type TYPE)(full_uri FULL_URI)(options OPTIONS))
  45. )
  46. note: "(lib_table" has already been read in.
  47. */
  48. T tok;
  49. while( ( tok = in->NextTok() ) != T_RIGHT )
  50. {
  51. // (lib (logical "LOGICAL")(type "TYPE")(full_uri "FULL_URI")(options "OPTIONS"))
  52. if( tok == T_EOF )
  53. in->Expecting( T_RIGHT );
  54. if( tok != T_LEFT )
  55. in->Expecting( T_LEFT );
  56. if( ( tok = in->NextTok() ) != T_lib )
  57. in->Expecting( T_lib );
  58. in->NeedLEFT();
  59. if( ( tok = in->NextTok() ) != T_logical )
  60. in->Expecting( T_logical );
  61. in->NeedSYMBOLorNUMBER();
  62. std::auto_ptr<ROW> row( new ROW( this ) );
  63. row->SetLogicalName( in->CurText() );
  64. in->NeedRIGHT();
  65. in->NeedLEFT();
  66. if( ( tok = in->NextTok() ) != T_type )
  67. in->Expecting( T_type );
  68. in->NeedSYMBOLorNUMBER();
  69. // verify that type is one of: {dir, schematic, subversion, http}
  70. if( strcmp( in->CurText(), "dir" ) &&
  71. strcmp( in->CurText(), "schematic" ) &&
  72. strcmp( in->CurText(), "subversion" ) &&
  73. strcmp( in->CurText(), "http" ) )
  74. {
  75. in->Expecting( "dir|schematic|subversion|http" );
  76. }
  77. row->SetType( in->CurText() );
  78. in->NeedRIGHT();
  79. in->NeedLEFT();
  80. if( ( tok = in->NextTok() ) != T_full_uri )
  81. in->Expecting( T_full_uri );
  82. in->NeedSYMBOLorNUMBER();
  83. row->SetFullURI( in->CurText() );
  84. in->NeedRIGHT();
  85. in->NeedLEFT();
  86. if( ( tok = in->NextTok() ) != T_options )
  87. in->Expecting( T_options );
  88. in->NeedSYMBOLorNUMBER();
  89. row->SetOptions( in->CurText() );
  90. in->NeedRIGHT();
  91. in->NeedRIGHT(); // terminate the (lib..)
  92. // all logicalNames within this table fragment must be unique, so we do not
  93. // use doReplace in InsertRow(). However a fallBack table can have a
  94. // conflicting logicalName and ours will supercede that one since in
  95. // FindLib() we search this table before any fall back.
  96. if( !InsertRow( row ) )
  97. {
  98. STRING msg;
  99. msg += '\'';
  100. msg += row->logicalName;
  101. msg += '\'';
  102. msg += " is a duplicate logical lib name";
  103. THROW_IO_ERROR( msg );
  104. }
  105. }
  106. }
  107. void LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const
  108. throw( IO_ERROR )
  109. {
  110. out->Print( nestLevel, "(lib_table\n" );
  111. for( ROWS_CITER it = rows.begin(); it != rows.end(); ++it )
  112. it->second->Format( out, nestLevel+1 );
  113. out->Print( nestLevel, ")\n" );
  114. }
  115. void LIB_TABLE::ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const
  116. throw( IO_ERROR )
  117. {
  118. out->Print( nestLevel, "(lib (logical %s)(type %s)(full_uri %s)(options %s))\n",
  119. out->Quotes( logicalName ).c_str(),
  120. out->Quotes( libType ).c_str(),
  121. out->Quotes( fullURI ).c_str(),
  122. out->Quotes( options ).c_str()
  123. );
  124. }
  125. STRINGS LIB_TABLE::GetLogicalLibs()
  126. {
  127. // Only return unique logical library names. Use std::set::insert() to
  128. // quietly reject any duplicates, which can happen when encountering a duplicate
  129. // logical lib name from one of the fall back table(s).
  130. std::set<STRING> unique;
  131. STRINGS ret;
  132. const LIB_TABLE* cur = this;
  133. do
  134. {
  135. for( ROWS_CITER it = cur->rows.begin(); it!=cur->rows.end(); ++it )
  136. {
  137. unique.insert( it->second->logicalName );
  138. }
  139. } while( ( cur = cur->fallBack ) != 0 );
  140. // return a sorted, unique set of logical lib name STRINGS to caller
  141. for( std::set<STRING>::const_iterator it = unique.begin(); it!=unique.end(); ++it )
  142. ret.push_back( *it );
  143. return ret;
  144. }
  145. PART* LIB_TABLE::LookupPart( const LPID& aLPID, LIB* aLocalLib )
  146. throw( IO_ERROR )
  147. {
  148. LIB* lib = lookupLib( aLPID, aLocalLib );
  149. return lib->LookupPart( aLPID, this );
  150. }
  151. LIB* LIB_TABLE::lookupLib( const LPID& aLPID, LIB* aFallBackLib )
  152. throw( IO_ERROR )
  153. {
  154. if( aLPID.GetLogicalLib().size() )
  155. {
  156. ROW* row = FindRow( aLPID.GetLogicalLib() );
  157. if( !row )
  158. {
  159. STRING msg = "lib table contains no logical lib '";
  160. msg += aLPID.GetLogicalLib();
  161. msg += '\'';
  162. THROW_IO_ERROR( msg );
  163. }
  164. if( !row->lib )
  165. {
  166. loadLib( row );
  167. }
  168. assert( row->lib ); // fix loadLib() to throw if cannot load
  169. return row->lib;
  170. }
  171. if( aFallBackLib )
  172. {
  173. return aFallBackLib;
  174. }
  175. STRING msg = "lookupLib() requires logicalLibName or a fallback lib";
  176. THROW_IO_ERROR( msg );
  177. }
  178. void LIB_TABLE::loadLib( ROW* aRow ) throw( IO_ERROR )
  179. {
  180. assert( !aRow->lib ); // caller should know better.
  181. const STRING& libType = aRow->GetType();
  182. if( !libType.compare( "dir" ) )
  183. {
  184. // autor_ptr wrap source while we create sink, in case sink throws.
  185. std::auto_ptr<LIB_SOURCE> source(
  186. new DIR_LIB_SOURCE(
  187. aRow->GetFullURI(),
  188. aRow->GetOptions() ) );
  189. /* @todo load LIB_SINK
  190. std::auto_ptr<LIB_SINK> sink(
  191. new DIR_LIB_SINK(
  192. aRow->GetFullURI(),
  193. aRow->GetOptions() ) );
  194. */
  195. // LIB::LIB( const STRING& aLogicalLibrary, LIB_SOURCE* aSource, LIB_SINK* aSink = NULL );
  196. aRow->lib = new LIB( aRow->GetLogicalName(), source.release(), NULL );
  197. }
  198. /*
  199. else if( !libType.compare( "schematic" ) )
  200. {
  201. // @todo code and load SCHEMATIC_LIB_SOURCE
  202. }
  203. else if( !libType.compare( "subversion" ) )
  204. {
  205. // @todo code and load SVN_LIB_SOURCE
  206. }
  207. else if( !libType.compare( "http" ) )
  208. {
  209. // @todo code and load HTTP_LIB_SOURCE
  210. }
  211. */
  212. else
  213. {
  214. STRING msg = "cannot load unknown libType: '";
  215. msg += libType;
  216. msg += '\'';
  217. THROW_IO_ERROR( msg );
  218. }
  219. }
  220. LIB_TABLE::ROW* LIB_TABLE::FindRow( const STRING& aLogicalName ) const
  221. {
  222. // this function must be *super* fast, so therefore should not instantiate
  223. // anything which would require using the heap. This function is the reason
  224. // ptr_map<> was used instead of ptr_set<>, which would have required
  225. // instantiating a ROW just to find a ROW.
  226. const LIB_TABLE* cur = this;
  227. do
  228. {
  229. ROWS_CITER it = cur->rows.find( aLogicalName );
  230. if( it != cur->rows.end() )
  231. {
  232. // reference: http://myitcorner.com/blog/?p=361
  233. return (LIB_TABLE::ROW*) it->second; // found
  234. }
  235. // not found, search fall back table(s), if any
  236. } while( ( cur = cur->fallBack ) != 0 );
  237. return 0; // not found
  238. }
  239. bool LIB_TABLE::InsertRow( std::auto_ptr<ROW>& aRow, bool doReplace )
  240. {
  241. // this does not need to be super fast.
  242. ROWS_CITER it = rows.find( aRow->logicalName );
  243. if( it == rows.end() )
  244. {
  245. // be careful here, key is needed because aRow can be
  246. // release()ed before logicalName is captured.
  247. const STRING& key = aRow->logicalName;
  248. rows.insert( key, aRow );
  249. return true;
  250. }
  251. if( doReplace )
  252. {
  253. rows.erase( aRow->logicalName );
  254. // be careful here, key is needed because aRow can be
  255. // release()ed before logicalName is captured.
  256. const STRING& key = aRow->logicalName;
  257. rows.insert( key, aRow );
  258. return true;
  259. }
  260. return false;
  261. }