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.

279 lines
7.8 KiB

  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 <sch_lib_table.h>
  25. #include <sch_lib_table_lexer.h>
  26. using namespace std;
  27. using namespace SCH;
  28. LIB_TABLE::LIB_TABLE( LIB_TABLE* aFallBackTable ) :
  29. fallBack( aFallBackTable )
  30. {
  31. /* not copying fall back, simply search aFallBackTable separately if "logicalName not found".
  32. if( aFallBackTable )
  33. {
  34. const ROWS& t = aFallBackTable->rows;
  35. for( ROWS_CITER it = t.begin(); it != t.end(); ++it )
  36. {
  37. // our rows are empty, expect no collisions here
  38. auto_ptr<ROW> row( new ROW( *it->second ) );
  39. row->owner = this;
  40. insert( row );
  41. }
  42. }
  43. */
  44. }
  45. void LIB_TABLE::Parse( SCH_LIB_TABLE_LEXER* in ) throw( IO_ERROR )
  46. {
  47. /* grammar:
  48. (lib_table
  49. (lib (logical "LOGICAL")(type "TYPE")(full_uri "FULL_URI")(options "OPTIONS"))
  50. (lib (logical "LOGICAL")(type "TYPE")(full_uri "FULL_URI")(options "OPTIONS"))
  51. (lib (logical "LOGICAL")(type "TYPE")(full_uri "FULL_URI")(options "OPTIONS"))
  52. )
  53. note: "(lib_table" has already been read in.
  54. */
  55. ELT_T tok;
  56. while( (tok = in->NextTok() ) != T_RIGHT && tok != T_EOF )
  57. {
  58. // (lib (logical "LOGICAL")(type "TYPE")(full_uri "FULL_URI")(options "OPTIONS"))
  59. if( tok != T_LEFT )
  60. in->Expecting( T_LEFT );
  61. if( ( tok = in->NextTok() ) != T_lib )
  62. in->Expecting( T_lib );
  63. in->NeedLEFT();
  64. if( ( tok = in->NextTok() ) != T_logical )
  65. in->Expecting( T_logical );
  66. in->NeedSYMBOLorNUMBER();
  67. auto_ptr<ROW> row( new ROW( this ) );
  68. row->SetLogicalName( in->CurText() );
  69. in->NeedRIGHT();
  70. in->NeedLEFT();
  71. if( ( tok = in->NextTok() ) != T_type )
  72. in->Expecting( T_type );
  73. in->NeedSYMBOLorNUMBER();
  74. // verify that type is one of: {dir, schematic, subversion, http}
  75. if( strcmp( in->CurText(), "dir" ) &&
  76. strcmp( in->CurText(), "schematic" ) &&
  77. strcmp( in->CurText(), "subversion" ) &&
  78. strcmp( in->CurText(), "http" ) )
  79. {
  80. in->Expecting( wxT( "dir|schematic|subversion|http" ) );
  81. }
  82. row->SetType( in->CurText() );
  83. in->NeedRIGHT();
  84. in->NeedLEFT();
  85. if( ( tok = in->NextTok() ) != T_full_uri )
  86. in->Expecting( T_full_uri );
  87. in->NeedSYMBOLorNUMBER();
  88. row->SetFullURI( in->CurText() );
  89. in->NeedRIGHT();
  90. in->NeedLEFT();
  91. if( ( tok = in->NextTok() ) != T_options )
  92. in->Expecting( T_options );
  93. in->NeedSYMBOLorNUMBER();
  94. row->SetOptions( in->CurText() );
  95. in->NeedRIGHT();
  96. in->NeedRIGHT(); // teriminate the (lib..)
  97. // all logicalNames within this table fragment must be unique, so we do not
  98. // replace. However a fallBack table can have a conflicting logicalName
  99. // and ours will supercede that one since in FindLib() we search this table
  100. // before any fall back.
  101. if( !InsertRow( row ) )
  102. {
  103. STRING msg;
  104. msg += '\'';
  105. msg += row->logicalName;
  106. msg += '\'';
  107. msg += " is a duplicate logical lib name";
  108. throw IO_ERROR( msg );
  109. }
  110. }
  111. return;
  112. }
  113. void LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const
  114. throw( IO_ERROR )
  115. {
  116. out->Print( nestLevel, "(lib_table\n" );
  117. for( ROWS_CITER it = rows.begin(); it != rows.end(); ++it )
  118. it->second->Format( out, nestLevel+1 );
  119. out->Print( nestLevel, ")\n" );
  120. }
  121. void LIB_TABLE::ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const
  122. throw( IO_ERROR )
  123. {
  124. out->Print( nestLevel, "(lib (logical \"%s\")(type \"%s\")(full_uri \"%s\")(options \"%s\"))\n",
  125. logicalName.c_str(), libType.c_str(), fullURI.c_str(), options.c_str() );
  126. }
  127. const LIB_TABLE::ROW* LIB_TABLE::FindRow( const STRING& aLogicalName )
  128. {
  129. // this function must be *super* fast, so therefore should not instantiate
  130. // anything which would require using the heap. This function is the reason
  131. // ptr_map<> was used instead of ptr_set<>, which would have required
  132. // instantiating a ROW just to find a ROW.
  133. LIB_TABLE* cur = this;
  134. ROWS_CITER it;
  135. do
  136. {
  137. it = cur->rows.find( aLogicalName );
  138. if( it != cur->rows.end() )
  139. {
  140. // reference: http://myitcorner.com/blog/?p=361
  141. return (const LIB_TABLE::ROW*) it->second; // found
  142. }
  143. // not found, search fall back table(s), if any
  144. } while( ( cur = cur->fallBack ) != 0 );
  145. return 0; // not found
  146. }
  147. bool LIB_TABLE::InsertRow( auto_ptr<ROW>& aRow, bool doReplace )
  148. {
  149. ROWS_ITER it = rows.find( aRow->logicalName );
  150. if( doReplace || it == rows.end() )
  151. {
  152. // be careful here, key is needed because aRow can be
  153. // release()ed before logicalName is captured.
  154. const STRING& key = aRow->logicalName;
  155. rows.insert( key, aRow );
  156. return true;
  157. }
  158. return false;
  159. }
  160. #if 1 && defined(DEBUG)
  161. // build this with a Debug CMAKE_BUILD_TYPE
  162. void LIB_TABLE::Test()
  163. {
  164. // the null string is not really a legal DSN token since any duplicated
  165. // double quote ("") is assumed to be a single double quote (").
  166. // To pass an empty string, we can pass " " to (options " ")
  167. SCH_LIB_TABLE_LEXER slr(
  168. "(lib_table \n"
  169. " (lib (logical meparts) (type dir) (full_uri /tmp/eeschema-lib) (options \" \"))\n"
  170. " (lib (logical old-project) (type schematic)(full_uri /tmp/old-schematic.sch) (options \" \"))\n"
  171. " (lib (logical www) (type http) (full_uri http://kicad.org/libs) (options \" \"))\n",
  172. wxT( "inline text" ) // source
  173. );
  174. try
  175. {
  176. // read the "( lib_table" pair of tokens
  177. slr.NextTok();
  178. slr.NextTok();
  179. // parse the rest of input to slr
  180. Parse( &slr );
  181. }
  182. catch( std::exception& ex )
  183. {
  184. printf( "std::exception\n" );
  185. }
  186. catch( IO_ERROR ioe )
  187. {
  188. printf( "exception: %s\n", (const char*) wxConvertWX2MB( ioe.errorText ) );
  189. }
  190. STRING_FORMATTER sf;
  191. Format( &sf, 0 );
  192. printf( "test 'Parse() <-> Format()' round tripping:\n" );
  193. printf( "%s", sf.GetString().c_str() );
  194. printf( "\ntest a lookup of 'www':\n" );
  195. const LIB_TABLE::ROW* www = FindRow( "www" );
  196. if( www )
  197. {
  198. // found, print it just to prove it.
  199. sf.Clear();
  200. www->Format( &sf, 1 );
  201. printf( "%s", sf.GetString().c_str() );
  202. }
  203. else
  204. printf( "not found\n" );
  205. }
  206. int main( int argc, char** argv )
  207. {
  208. LIB_TABLE lib_table;
  209. lib_table.Test();
  210. return 0;
  211. }
  212. #endif