KiCad PCB EDA Suite
pcb_parser.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 CERN
5  * Copyright (C) 2012-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 
30 #include <errno.h>
31 #include <common.h>
32 #include <confirm.h>
33 #include <macros.h>
34 #include <trigo.h>
35 #include <class_title_block.h>
36 
37 #include <class_board.h>
38 #include <class_dimension.h>
39 #include <class_drawsegment.h>
40 #include <class_edge_mod.h>
41 #include <class_mire.h>
42 #include <class_module.h>
43 #include <class_netclass.h>
44 #include <class_pad.h>
45 #include <class_track.h>
46 #include <class_zone.h>
47 #include <kicad_plugin.h>
48 #include <pcb_plot_params_parser.h>
49 #include <pcb_plot_params.h>
50 #include <zones.h>
51 #include <pcb_parser.h>
52 
53 using namespace PCB_KEYS_T;
54 
55 
57 {
58  m_tooRecent = false;
59  m_requiredVersion = 0;
60  m_layerIndices.clear();
61  m_layerMasks.clear();
62 
63  // Add untranslated default (i.e. english) layernames.
64  // Some may be overridden later if parsing a board rather than a footprint.
65  // The english name will survive if parsing only a footprint.
66  for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
67  {
68  std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) );
69 
70  m_layerIndices[ untranslated ] = PCB_LAYER_ID( layer );
71  m_layerMasks[ untranslated ] = LSET( PCB_LAYER_ID( layer ) );
72  }
73 
74  m_layerMasks[ "*.Cu" ] = LSET::AllCuMask();
75  m_layerMasks[ "F&B.Cu" ] = LSET( 2, F_Cu, B_Cu );
76  m_layerMasks[ "*.Adhes" ] = LSET( 2, B_Adhes, F_Adhes );
77  m_layerMasks[ "*.Paste" ] = LSET( 2, B_Paste, F_Paste );
78  m_layerMasks[ "*.Mask" ] = LSET( 2, B_Mask, F_Mask );
79  m_layerMasks[ "*.SilkS" ] = LSET( 2, B_SilkS, F_SilkS );
80  m_layerMasks[ "*.Fab" ] = LSET( 2, B_Fab, F_Fab );
81  m_layerMasks[ "*.CrtYd" ] = LSET( 2, B_CrtYd, F_CrtYd );
82 
83  // This is for the first pretty & *.kicad_pcb formats, which had
84  // Inner1_Cu - Inner14_Cu with the numbering sequence
85  // reversed from the subsequent format's In1_Cu - In30_Cu numbering scheme.
86  // The newer format brought in an additional 16 Cu layers and flipped the cu stack but
87  // kept the gap between one of the outside layers and the last cu internal.
88 
89  for( int i=1; i<=14; ++i )
90  {
91  std::string key = StrPrintf( "Inner%d.Cu", i );
92 
93  m_layerMasks[ key ] = LSET( PCB_LAYER_ID( In15_Cu - i ) );
94  }
95 
96 #if defined(DEBUG) && 0
97  printf( "m_layerMasks:\n" );
98  for( LSET_MAP::const_iterator it = m_layerMasks.begin(); it != m_layerMasks.end(); ++it )
99  {
100  printf( " [%s] == 0x%s\n", it->first.c_str(), it->second.FmtHex().c_str() );
101  }
102 
103  printf( "m_layerIndices:\n" );
104  for( LAYER_ID_MAP::const_iterator it = m_layerIndices.begin(); it != m_layerIndices.end(); ++it )
105  {
106  printf( " [%s] == %d\n", it->first.c_str(), it->second );
107  }
108 #endif
109 
110 }
111 
112 
113 void PCB_PARSER::pushValueIntoMap( int aIndex, int aValue )
114 {
115  // Add aValue in netcode mapping (m_netCodes) at index aNetCode
116  // ensure there is room in m_netCodes for that, and add room if needed.
117 
118  if( (int)m_netCodes.size() <= aIndex )
119  m_netCodes.resize( aIndex+1 );
120 
121  m_netCodes[aIndex] = aValue;
122 }
123 
125 {
126  char* tmp;
127 
128  errno = 0;
129 
130  double fval = strtod( CurText(), &tmp );
131 
132  if( errno )
133  {
134  wxString error;
135  error.Printf( _( "invalid floating point number in\nfile: <%s>\nline: %d\noffset: %d" ),
136  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
137 
138  THROW_IO_ERROR( error );
139  }
140 
141  if( CurText() == tmp )
142  {
143  wxString error;
144  error.Printf( _( "missing floating point number in\nfile: <%s>\nline: %d\noffset: %d" ),
145  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
146 
147  THROW_IO_ERROR( error );
148  }
149 
150  return fval;
151 }
152 
153 
155 {
156  T token = NextTok();
157 
158  if( token == T_yes )
159  return true;
160  else if( token == T_no )
161  return false;
162  else
163  Expecting( "yes or no" );
164 
165  return false;
166 }
167 
168 
170 {
171  if( NextTok() != T_version )
172  Expecting( GetTokenText( T_version ) );
173 
174  int pcb_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
175 
176  NeedRIGHT();
177 
178  return pcb_version;
179 }
180 
181 
183 {
184  int year, month, day;
185 
186  year = m_requiredVersion / 10000;
187  month = ( m_requiredVersion / 100 ) - ( year * 100 );
188  day = m_requiredVersion - ( year * 10000 ) - ( month * 100 );
189 
190  // wx throws an assertion, not a catchable exception, when the date is invalid.
191  // User input shouldn't give wx asserts, so check manually and throw a proper
192  // error instead
193  if( day <= 0 || month <= 0 || month > 12 ||
194  day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) )
195  {
196  wxString err;
197  err.Printf( _( "cannot interpret date code %d" ), m_requiredVersion );
198  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
199  }
200 
201  wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 );
202  return date.FormatDate();
203 }
204 
205 
207 {
208  if( CurTok() != T_LEFT )
209  NeedLEFT();
210 
211  wxPoint pt;
212  T token = NextTok();
213 
214  if( token != T_xy )
215  Expecting( T_xy );
216 
217  pt.x = parseBoardUnits( "X coordinate" );
218  pt.y = parseBoardUnits( "Y coordinate" );
219 
220  NeedRIGHT();
221 
222  return pt;
223 }
224 
225 
226 void PCB_PARSER::parseXY( int* aX, int* aY ) throw( PARSE_ERROR, IO_ERROR )
227 {
228  wxPoint pt = parseXY();
229 
230  if( aX )
231  *aX = pt.x;
232 
233  if( aY )
234  *aY = pt.y;
235 }
236 
237 
239 {
240  wxCHECK_RET( CurTok() == T_effects,
241  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) );
242 
243  T token;
244 
245  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
246  {
247  if( token == T_LEFT )
248  token = NextTok();
249 
250  switch( token )
251  {
252  case T_font:
253  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
254  {
255  if( token == T_LEFT )
256  continue;
257 
258  switch( token )
259  {
260  case T_size:
261  {
262  wxSize sz;
263  sz.SetHeight( parseBoardUnits( "text height" ) );
264  sz.SetWidth( parseBoardUnits( "text width" ) );
265  aText->SetTextSize( sz );
266  NeedRIGHT();
267  }
268  break;
269 
270  case T_thickness:
271  aText->SetThickness( parseBoardUnits( "text thickness" ) );
272  NeedRIGHT();
273  break;
274 
275  case T_bold:
276  aText->SetBold( true );
277  break;
278 
279  case T_italic:
280  aText->SetItalic( true );
281  break;
282 
283  default:
284  Expecting( "size, bold, or italic" );
285  }
286  }
287  break;
288 
289  case T_justify:
290  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
291  {
292  if( token == T_LEFT )
293  continue;
294 
295  switch( token )
296  {
297  case T_left:
298  aText->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
299  break;
300 
301  case T_right:
302  aText->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
303  break;
304 
305  case T_top:
306  aText->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
307  break;
308 
309  case T_bottom:
310  aText->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
311  break;
312 
313  case T_mirror:
314  aText->SetMirrored( true );
315  break;
316 
317  default:
318  Expecting( "left, right, top, bottom, or mirror" );
319  }
320 
321  }
322  break;
323 
324  case T_hide:
325  aText->SetVisible( false );
326  break;
327 
328  default:
329  Expecting( "font, justify, or hide" );
330  }
331  }
332 }
333 
334 
336 {
337  wxCHECK_MSG( CurTok() == T_model, NULL,
338  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as S3D_INFO." ) );
339 
340  T token;
341 
342  S3D_INFO* n3D = new S3D_INFO;
343  NeedSYMBOLorNUMBER();
344  n3D->m_Filename = FromUTF8();
345 
346  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
347  {
348  if( token != T_LEFT )
349  Expecting( T_LEFT );
350 
351  token = NextTok();
352 
353  switch( token )
354  {
355  case T_at:
356  NeedLEFT();
357  token = NextTok();
358 
359  if( token != T_xyz )
360  Expecting( T_xyz );
361 
362  n3D->m_Offset.x = parseDouble( "x value" );
363  n3D->m_Offset.y = parseDouble( "y value" );
364  n3D->m_Offset.z = parseDouble( "z value" );
365  NeedRIGHT();
366  break;
367 
368  case T_scale:
369  NeedLEFT();
370  token = NextTok();
371 
372  if( token != T_xyz )
373  Expecting( T_xyz );
374 
375  n3D->m_Scale.x = parseDouble( "x value" );
376  n3D->m_Scale.y = parseDouble( "y value" );
377  n3D->m_Scale.z = parseDouble( "z value" );
378  NeedRIGHT();
379  break;
380 
381  case T_rotate:
382  NeedLEFT();
383  token = NextTok();
384 
385  if( token != T_xyz )
386  Expecting( T_xyz );
387 
388  n3D->m_Rotation.x = parseDouble( "x value" );
389  n3D->m_Rotation.y = parseDouble( "y value" );
390  n3D->m_Rotation.z = parseDouble( "z value" );
391  NeedRIGHT();
392  break;
393 
394  default:
395  Expecting( "at, scale, or rotate" );
396  }
397 
398  NeedRIGHT();
399  }
400 
401  return n3D;
402 }
403 
404 
406 {
407  T token;
408  BOARD_ITEM* item;
409  LOCALE_IO toggle;
410 
411  // MODULEs can be prefixed with an initial block of single line comments and these
412  // are kept for Format() so they round trip in s-expression form. BOARDs might
413  // eventually do the same, but currently do not.
414  std::unique_ptr<wxArrayString> initial_comments( ReadCommentLines() );
415 
416  token = CurTok();
417 
418  if( token != T_LEFT )
419  Expecting( T_LEFT );
420 
421  switch( NextTok() )
422  {
423  case T_kicad_pcb:
424  if( m_board == NULL )
425  m_board = new BOARD();
426 
427  item = (BOARD_ITEM*) parseBOARD();
428  break;
429 
430  case T_module:
431  item = (BOARD_ITEM*) parseMODULE( initial_comments.release() );
432  break;
433 
434  default:
435  wxString err;
436  err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) );
437  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
438  }
439 
440  return item;
441 }
442 
443 
445 {
446  try
447  {
448  return parseBOARD_unchecked();
449  }
450  catch( const PARSE_ERROR& parse_error )
451  {
452  if( m_tooRecent )
453  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
454  else
455  throw;
456  }
457 }
458 
459 
461 {
462  T token;
463 
464  parseHeader();
465 
466  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
467  {
468  if( token != T_LEFT )
469  Expecting( T_LEFT );
470 
471  token = NextTok();
472 
473  switch( token )
474  {
475  case T_general:
476  parseGeneralSection();
477  break;
478 
479  case T_page:
480  parsePAGE_INFO();
481  break;
482 
483  case T_title_block:
484  parseTITLE_BLOCK();
485  break;
486 
487  case T_layers:
488  parseLayers();
489  break;
490 
491  case T_setup:
492  parseSetup();
493  break;
494 
495  case T_net:
496  parseNETINFO_ITEM();
497  break;
498 
499  case T_net_class:
500  parseNETCLASS();
501  break;
502 
503  case T_gr_arc:
504  case T_gr_circle:
505  case T_gr_curve:
506  case T_gr_line:
507  case T_gr_poly:
508  m_board->Add( parseDRAWSEGMENT(), ADD_APPEND );
509  break;
510 
511  case T_gr_text:
512  m_board->Add( parseTEXTE_PCB(), ADD_APPEND );
513  break;
514 
515  case T_dimension:
516  m_board->Add( parseDIMENSION(), ADD_APPEND );
517  break;
518 
519  case T_module:
520  m_board->Add( parseMODULE(), ADD_APPEND );
521  break;
522 
523  case T_segment:
524  m_board->Add( parseTRACK(), ADD_APPEND );
525  break;
526 
527  case T_via:
528  m_board->Add( parseVIA(), ADD_APPEND );
529  break;
530 
531  case T_zone:
532  m_board->Add( parseZONE_CONTAINER(), ADD_APPEND );
533  break;
534 
535  case T_target:
536  m_board->Add( parsePCB_TARGET(), ADD_APPEND );
537  break;
538 
539  default:
540  wxString err;
541  err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) );
542  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
543  }
544  }
545 
546  return m_board;
547 }
548 
549 
551 {
552  wxCHECK_RET( CurTok() == T_kicad_pcb,
553  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
554 
555  NeedLEFT();
556 
557  T tok = NextTok();
558  if( tok == T_version )
559  {
560  m_requiredVersion = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
561  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
562  NeedRIGHT();
563 
564  // Skip the host name and host build version information.
565  NeedLEFT();
566  NeedSYMBOL();
567  NeedSYMBOL();
568  NeedSYMBOL();
569  NeedRIGHT();
570  }
571  else
572  {
573  m_requiredVersion = SEXPR_BOARD_FILE_VERSION;
574  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
575 
576  // Skip the host name and host build version information.
577  NeedSYMBOL();
578  NeedSYMBOL();
579  NeedRIGHT();
580  }
581 
582  m_board->SetFileFormatVersionAtLoad( m_requiredVersion );
583 }
584 
585 
587 {
588  wxCHECK_RET( CurTok() == T_general,
589  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
590  wxT( " as a general section." ) );
591 
592  T token;
593 
594  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
595  {
596  if( token != T_LEFT )
597  Expecting( T_LEFT );
598 
599  token = NextTok();
600 
601  switch( token )
602  {
603  case T_thickness:
604  m_board->GetDesignSettings().SetBoardThickness( parseBoardUnits( T_thickness ) );
605  NeedRIGHT();
606  break;
607 
608  case T_nets:
609  m_netCodes.resize( parseInt( "nets number" ) );
610  NeedRIGHT();
611  break;
612 
613  case T_no_connects:
614  m_board->SetUnconnectedNetCount( parseInt( "no connect count" ) );
615  NeedRIGHT();
616  break;
617 
618  default: // Skip everything but the board thickness.
619  //wxLogDebug( wxT( "Skipping general section token %s " ), GetChars( GetTokenString( token ) ) );
620 
621  while( ( token = NextTok() ) != T_RIGHT )
622  {
623  if( !IsSymbol( token ) && token != T_NUMBER )
624  Expecting( "symbol or number" );
625  }
626  }
627  }
628 }
629 
630 
632 {
633  wxCHECK_RET( CurTok() == T_page,
634  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) );
635 
636  T token;
637  PAGE_INFO pageInfo;
638 
639  NeedSYMBOL();
640 
641  wxString pageType = FromUTF8();
642 
643  if( !pageInfo.SetType( pageType ) )
644  {
645  wxString err;
646  err.Printf( _( "page type \"%s\" is not valid " ), GetChars( FromUTF8() ) );
647  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
648  }
649 
650  if( pageType == PAGE_INFO::Custom )
651  {
652  double width = parseDouble( "width" ); // width in mm
653 
654  // Perform some controls to avoid crashes if the size is edited by hands
655  if( width < 100.0 )
656  width = 100.0;
657  else if( width > 1200.0 )
658  width = 1200.0;
659 
660  double height = parseDouble( "height" ); // height in mm
661 
662  if( height < 100.0 )
663  height = 100.0;
664  else if( height > 1200.0 )
665  height = 1200.0;
666 
667  pageInfo.SetWidthMils( Mm2mils( width ) );
668  pageInfo.SetHeightMils( Mm2mils( height ) );
669  }
670 
671  token = NextTok();
672 
673  if( token == T_portrait )
674  {
675  pageInfo.SetPortrait( true );
676  NeedRIGHT();
677  }
678  else if( token != T_RIGHT )
679  {
680  Expecting( "portrait|)" );
681  }
682 
683  m_board->SetPageSettings( pageInfo );
684 }
685 
686 
688 {
689  wxCHECK_RET( CurTok() == T_title_block,
690  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
691  wxT( " as TITLE_BLOCK." ) );
692 
693  T token;
694  TITLE_BLOCK titleBlock;
695 
696  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
697  {
698  if( token != T_LEFT )
699  Expecting( T_LEFT );
700 
701  token = NextTok();
702 
703  switch( token )
704  {
705  case T_title:
706  NextTok();
707  titleBlock.SetTitle( FromUTF8() );
708  break;
709 
710  case T_date:
711  NextTok();
712  titleBlock.SetDate( FromUTF8() );
713  break;
714 
715  case T_rev:
716  NextTok();
717  titleBlock.SetRevision( FromUTF8() );
718  break;
719 
720  case T_company:
721  NextTok();
722  titleBlock.SetCompany( FromUTF8() );
723  break;
724 
725  case T_comment:
726  {
727  int commentNumber = parseInt( "comment" );
728 
729  switch( commentNumber )
730  {
731  case 1:
732  NextTok();
733  titleBlock.SetComment1( FromUTF8() );
734  break;
735 
736  case 2:
737  NextTok();
738  titleBlock.SetComment2( FromUTF8() );
739  break;
740 
741  case 3:
742  NextTok();
743  titleBlock.SetComment3( FromUTF8() );
744  break;
745 
746  case 4:
747  NextTok();
748  titleBlock.SetComment4( FromUTF8() );
749  break;
750 
751  default:
752  wxString err;
753  err.Printf( wxT( "%d is not a valid title block comment number" ), commentNumber );
754  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
755  }
756  }
757  break;
758 
759  default:
760  Expecting( "title, date, rev, company, or comment" );
761  }
762 
763  NeedRIGHT();
764  }
765 
766  m_board->SetTitleBlock( titleBlock );
767 }
768 
769 
771 {
772  T token;
773 
774  std::string name;
775  std::string type;
776  bool isVisible = true;
777 
778  aLayer->clear();
779 
780  if( CurTok() != T_LEFT )
781  Expecting( T_LEFT );
782 
783  // this layer_num is not used, we DO depend on LAYER_T however.
784  LAYER_NUM layer_num = parseInt( "layer index" );
785 
786  NeedSYMBOLorNUMBER();
787  name = CurText();
788 
789  NeedSYMBOL();
790  type = CurText();
791 
792  token = NextTok();
793 
794  if( token == T_hide )
795  {
796  isVisible = false;
797  NeedRIGHT();
798  }
799  else if( token != T_RIGHT )
800  {
801  Expecting( "hide or )" );
802  }
803 
804  aLayer->m_name = FROM_UTF8( name.c_str() );
805  aLayer->m_type = LAYER::ParseType( type.c_str() );
806  aLayer->m_number = layer_num;
807  aLayer->m_visible = isVisible;
808 }
809 
810 
811 
813 {
814  wxCHECK_RET( CurTok() == T_layers,
815  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) );
816 
817  T token;
818  LSET visibleLayers;
819  LSET enabledLayers;
820  int copperLayerCount = 0;
821  LAYER layer;
822 
823  std::vector<LAYER> cu;
824 
825  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
826  {
827  parseLayer( &layer );
828 
829  if( layer.m_type == LT_UNDEFINED ) // it's a non-copper layer
830  break;
831 
832  cu.push_back( layer ); // it's copper
833  }
834 
835  // All Cu layers are parsed, but not the non-cu layers here.
836 
837  // The original *.kicad_pcb file format and the inverted
838  // Cu stack format both have all the Cu layers first, so use this
839  // trick to handle either. The layer number in the (layers ..)
840  // s-expression element are ignored.
841  if( cu.size() )
842  {
843  // Rework the layer numbers, which changed when the Cu stack
844  // was flipped. So we instead use position in the list.
845  cu[cu.size()-1].m_number = B_Cu;
846 
847  for( unsigned i=0; i < cu.size()-1; ++i )
848  {
849  cu[i].m_number = i;
850  }
851 
852  for( std::vector<LAYER>::const_iterator it = cu.begin(); it<cu.end(); ++it )
853  {
854  enabledLayers.set( it->m_number );
855 
856  if( it->m_visible )
857  visibleLayers.set( it->m_number );
858 
859  m_board->SetLayerDescr( PCB_LAYER_ID( it->m_number ), *it );
860 
861  UTF8 name = it->m_name;
862 
863  m_layerIndices[ name ] = PCB_LAYER_ID( it->m_number );
864  m_layerMasks[ name ] = LSET( PCB_LAYER_ID( it->m_number ) );
865  }
866 
867  copperLayerCount = cu.size();
868  }
869 
870  // process non-copper layers
871  while( token != T_RIGHT )
872  {
873  LAYER_ID_MAP::const_iterator it = m_layerIndices.find( UTF8( layer.m_name ) );
874 
875  if( it == m_layerIndices.end() )
876  {
877  wxString error = wxString::Format(
878  _( "Layer '%s' in file '%s' at line %d, is not in fixed layer hash" ),
879  GetChars( layer.m_name ),
880  GetChars( CurSource() ),
881  CurLineNumber(),
882  CurOffset()
883  );
884 
885  THROW_IO_ERROR( error );
886  }
887 
888  layer.m_number = it->second;
889 
890  enabledLayers.set( layer.m_number );
891 
892  if( layer.m_visible )
893  visibleLayers.set( layer.m_number );
894 
895  // DBG( printf( "aux m_visible:%s\n", layer.m_visible ? "true" : "false" );)
896 
897  m_board->SetLayerDescr( it->second, layer );
898 
899  token = NextTok();
900 
901  if( token != T_LEFT )
902  break;
903 
904  parseLayer( &layer );
905  }
906 
907  // We need at least 2 copper layers and there must be an even number of them.
908  if( copperLayerCount < 2 || (copperLayerCount % 2) != 0 )
909  {
910  wxString err = wxString::Format(
911  _( "%d is not a valid layer count" ), copperLayerCount );
912 
913  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
914  }
915 
916  m_board->SetCopperLayerCount( copperLayerCount );
917  m_board->SetEnabledLayers( enabledLayers );
918 
919  // call SetEnabledLayers before SetVisibleLayers()
920  m_board->SetVisibleLayers( visibleLayers );
921 }
922 
923 
924 template<class T, class M>
925 T PCB_PARSER::lookUpLayer( const M& aMap ) throw( PARSE_ERROR, IO_ERROR )
926 {
927  // avoid constructing another std::string, use lexer's directly
928  typename M::const_iterator it = aMap.find( curText );
929 
930  if( it == aMap.end() )
931  {
932 #if 0 && defined(DEBUG)
933  // dump the whole darn table, there's something wrong with it.
934  for( it = aMap.begin(); it != aMap.end(); ++it )
935  {
936  wxLogDebug( &aMap == (void*)&m_layerIndices ? wxT( "lm[%s] = %d" ) :
937  wxT( "lm[%s] = %08X" ), it->first.c_str(), it->second );
938  }
939 #endif
940 
941  wxString error = wxString::Format( _(
942  "Layer '%s' in file\n"
943  "'%s'\n"
944  "at line %d, position %d\n"
945  "was not defined in the layers section"
946  ),
947  GetChars( FROM_UTF8( CurText() ) ),
948  GetChars( CurSource() ),
949  CurLineNumber(), CurOffset() );
950 
951  THROW_IO_ERROR( error );
952  }
953 
954  return it->second;
955 }
956 
957 
959 {
960  wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER,
961  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) );
962 
963  NextTok();
964 
965  PCB_LAYER_ID layerIndex = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
966 
967  // Handle closing ) in object parser.
968 
969  return layerIndex;
970 }
971 
972 
974 {
975  wxCHECK_MSG( CurTok() == T_layers, LSET(),
976  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
977  wxT( " as item layer mask." ) );
978 
979  LSET layerMask;
980 
981  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
982  {
983  LSET mask = lookUpLayer<LSET>( m_layerMasks );
984  layerMask |= mask;
985  }
986 
987  return layerMask;
988 }
989 
990 
992 {
993  wxCHECK_RET( CurTok() == T_setup,
994  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
995 
996  T token;
997  NETCLASSPTR defaultNetClass = m_board->GetDesignSettings().GetDefault();
998  // TODO Orson: is it really necessary to first operate on a copy and then apply it?
999  // would not it be better to use reference here and apply all the changes instantly?
1000  BOARD_DESIGN_SETTINGS designSettings = m_board->GetDesignSettings();
1001  ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings();
1002 
1003  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1004  {
1005  if( token != T_LEFT )
1006  Expecting( T_LEFT );
1007 
1008  token = NextTok();
1009 
1010  switch( token )
1011  {
1012  case T_last_trace_width: // not used now
1013  /* lastTraceWidth =*/ parseBoardUnits( T_last_trace_width );
1014  NeedRIGHT();
1015  break;
1016 
1017  case T_user_trace_width:
1018  designSettings.m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) );
1019  NeedRIGHT();
1020  break;
1021 
1022  case T_trace_clearance:
1023  defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) );
1024  NeedRIGHT();
1025  break;
1026 
1027  case T_zone_clearance:
1028  zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance );
1029  NeedRIGHT();
1030  break;
1031 
1032  case T_zone_45_only:
1033  zoneSettings.m_Zone_45_Only = parseBool();
1034  NeedRIGHT();
1035  break;
1036 
1037  case T_trace_min:
1038  designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min );
1039  NeedRIGHT();
1040  break;
1041 
1042  case T_segment_width:
1043  designSettings.m_DrawSegmentWidth = parseBoardUnits( T_segment_width );
1044  NeedRIGHT();
1045  break;
1046 
1047  case T_edge_width:
1048  designSettings.m_EdgeSegmentWidth = parseBoardUnits( T_edge_width );
1049  NeedRIGHT();
1050  break;
1051 
1052  case T_via_size:
1053  defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) );
1054  NeedRIGHT();
1055  break;
1056 
1057  case T_via_drill:
1058  defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) );
1059  NeedRIGHT();
1060  break;
1061 
1062  case T_via_min_size:
1063  designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size );
1064  NeedRIGHT();
1065  break;
1066 
1067  case T_via_min_drill:
1068  designSettings.m_ViasMinDrill = parseBoardUnits( T_via_min_drill );
1069  NeedRIGHT();
1070  break;
1071 
1072  case T_user_via:
1073  {
1074  int viaSize = parseBoardUnits( "user via size" );
1075  int viaDrill = parseBoardUnits( "user via drill" );
1076  designSettings.m_ViasDimensionsList.push_back( VIA_DIMENSION( viaSize, viaDrill ) );
1077  NeedRIGHT();
1078  }
1079  break;
1080 
1081  case T_uvia_size:
1082  defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) );
1083  NeedRIGHT();
1084  break;
1085 
1086  case T_uvia_drill:
1087  defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1088  NeedRIGHT();
1089  break;
1090 
1091  case T_uvias_allowed:
1092  designSettings.m_MicroViasAllowed = parseBool();
1093  NeedRIGHT();
1094  break;
1095 
1097  designSettings.m_BlindBuriedViaAllowed = parseBool();
1098  NeedRIGHT();
1099  break;
1100 
1101  case T_uvia_min_size:
1102  designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size );
1103  NeedRIGHT();
1104  break;
1105 
1106  case T_uvia_min_drill:
1107  designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill );
1108  NeedRIGHT();
1109  break;
1110 
1111  case T_pcb_text_width:
1112  designSettings.m_PcbTextWidth = parseBoardUnits( T_pcb_text_width );
1113  NeedRIGHT();
1114  break;
1115 
1116  case T_pcb_text_size:
1117  designSettings.m_PcbTextSize.x = parseBoardUnits( "pcb text width" );
1118  designSettings.m_PcbTextSize.y = parseBoardUnits( "pcb text height" );
1119  NeedRIGHT();
1120  break;
1121 
1122  case T_mod_edge_width:
1123  designSettings.m_ModuleSegmentWidth = parseBoardUnits( T_mod_edge_width );
1124  NeedRIGHT();
1125  break;
1126 
1127  case T_mod_text_size:
1128  designSettings.m_ModuleTextSize.x = parseBoardUnits( "module text width" );
1129  designSettings.m_ModuleTextSize.y = parseBoardUnits( "module text height" );
1130  NeedRIGHT();
1131  break;
1132 
1133  case T_mod_text_width:
1134  designSettings.m_ModuleTextWidth = parseBoardUnits( T_mod_text_width );
1135  NeedRIGHT();
1136  break;
1137 
1138  case T_pad_size:
1139  {
1140  wxSize sz;
1141  sz.SetWidth( parseBoardUnits( "master pad width" ) );
1142  sz.SetHeight( parseBoardUnits( "master pad height" ) );
1143  designSettings.m_Pad_Master.SetSize( sz );
1144  NeedRIGHT();
1145  }
1146  break;
1147 
1148  case T_pad_drill:
1149  {
1150  int drillSize = parseBoardUnits( T_pad_drill );
1151  designSettings.m_Pad_Master.SetDrillSize( wxSize( drillSize, drillSize ) );
1152  NeedRIGHT();
1153  }
1154  break;
1155 
1157  designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance );
1158  NeedRIGHT();
1159  break;
1160 
1162  designSettings.m_SolderMaskMinWidth = parseBoardUnits( T_solder_mask_min_width );
1163  NeedRIGHT();
1164  break;
1165 
1167  designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance );
1168  NeedRIGHT();
1169  break;
1170 
1173  NeedRIGHT();
1174  break;
1175 
1176  case T_aux_axis_origin:
1177  {
1178  int x = parseBoardUnits( "auxiliary origin X" );
1179  int y = parseBoardUnits( "auxiliary origin Y" );
1180  // m_board->SetAuxOrigin( wxPoint( x, y ) ); gets overwritten via SetDesignSettings below
1181  designSettings.m_AuxOrigin = wxPoint( x, y );
1182  NeedRIGHT();
1183  }
1184  break;
1185 
1186  case T_grid_origin:
1187  {
1188  int x = parseBoardUnits( "grid origin X" );
1189  int y = parseBoardUnits( "grid origin Y" );
1190  // m_board->SetGridOrigin( wxPoint( x, y ) ); gets overwritten SetDesignSettings below
1191  designSettings.m_GridOrigin = wxPoint( x, y );
1192  NeedRIGHT();
1193  }
1194  break;
1195 
1196  case T_visible_elements:
1197  designSettings.SetVisibleElements( parseHex() | MIN_VISIBILITY_MASK );
1198  NeedRIGHT();
1199  break;
1200 
1201  case T_pcbplotparams:
1202  {
1203  PCB_PLOT_PARAMS plotParams;
1204  PCB_PLOT_PARAMS_PARSER parser( reader );
1205  // parser must share the same current line as our current PCB parser
1206  // synchronize it.
1207  parser.SyncLineReaderWith( *this );
1208 
1209  plotParams.Parse( &parser );
1210  SyncLineReaderWith( parser );
1211 
1212  m_board->SetPlotOptions( plotParams );
1213  }
1214  break;
1215 
1216  default:
1217  Unexpected( CurText() );
1218  }
1219  }
1220 
1221  m_board->SetDesignSettings( designSettings );
1222  m_board->SetZoneSettings( zoneSettings );
1223 }
1224 
1225 
1227 {
1228  wxCHECK_RET( CurTok() == T_net,
1229  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) );
1230 
1231  int netCode = parseInt( "net number" );
1232 
1233  NeedSYMBOLorNUMBER();
1234  wxString name = FromUTF8();
1235 
1236  NeedRIGHT();
1237 
1238  // net 0 should be already in list, so store this net
1239  // if it is not the net 0, or if the net 0 does not exists.
1240  // (TODO: a better test.)
1241  if( netCode > NETINFO_LIST::UNCONNECTED || !m_board->FindNet( NETINFO_LIST::UNCONNECTED ) )
1242  {
1243  NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, netCode );
1244  m_board->Add( net );
1245 
1246  // Store the new code mapping
1247  pushValueIntoMap( netCode, net->GetNet() );
1248  }
1249 }
1250 
1251 
1253 {
1254  wxCHECK_RET( CurTok() == T_net_class,
1255  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) );
1256 
1257  T token;
1258 
1259  NETCLASSPTR nc = std::make_shared<NETCLASS>( wxEmptyString );
1260 
1261  // Read netclass name (can be a name or just a number like track width)
1262  NeedSYMBOLorNUMBER();
1263  nc->SetName( FromUTF8() );
1264  NeedSYMBOL();
1265  nc->SetDescription( FromUTF8() );
1266 
1267  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1268  {
1269  if( token != T_LEFT )
1270  Expecting( T_LEFT );
1271 
1272  token = NextTok();
1273 
1274  switch( token )
1275  {
1276  case T_clearance:
1277  nc->SetClearance( parseBoardUnits( T_clearance ) );
1278  break;
1279 
1280  case T_trace_width:
1281  nc->SetTrackWidth( parseBoardUnits( T_trace_width ) );
1282  break;
1283 
1284  case T_via_dia:
1285  nc->SetViaDiameter( parseBoardUnits( T_via_dia ) );
1286  break;
1287 
1288  case T_via_drill:
1289  nc->SetViaDrill( parseBoardUnits( T_via_drill ) );
1290  break;
1291 
1292  case T_uvia_dia:
1293  nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) );
1294  break;
1295 
1296  case T_uvia_drill:
1297  nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1298  break;
1299 
1300  case T_diff_pair_width:
1301  nc->SetDiffPairWidth( parseBoardUnits( T_diff_pair_width ) );
1302  break;
1303 
1304  case T_diff_pair_gap:
1305  nc->SetDiffPairGap( parseBoardUnits( T_diff_pair_gap ) );
1306  break;
1307 
1308  case T_add_net:
1309  NeedSYMBOLorNUMBER();
1310  nc->Add( FromUTF8() );
1311  break;
1312 
1313  default:
1314  Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, diff_pair_width, diff_pair_gap or add_net" );
1315  }
1316 
1317  NeedRIGHT();
1318  }
1319 
1320  if( !m_board->GetDesignSettings().m_NetClasses.Add( nc ) )
1321  {
1322  // Must have been a name conflict, this is a bad board file.
1323  // User may have done a hand edit to the file.
1324 
1325  // unique_ptr will delete nc on this code path
1326 
1327  wxString error;
1328  error.Printf( _( "duplicate NETCLASS name '%s' in file <%s> at line %d, offset %d" ),
1329  nc->GetName().GetData(), CurSource().GetData(), CurLineNumber(), CurOffset() );
1330  THROW_IO_ERROR( error );
1331  }
1332 }
1333 
1334 
1336 {
1337  wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
1338  CurTok() == T_gr_line || CurTok() == T_gr_poly, NULL,
1339  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DRAWSEGMENT." ) );
1340 
1341  T token;
1342  wxPoint pt;
1343  std::unique_ptr< DRAWSEGMENT > segment( new DRAWSEGMENT( NULL ) );
1344 
1345  switch( CurTok() )
1346  {
1347  case T_gr_arc:
1348  segment->SetShape( S_ARC );
1349  NeedLEFT();
1350  token = NextTok();
1351 
1352  if( token != T_start )
1353  Expecting( T_start );
1354 
1355  pt.x = parseBoardUnits( "X coordinate" );
1356  pt.y = parseBoardUnits( "Y coordinate" );
1357  segment->SetStart( pt );
1358  NeedRIGHT();
1359  NeedLEFT();
1360  token = NextTok();
1361 
1362  if( token != T_end )
1363  Expecting( T_end );
1364 
1365  pt.x = parseBoardUnits( "X coordinate" );
1366  pt.y = parseBoardUnits( "Y coordinate" );
1367  segment->SetEnd( pt );
1368  NeedRIGHT();
1369  break;
1370 
1371  case T_gr_circle:
1372  segment->SetShape( S_CIRCLE );
1373  NeedLEFT();
1374  token = NextTok();
1375 
1376  if( token != T_center )
1377  Expecting( T_center );
1378 
1379  pt.x = parseBoardUnits( "X coordinate" );
1380  pt.y = parseBoardUnits( "Y coordinate" );
1381  segment->SetStart( pt );
1382  NeedRIGHT();
1383  NeedLEFT();
1384 
1385  token = NextTok();
1386 
1387  if( token != T_end )
1388  Expecting( T_end );
1389 
1390  pt.x = parseBoardUnits( "X coordinate" );
1391  pt.y = parseBoardUnits( "Y coordinate" );
1392  segment->SetEnd( pt );
1393  NeedRIGHT();
1394  break;
1395 
1396  case T_gr_curve:
1397  segment->SetShape( S_CURVE );
1398  NeedLEFT();
1399  token = NextTok();
1400 
1401  if( token != T_pts )
1402  Expecting( T_pts );
1403 
1404  segment->SetStart( parseXY() );
1405  segment->SetBezControl1( parseXY() );
1406  segment->SetBezControl2( parseXY() );
1407  segment->SetEnd( parseXY() );
1408  NeedRIGHT();
1409  break;
1410 
1411  case T_gr_line:
1412  // Default DRAWSEGMENT type is S_SEGMENT.
1413  NeedLEFT();
1414  token = NextTok();
1415 
1416  if( token != T_start )
1417  Expecting( T_start );
1418 
1419  pt.x = parseBoardUnits( "X coordinate" );
1420  pt.y = parseBoardUnits( "Y coordinate" );
1421  segment->SetStart( pt );
1422  NeedRIGHT();
1423  NeedLEFT();
1424  token = NextTok();
1425 
1426  if( token != T_end )
1427  Expecting( T_end );
1428 
1429  pt.x = parseBoardUnits( "X coordinate" );
1430  pt.y = parseBoardUnits( "Y coordinate" );
1431  segment->SetEnd( pt );
1432  NeedRIGHT();
1433  break;
1434 
1435  case T_gr_poly:
1436  {
1437  segment->SetShape( S_POLYGON );
1438  NeedLEFT();
1439  token = NextTok();
1440 
1441  if( token != T_pts )
1442  Expecting( T_pts );
1443 
1444  std::vector< wxPoint > pts;
1445 
1446  while( (token = NextTok()) != T_RIGHT )
1447  pts.push_back( parseXY() );
1448 
1449  segment->SetPolyPoints( pts );
1450  }
1451  break;
1452 
1453  default:
1454  Expecting( "gr_arc, gr_circle, gr_curve, gr_line, or gr_poly" );
1455  }
1456 
1457  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1458  {
1459  if( token != T_LEFT )
1460  Expecting( T_LEFT );
1461 
1462  token = NextTok();
1463 
1464  switch( token )
1465  {
1466  case T_angle:
1467  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
1468  break;
1469 
1470  case T_layer:
1471  segment->SetLayer( parseBoardItemLayer() );
1472  break;
1473 
1474  case T_width:
1475  segment->SetWidth( parseBoardUnits( T_width ) );
1476  break;
1477 
1478  case T_tstamp:
1479  segment->SetTimeStamp( parseHex() );
1480  break;
1481 
1482  case T_status:
1483  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
1484  break;
1485 
1486  default:
1487  Expecting( "layer, width, tstamp, or status" );
1488  }
1489 
1490  NeedRIGHT();
1491  }
1492 
1493  return segment.release();
1494 }
1495 
1496 
1498 {
1499  wxCHECK_MSG( CurTok() == T_gr_text, NULL,
1500  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TEXTE_PCB." ) );
1501 
1502  T token;
1503 
1504  std::unique_ptr<TEXTE_PCB> text( new TEXTE_PCB( m_board ) );
1505  NeedSYMBOLorNUMBER();
1506 
1507  text->SetText( FromUTF8() );
1508  NeedLEFT();
1509  token = NextTok();
1510 
1511  if( token != T_at )
1512  Expecting( T_at );
1513 
1514  wxPoint pt;
1515 
1516  pt.x = parseBoardUnits( "X coordinate" );
1517  pt.y = parseBoardUnits( "Y coordinate" );
1518  text->SetTextPos( pt );
1519 
1520  // If there is no orientation defined, then it is the default value of 0 degrees.
1521  token = NextTok();
1522 
1523  if( token == T_NUMBER )
1524  {
1525  text->SetTextAngle( parseDouble() * 10.0 );
1526  NeedRIGHT();
1527  }
1528  else if( token != T_RIGHT )
1529  {
1530  Unexpected( CurText() );
1531  }
1532 
1533  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1534  {
1535  if( token != T_LEFT )
1536  Expecting( T_LEFT );
1537 
1538  token = NextTok();
1539 
1540  switch( token )
1541  {
1542  case T_layer:
1543  text->SetLayer( parseBoardItemLayer() );
1544  NeedRIGHT();
1545  break;
1546 
1547  case T_tstamp:
1548  text->SetTimeStamp( parseHex() );
1549  NeedRIGHT();
1550  break;
1551 
1552  case T_effects:
1553  parseEDA_TEXT( (EDA_TEXT*) text.get() );
1554  break;
1555 
1556  default:
1557  Expecting( "layer, tstamp or effects" );
1558  }
1559  }
1560 
1561  return text.release();
1562 }
1563 
1564 
1566 {
1567  wxCHECK_MSG( CurTok() == T_dimension, NULL,
1568  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) );
1569 
1570  T token;
1571 
1572  std::unique_ptr<DIMENSION> dimension( new DIMENSION( NULL ) );
1573 
1574  dimension->SetValue( parseBoardUnits( "dimension value" ) );
1575  NeedLEFT();
1576  token = NextTok();
1577 
1578  if( token != T_width )
1579  Expecting( T_width );
1580 
1581  dimension->SetWidth( parseBoardUnits( "dimension width value" ) );
1582  NeedRIGHT();
1583 
1584  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1585  {
1586  if( token != T_LEFT )
1587  Expecting( T_LEFT );
1588 
1589  token = NextTok();
1590 
1591  switch( token )
1592  {
1593  case T_layer:
1594  dimension->SetLayer( parseBoardItemLayer() );
1595  NeedRIGHT();
1596  break;
1597 
1598  case T_tstamp:
1599  dimension->SetTimeStamp( parseHex() );
1600  NeedRIGHT();
1601  break;
1602 
1603  case T_gr_text:
1604  {
1605  TEXTE_PCB* text = parseTEXTE_PCB();
1606  dimension->Text() = *text;
1607  dimension->SetPosition( text->GetTextPos() );
1608  delete text;
1609  break;
1610  }
1611 
1612  case T_feature1:
1613  NeedLEFT();
1614  token = NextTok();
1615 
1616  if( token != T_pts )
1617  Expecting( T_pts );
1618 
1619  parseXY( &dimension->m_featureLineDO.x, &dimension->m_featureLineDO.y );
1620  parseXY( &dimension->m_featureLineDF.x, &dimension->m_featureLineDF.y );
1621  dimension->UpdateHeight();
1622  NeedRIGHT();
1623  NeedRIGHT();
1624  break;
1625 
1626  case T_feature2:
1627  NeedLEFT();
1628  token = NextTok();
1629 
1630  if( token != T_pts )
1631  Expecting( T_pts );
1632 
1633  parseXY( &dimension->m_featureLineGO.x, &dimension->m_featureLineGO.y );
1634  parseXY( &dimension->m_featureLineGF.x, &dimension->m_featureLineGF.y );
1635  dimension->UpdateHeight();
1636  NeedRIGHT();
1637  NeedRIGHT();
1638  break;
1639 
1640 
1641  case T_crossbar:
1642  NeedLEFT();
1643  token = NextTok();
1644 
1645  if( token != T_pts )
1646  Expecting( T_pts );
1647 
1648  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1649  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1650  dimension->UpdateHeight();
1651  NeedRIGHT();
1652  NeedRIGHT();
1653  break;
1654 
1655  case T_arrow1a:
1656  NeedLEFT();
1657  token = NextTok();
1658 
1659  if( token != T_pts )
1660  Expecting( T_pts );
1661 
1662  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1663  parseXY( &dimension->m_arrowD1F.x, &dimension->m_arrowD1F.y );
1664  NeedRIGHT();
1665  NeedRIGHT();
1666  break;
1667 
1668  case T_arrow1b:
1669  NeedLEFT();
1670  token = NextTok();
1671 
1672  if( token != T_pts )
1673  Expecting( T_pts );
1674 
1675  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1676  parseXY( &dimension->m_arrowD2F.x, &dimension->m_arrowD2F.y );
1677  NeedRIGHT();
1678  NeedRIGHT();
1679  break;
1680 
1681  case T_arrow2a:
1682  NeedLEFT();
1683  token = NextTok();
1684 
1685  if( token != T_pts )
1686  Expecting( T_pts );
1687 
1688  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1689  parseXY( &dimension->m_arrowG1F.x, &dimension->m_arrowG1F.y );
1690  NeedRIGHT();
1691  NeedRIGHT();
1692  break;
1693 
1694  case T_arrow2b:
1695  NeedLEFT();
1696  token = NextTok();
1697 
1698  if( token != T_pts )
1699  Expecting( T_pts );
1700 
1701  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1702  parseXY( &dimension->m_arrowG2F.x, &dimension->m_arrowG2F.y );
1703  NeedRIGHT();
1704  NeedRIGHT();
1705  break;
1706 
1707  default:
1708  Expecting( "layer, tstamp, gr_text, feature1, feature2 crossbar, arrow1a, "
1709  "arrow1b, arrow2a, or arrow2b" );
1710  }
1711  }
1712 
1713  return dimension.release();
1714 }
1715 
1716 
1717 MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments )
1719 {
1720  try
1721  {
1722  return parseMODULE_unchecked( aInitialComments );
1723  }
1724  catch( const PARSE_ERROR& parse_error )
1725  {
1726  if( m_tooRecent )
1727  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
1728  else
1729  throw;
1730  }
1731 }
1732 
1733 
1734 MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
1735  throw( IO_ERROR, PARSE_ERROR )
1736 {
1737  wxCHECK_MSG( CurTok() == T_module, NULL,
1738  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) );
1739 
1740  wxString name;
1741  wxPoint pt;
1742  T token;
1743  LIB_ID fpid;
1744 
1745  std::unique_ptr<MODULE> module( new MODULE( m_board ) );
1746 
1747  module->SetInitialComments( aInitialComments );
1748 
1749  token = NextTok();
1750 
1751  if( !IsSymbol( token ) && token != T_NUMBER )
1752  Expecting( "symbol|number" );
1753 
1754  name = FromUTF8();
1755 
1756  if( !name.IsEmpty() && fpid.Parse( TO_UTF8( FromUTF8() ) ) >= 0 )
1757  {
1758  wxString error;
1759  error.Printf( _( "invalid footprint ID in\nfile: <%s>\nline: %d\noffset: %d" ),
1760  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
1761  THROW_IO_ERROR( error );
1762  }
1763 
1764  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1765  {
1766  if( token == T_LEFT )
1767  token = NextTok();
1768 
1769  switch( token )
1770  {
1771  case T_version:
1772  {
1773  // Theoretically a module nested in a PCB could declare its own version, though
1774  // as of writing this comment we don't do that. Just in case, take the greater
1775  // version.
1776  int this_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
1777  NeedRIGHT();
1778  m_requiredVersion = std::max( m_requiredVersion, this_version );
1779  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
1780  break;
1781  }
1782 
1783  case T_locked:
1784  module->SetLocked( true );
1785  break;
1786 
1787  case T_placed:
1788  module->SetIsPlaced( true );
1789  break;
1790 
1791  case T_layer:
1792  {
1793  // Footprints can be only on the front side or the back side.
1794  // but because we can find some stupid layer in file, ensure a
1795  // acceptable layer is set for the footprint
1796  PCB_LAYER_ID layer = parseBoardItemLayer();
1797  module->SetLayer( layer == B_Cu ? B_Cu : F_Cu );
1798  }
1799  NeedRIGHT();
1800  break;
1801 
1802  case T_tedit:
1803  module->SetLastEditTime( parseHex() );
1804  NeedRIGHT();
1805  break;
1806 
1807  case T_tstamp:
1808  module->SetTimeStamp( parseHex() );
1809  NeedRIGHT();
1810  break;
1811 
1812  case T_at:
1813  pt.x = parseBoardUnits( "X coordinate" );
1814  pt.y = parseBoardUnits( "Y coordinate" );
1815  module->SetPosition( pt );
1816  token = NextTok();
1817 
1818  if( token == T_NUMBER )
1819  {
1820  module->SetOrientation( parseDouble() * 10.0 );
1821  NeedRIGHT();
1822  }
1823  else if( token != T_RIGHT )
1824  {
1825  Expecting( T_RIGHT );
1826  }
1827 
1828  break;
1829 
1830  case T_descr:
1831  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
1832  module->SetDescription( FromUTF8() );
1833  NeedRIGHT();
1834  break;
1835 
1836  case T_tags:
1837  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
1838  module->SetKeywords( FromUTF8() );
1839  NeedRIGHT();
1840  break;
1841 
1842  case T_path:
1843  NeedSYMBOLorNUMBER(); // Paths can be numerical so a number is also a symbol here
1844  module->SetPath( FromUTF8() );
1845  NeedRIGHT();
1846  break;
1847 
1848  case T_autoplace_cost90:
1849  module->SetPlacementCost90( parseInt( "auto place cost at 90 degrees" ) );
1850  NeedRIGHT();
1851  break;
1852 
1853  case T_autoplace_cost180:
1854  module->SetPlacementCost180( parseInt( "auto place cost at 180 degrees" ) );
1855  NeedRIGHT();
1856  break;
1857 
1858  case T_solder_mask_margin:
1859  module->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) );
1860  NeedRIGHT();
1861  break;
1862 
1863  case T_solder_paste_margin:
1864  module->SetLocalSolderPasteMargin(
1865  parseBoardUnits( "local solder paste margin value" ) );
1866  NeedRIGHT();
1867  break;
1868 
1869  case T_solder_paste_ratio:
1870  module->SetLocalSolderPasteMarginRatio(
1871  parseDouble( "local solder paste margin ratio value" ) );
1872  NeedRIGHT();
1873  break;
1874 
1875  case T_clearance:
1876  module->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
1877  NeedRIGHT();
1878  break;
1879 
1880  case T_zone_connect:
1881  module->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) );
1882  NeedRIGHT();
1883  break;
1884 
1885  case T_thermal_width:
1886  module->SetThermalWidth( parseBoardUnits( "thermal width value" ) );
1887  NeedRIGHT();
1888  break;
1889 
1890  case T_thermal_gap:
1891  module->SetThermalGap( parseBoardUnits( "thermal gap value" ) );
1892  NeedRIGHT();
1893  break;
1894 
1895  case T_attr:
1896  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1897  {
1898  switch( token )
1899  {
1900  case T_smd:
1901  module->SetAttributes( module->GetAttributes() | MOD_CMS );
1902  break;
1903 
1904  case T_virtual:
1905  module->SetAttributes( module->GetAttributes() | MOD_VIRTUAL );
1906  break;
1907 
1908  default:
1909  Expecting( "smd and/or virtual" );
1910  }
1911  }
1912 
1913  break;
1914 
1915  case T_fp_text:
1916  {
1917  TEXTE_MODULE* text = parseTEXTE_MODULE();
1918  text->SetParent( module.get() );
1919  double orientation = text->GetTextAngle();
1920  orientation -= module->GetOrientation();
1921  text->SetTextAngle( orientation );
1922  text->SetDrawCoord();
1923 
1924  switch( text->GetType() )
1925  {
1927  module->Reference() = *text;
1928  delete text;
1929  break;
1930 
1932  module->Value() = *text;
1933  delete text;
1934  break;
1935 
1936  default:
1937  module->GraphicalItems().PushBack( text );
1938  }
1939  }
1940  break;
1941 
1942  case T_fp_arc:
1943  case T_fp_circle:
1944  case T_fp_curve:
1945  case T_fp_line:
1946  case T_fp_poly:
1947  {
1948  EDGE_MODULE* em = parseEDGE_MODULE();
1949  em->SetParent( module.get() );
1950  em->SetDrawCoord();
1951  module->GraphicalItems().PushBack( em );
1952  }
1953  break;
1954 
1955  case T_pad:
1956  {
1957  D_PAD* pad = parseD_PAD( module.get() );
1958  pt = pad->GetPos0();
1959 
1960  RotatePoint( &pt, module->GetOrientation() );
1961  pad->SetPosition( pt + module->GetPosition() );
1962  module->Add( pad, ADD_APPEND );
1963  }
1964  break;
1965 
1966  case T_model:
1967  module->Add3DModel( parse3DModel() );
1968  break;
1969 
1970  default:
1971  Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, "
1972  "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
1973  "solder_paste_margin, solder_paste_ratio, clearance, "
1974  "zone_connect, thermal_width, thermal_gap, attr, fp_text, "
1975  "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, or model" );
1976  }
1977  }
1978 
1979  module->SetFPID( fpid );
1980  module->CalculateBoundingBox();
1981 
1982  return module.release();
1983 }
1984 
1985 
1987 {
1988  wxCHECK_MSG( CurTok() == T_fp_text, NULL,
1989  wxString::Format( wxT( "Cannot parse %s as TEXTE_MODULE at line %d, offset %d." ),
1990  GetChars( GetTokenString( CurTok() ) ),
1991  CurLineNumber(), CurOffset() ) );
1992 
1993  T token = NextTok();
1994 
1995  std::unique_ptr<TEXTE_MODULE> text( new TEXTE_MODULE( NULL ) );
1996 
1997  switch( token )
1998  {
1999  case T_reference:
2000  text->SetType( TEXTE_MODULE::TEXT_is_REFERENCE );
2001  break;
2002 
2003  case T_value:
2004  text->SetType( TEXTE_MODULE::TEXT_is_VALUE );
2005  break;
2006 
2007  case T_user:
2008  break; // Default type is user text.
2009 
2010  default:
2011  THROW_IO_ERROR( wxString::Format( _( "cannot handle footprint text type %s" ),
2012  GetChars( FromUTF8() ) ) );
2013  }
2014 
2015  NeedSYMBOLorNUMBER();
2016 
2017  text->SetText( FromUTF8() );
2018  NeedLEFT();
2019  token = NextTok();
2020 
2021  if( token != T_at )
2022  Expecting( T_at );
2023 
2024  wxPoint pt;
2025 
2026  pt.x = parseBoardUnits( "X coordinate" );
2027  pt.y = parseBoardUnits( "Y coordinate" );
2028  text->SetPos0( pt );
2029  token = NextTok();
2030 
2031  // If there is no orientation defined, then it is the default value of 0 degrees.
2032  if( token == T_NUMBER )
2033  {
2034  text->SetTextAngle( parseDouble() * 10.0 );
2035  NeedRIGHT();
2036  }
2037  else if( token != T_RIGHT )
2038  {
2039  Unexpected( CurText() );
2040  }
2041 
2042  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2043  {
2044  if( token == T_LEFT )
2045  token = NextTok();
2046 
2047  switch( token )
2048  {
2049  case T_layer:
2050  text->SetLayer( parseBoardItemLayer() );
2051  NeedRIGHT();
2052  break;
2053 
2054  case T_hide:
2055  text->SetVisible( false );
2056  break;
2057 
2058  case T_effects:
2059  parseEDA_TEXT( (EDA_TEXT*) text.get() );
2060  break;
2061 
2062  default:
2063  Expecting( "hide or effects" );
2064  }
2065  }
2066 
2067  return text.release();
2068 }
2069 
2070 
2072 {
2073  wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
2074  CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL,
2075  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDGE_MODULE." ) );
2076 
2077  wxPoint pt;
2078  T token;
2079 
2080  std::unique_ptr< EDGE_MODULE > segment( new EDGE_MODULE( NULL ) );
2081 
2082  switch( CurTok() )
2083  {
2084  case T_fp_arc:
2085  segment->SetShape( S_ARC );
2086  NeedLEFT();
2087  token = NextTok();
2088 
2089  if( token != T_start )
2090  Expecting( T_start );
2091 
2092  pt.x = parseBoardUnits( "X coordinate" );
2093  pt.y = parseBoardUnits( "Y coordinate" );
2094  segment->SetStart0( pt );
2095  NeedRIGHT();
2096  NeedLEFT();
2097  token = NextTok();
2098 
2099  if( token != T_end )
2100  Expecting( T_end );
2101 
2102  pt.x = parseBoardUnits( "X coordinate" );
2103  pt.y = parseBoardUnits( "Y coordinate" );
2104  segment->SetEnd0( pt );
2105  NeedRIGHT();
2106  NeedLEFT();
2107  token = NextTok();
2108 
2109  if( token != T_angle )
2110  Expecting( T_angle );
2111 
2112  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
2113  NeedRIGHT();
2114  break;
2115 
2116  case T_fp_circle:
2117  segment->SetShape( S_CIRCLE );
2118  NeedLEFT();
2119  token = NextTok();
2120 
2121  if( token != T_center )
2122  Expecting( T_center );
2123 
2124  pt.x = parseBoardUnits( "X coordinate" );
2125  pt.y = parseBoardUnits( "Y coordinate" );
2126  segment->SetStart0( pt );
2127  NeedRIGHT();
2128  NeedLEFT();
2129  token = NextTok();
2130 
2131  if( token != T_end )
2132  Expecting( T_end );
2133 
2134  pt.x = parseBoardUnits( "X coordinate" );
2135  pt.y = parseBoardUnits( "Y coordinate" );
2136  segment->SetEnd0( pt );
2137  NeedRIGHT();
2138  break;
2139 
2140  case T_fp_curve:
2141  segment->SetShape( S_CURVE );
2142  NeedLEFT();
2143  token = NextTok();
2144 
2145  if( token != T_pts )
2146  Expecting( T_pts );
2147 
2148  segment->SetStart0( parseXY() );
2149  segment->SetBezControl1( parseXY() );
2150  segment->SetBezControl2( parseXY() );
2151  segment->SetEnd0( parseXY() );
2152  NeedRIGHT();
2153  break;
2154 
2155  case T_fp_line:
2156  // Default DRAWSEGMENT type is S_SEGMENT.
2157  NeedLEFT();
2158  token = NextTok();
2159 
2160  if( token != T_start )
2161  Expecting( T_start );
2162 
2163  pt.x = parseBoardUnits( "X coordinate" );
2164  pt.y = parseBoardUnits( "Y coordinate" );
2165  segment->SetStart0( pt );
2166 
2167  NeedRIGHT();
2168  NeedLEFT();
2169  token = NextTok();
2170 
2171  if( token != T_end )
2172  Expecting( T_end );
2173 
2174  pt.x = parseBoardUnits( "X coordinate" );
2175  pt.y = parseBoardUnits( "Y coordinate" );
2176  segment->SetEnd0( pt );
2177  NeedRIGHT();
2178  break;
2179 
2180  case T_fp_poly:
2181  {
2182  segment->SetShape( S_POLYGON );
2183  NeedLEFT();
2184  token = NextTok();
2185 
2186  if( token != T_pts )
2187  Expecting( T_pts );
2188 
2189  std::vector< wxPoint > pts;
2190 
2191  while( (token = NextTok()) != T_RIGHT )
2192  pts.push_back( parseXY() );
2193 
2194  segment->SetPolyPoints( pts );
2195  }
2196  break;
2197 
2198  default:
2199  Expecting( "fp_arc, fp_circle, fp_curve, fp_line, or fp_poly" );
2200  }
2201 
2202  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2203  {
2204  if( token != T_LEFT )
2205  Expecting( T_LEFT );
2206 
2207  token = NextTok();
2208 
2209  switch( token )
2210  {
2211  case T_layer:
2212  segment->SetLayer( parseBoardItemLayer() );
2213  break;
2214 
2215  case T_width:
2216  segment->SetWidth( parseBoardUnits( T_width ) );
2217  break;
2218 
2219  case T_tstamp:
2220  segment->SetTimeStamp( parseHex() );
2221  break;
2222 
2223  case T_status:
2224  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2225  break;
2226 
2227  default:
2228  Expecting( "layer or width" );
2229  }
2230 
2231  NeedRIGHT();
2232  }
2233 
2234  return segment.release();
2235 }
2236 
2237 
2239 {
2240  wxCHECK_MSG( CurTok() == T_pad, NULL,
2241  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as D_PAD." ) );
2242 
2243  wxSize sz;
2244  wxPoint pt;
2245 
2246  std::unique_ptr< D_PAD > pad( new D_PAD( aParent ) );
2247 
2248  NeedSYMBOLorNUMBER();
2249  pad->SetPadName( FromUTF8() );
2250 
2251  T token = NextTok();
2252 
2253  switch( token )
2254  {
2255  case T_thru_hole:
2256  pad->SetAttribute( PAD_ATTRIB_STANDARD );
2257  break;
2258 
2259  case T_smd:
2260  pad->SetAttribute( PAD_ATTRIB_SMD );
2261 
2262  // Default D_PAD object is thru hole with drill.
2263  // SMD pads have no hole
2264  pad->SetDrillSize( wxSize( 0, 0 ) );
2265  break;
2266 
2267  case T_connect:
2268  pad->SetAttribute( PAD_ATTRIB_CONN );
2269 
2270  // Default D_PAD object is thru hole with drill.
2271  // CONN pads have no hole
2272  pad->SetDrillSize( wxSize( 0, 0 ) );
2273  break;
2274 
2275  case T_np_thru_hole:
2276  pad->SetAttribute( PAD_ATTRIB_HOLE_NOT_PLATED );
2277  break;
2278 
2279  default:
2280  Expecting( "thru_hole, smd, connect, or np_thru_hole" );
2281  }
2282 
2283  token = NextTok();
2284 
2285  switch( token )
2286  {
2287  case T_circle:
2288  pad->SetShape( PAD_SHAPE_CIRCLE );
2289  break;
2290 
2291  case T_rect:
2292  pad->SetShape( PAD_SHAPE_RECT );
2293  break;
2294 
2295  case T_oval:
2296  pad->SetShape( PAD_SHAPE_OVAL );
2297  break;
2298 
2299  case T_trapezoid:
2300  pad->SetShape( PAD_SHAPE_TRAPEZOID );
2301  break;
2302 
2303  case T_roundrect:
2304  pad->SetShape( PAD_SHAPE_ROUNDRECT );
2305  break;
2306 
2307  default:
2308  Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
2309  }
2310 
2311  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2312  {
2313  if( token != T_LEFT )
2314  Expecting( T_LEFT );
2315 
2316  token = NextTok();
2317 
2318  switch( token )
2319  {
2320  case T_size:
2321  sz.SetWidth( parseBoardUnits( "width value" ) );
2322  sz.SetHeight( parseBoardUnits( "height value" ) );
2323  pad->SetSize( sz );
2324  NeedRIGHT();
2325  break;
2326 
2327  case T_at:
2328  pt.x = parseBoardUnits( "X coordinate" );
2329  pt.y = parseBoardUnits( "Y coordinate" );
2330  pad->SetPos0( pt );
2331  token = NextTok();
2332 
2333  if( token == T_NUMBER )
2334  {
2335  pad->SetOrientation( parseDouble() * 10.0 );
2336  NeedRIGHT();
2337  }
2338  else if( token != T_RIGHT )
2339  {
2340  Expecting( ") or angle value" );
2341  }
2342 
2343  break;
2344 
2345  case T_rect_delta:
2346  {
2347  wxSize delta;
2348  delta.SetWidth( parseBoardUnits( "rectangle delta width" ) );
2349  delta.SetHeight( parseBoardUnits( "rectangle delta height" ) );
2350  pad->SetDelta( delta );
2351  NeedRIGHT();
2352  }
2353  break;
2354 
2355  case T_drill:
2356  {
2357  bool haveWidth = false;
2358  wxSize drillSize = pad->GetDrillSize();
2359 
2360  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2361  {
2362  if( token == T_LEFT )
2363  token = NextTok();
2364 
2365  switch( token )
2366  {
2367  case T_oval:
2368  pad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG );
2369  break;
2370 
2371  case T_NUMBER:
2372  {
2373  if( !haveWidth )
2374  {
2375  drillSize.SetWidth( parseBoardUnits() );
2376 
2377  // If height is not defined the width and height are the same.
2378  drillSize.SetHeight( drillSize.GetWidth() );
2379  haveWidth = true;
2380  }
2381  else
2382  {
2383  drillSize.SetHeight( parseBoardUnits() );
2384  }
2385 
2386  }
2387  break;
2388 
2389  case T_offset:
2390  pt.x = parseBoardUnits( "drill offset x" );
2391  pt.y = parseBoardUnits( "drill offset y" );
2392  pad->SetOffset( pt );
2393  NeedRIGHT();
2394  break;
2395 
2396  default:
2397  Expecting( "oval, size, or offset" );
2398  }
2399  }
2400 
2401  // This fixes a bug caused by setting the default D_PAD drill size to a value
2402  // other than 0 used to fix a bunch of debug assertions even though it is defined
2403  // as a through hole pad. Wouldn't a though hole pad with no drill be a surface
2404  // mount pad (or a conn pad which is a smd pad with no solder paste)?
2405  if( ( pad->GetAttribute() != PAD_ATTRIB_SMD ) && ( pad->GetAttribute() != PAD_ATTRIB_CONN ) )
2406  pad->SetDrillSize( drillSize );
2407  else
2408  pad->SetDrillSize( wxSize( 0, 0 ) );
2409 
2410  }
2411  break;
2412 
2413  case T_layers:
2414  {
2415  LSET layerMask = parseBoardItemLayersAsMask();
2416  pad->SetLayerSet( layerMask );
2417  }
2418  break;
2419 
2420  case T_net:
2421  if( ! pad->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
2423  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2424  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2425  );
2426  NeedSYMBOLorNUMBER();
2427  if( m_board && FromUTF8() != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
2429  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2430  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2431  );
2432  NeedRIGHT();
2433  break;
2434 
2435  case T_die_length:
2436  pad->SetPadToDieLength( parseBoardUnits( T_die_length ) );
2437  NeedRIGHT();
2438  break;
2439 
2440  case T_solder_mask_margin:
2441  pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) );
2442  NeedRIGHT();
2443  break;
2444 
2445  case T_solder_paste_margin:
2446  pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) );
2447  NeedRIGHT();
2448  break;
2449 
2451  pad->SetLocalSolderPasteMarginRatio(
2452  parseDouble( "pad local solder paste margin ratio value" ) );
2453  NeedRIGHT();
2454  break;
2455 
2456  case T_clearance:
2457  pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
2458  NeedRIGHT();
2459  break;
2460 
2461  case T_zone_connect:
2462  pad->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) );
2463  NeedRIGHT();
2464  break;
2465 
2466  case T_thermal_width:
2467  pad->SetThermalWidth( parseBoardUnits( T_thermal_width ) );
2468  NeedRIGHT();
2469  break;
2470 
2471  case T_thermal_gap:
2472  pad->SetThermalGap( parseBoardUnits( T_thermal_gap ) );
2473  NeedRIGHT();
2474  break;
2475 
2476  case T_roundrect_rratio:
2477  pad->SetRoundRectRadiusRatio( parseDouble( "roundrect radius ratio" ) );
2478  NeedRIGHT();
2479  break;
2480 
2481  default:
2482  Expecting( "at, drill, layers, net, die_length, solder_mask_margin, roundrect_rratio,"
2483  "solder_paste_margin, solder_paste_margin_ratio, clearance, "
2484  "zone_connect, fp_poly, basic_shapes, thermal_width, or thermal_gap" );
2485  }
2486  }
2487 
2488  return pad.release();
2489 }
2490 
2491 
2493 {
2494  wxCHECK_MSG( CurTok() == T_segment, NULL,
2495  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TRACK." ) );
2496 
2497  wxPoint pt;
2498  T token;
2499 
2500  std::unique_ptr< TRACK > track( new TRACK( m_board ) );
2501 
2502  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2503  {
2504  if( token != T_LEFT )
2505  Expecting( T_LEFT );
2506 
2507  token = NextTok();
2508 
2509  switch( token )
2510  {
2511  case T_start:
2512  pt.x = parseBoardUnits( "start x" );
2513  pt.y = parseBoardUnits( "start y" );
2514  track->SetStart( pt );
2515  break;
2516 
2517  case T_end:
2518  pt.x = parseBoardUnits( "end x" );
2519  pt.y = parseBoardUnits( "end y" );
2520  track->SetEnd( pt );
2521  break;
2522 
2523  case T_width:
2524  track->SetWidth( parseBoardUnits( "width" ) );
2525  break;
2526 
2527  case T_layer:
2528  track->SetLayer( parseBoardItemLayer() );
2529  break;
2530 
2531  case T_net:
2532  if( ! track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
2534  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2535  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2536  );
2537  break;
2538 
2539  case T_tstamp:
2540  track->SetTimeStamp( parseHex() );
2541  break;
2542 
2543  case T_status:
2544  track->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2545  break;
2546 
2547  default:
2548  Expecting( "start, end, width, layer, net, tstamp, or status" );
2549  }
2550 
2551  NeedRIGHT();
2552  }
2553 
2554  return track.release();
2555 }
2556 
2557 
2559 {
2560  wxCHECK_MSG( CurTok() == T_via, NULL,
2561  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as VIA." ) );
2562 
2563  wxPoint pt;
2564  T token;
2565 
2566  std::unique_ptr< VIA > via( new VIA( m_board ) );
2567 
2568  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2569  {
2570  if( token == T_LEFT )
2571  token = NextTok();
2572 
2573  switch( token )
2574  {
2575  case T_blind:
2576  via->SetViaType( VIA_BLIND_BURIED );
2577  break;
2578 
2579  case T_micro:
2580  via->SetViaType( VIA_MICROVIA );
2581  break;
2582 
2583  case T_at:
2584  pt.x = parseBoardUnits( "start x" );
2585  pt.y = parseBoardUnits( "start y" );
2586  via->SetStart( pt );
2587  via->SetEnd( pt );
2588  NeedRIGHT();
2589  break;
2590 
2591  case T_size:
2592  via->SetWidth( parseBoardUnits( "via width" ) );
2593  NeedRIGHT();
2594  break;
2595 
2596  case T_drill:
2597  via->SetDrill( parseBoardUnits( "drill diameter" ) );
2598  NeedRIGHT();
2599  break;
2600 
2601  case T_layers:
2602  {
2603  PCB_LAYER_ID layer1, layer2;
2604  NextTok();
2605  layer1 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
2606  NextTok();
2607  layer2 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
2608  via->SetLayerPair( layer1, layer2 );
2609  NeedRIGHT();
2610  }
2611  break;
2612 
2613  case T_net:
2614  if(! via->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true))
2616  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2617  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2618  );
2619  NeedRIGHT();
2620  break;
2621 
2622  case T_tstamp:
2623  via->SetTimeStamp( parseHex() );
2624  NeedRIGHT();
2625  break;
2626 
2627  case T_status:
2628  via->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2629  NeedRIGHT();
2630  break;
2631 
2632  default:
2633  Expecting( "blind, micro, at, size, drill, layers, net, tstamp, or status" );
2634  }
2635  }
2636 
2637  return via.release();
2638 }
2639 
2640 
2642 {
2643  wxCHECK_MSG( CurTok() == T_zone, NULL,
2644  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
2645  wxT( " as ZONE_CONTAINER." ) );
2646 
2648 
2649  int hatchPitch = Mils2iu( ZONE_CONTAINER::GetDefaultHatchPitchMils() );
2650  wxPoint pt;
2651  T token;
2652  int tmp;
2653  wxString netnameFromfile; // the zone net name find in file
2654 
2655  // bigger scope since each filled_polygon is concatenated in here
2656  SHAPE_POLY_SET pts;
2657 
2658  std::unique_ptr< ZONE_CONTAINER > zone( new ZONE_CONTAINER( m_board ) );
2659 
2660  zone->SetPriority( 0 );
2661 
2662  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2663  {
2664  if( token == T_LEFT )
2665  token = NextTok();
2666 
2667  switch( token )
2668  {
2669  case T_net:
2670  // Init the net code only, not the netname, to be sure
2671  // the zone net name is the name read in file.
2672  // (When mismatch, the user will be prompted in DRC, to fix the actual name)
2673  tmp = getNetCode( parseInt( "net number" ) );
2674 
2675  if( tmp < 0 )
2676  tmp = 0;
2677 
2678  if( ! zone->SetNetCode( tmp, /* aNoAssert */ true ) )
2680  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2681  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2682  );
2683 
2684  NeedRIGHT();
2685  break;
2686 
2687  case T_net_name:
2688  NeedSYMBOLorNUMBER();
2689  netnameFromfile = FromUTF8();
2690  NeedRIGHT();
2691  break;
2692 
2693  case T_layer:
2694  zone->SetLayer( parseBoardItemLayer() );
2695  NeedRIGHT();
2696  break;
2697 
2698  case T_tstamp:
2699  zone->SetTimeStamp( parseHex() );
2700  NeedRIGHT();
2701  break;
2702 
2703  case T_hatch:
2704  token = NextTok();
2705 
2706  if( token != T_none && token != T_edge && token != T_full )
2707  Expecting( "none, edge, or full" );
2708 
2709  switch( token )
2710  {
2711  default:
2712  case T_none: hatchStyle = ZONE_CONTAINER::NO_HATCH; break;
2713  case T_edge: hatchStyle = ZONE_CONTAINER::DIAGONAL_EDGE; break;
2714  case T_full: hatchStyle = ZONE_CONTAINER::DIAGONAL_FULL;
2715  }
2716 
2717  hatchPitch = parseBoardUnits( "hatch pitch" );
2718  NeedRIGHT();
2719  break;
2720 
2721  case T_priority:
2722  zone->SetPriority( parseInt( "zone priority" ) );
2723  NeedRIGHT();
2724  break;
2725 
2726  case T_connect_pads:
2727  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2728  {
2729  if( token == T_LEFT )
2730  token = NextTok();
2731 
2732  switch( token )
2733  {
2734  case T_yes:
2735  zone->SetPadConnection( PAD_ZONE_CONN_FULL );
2736  break;
2737 
2738  case T_no:
2739  zone->SetPadConnection( PAD_ZONE_CONN_NONE );
2740  break;
2741 
2742  case T_thru_hole_only:
2743  zone->SetPadConnection( PAD_ZONE_CONN_THT_THERMAL );
2744  break;
2745 
2746  case T_clearance:
2747  zone->SetZoneClearance( parseBoardUnits( "zone clearance" ) );
2748  NeedRIGHT();
2749  break;
2750 
2751  default:
2752  Expecting( "yes, no, or clearance" );
2753  }
2754  }
2755 
2756  break;
2757 
2758  case T_min_thickness:
2759  zone->SetMinThickness( parseBoardUnits( T_min_thickness ) );
2760  NeedRIGHT();
2761  break;
2762 
2763  case T_fill:
2764  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2765  {
2766  if( token == T_LEFT )
2767  token = NextTok();
2768 
2769  switch( token )
2770  {
2771  case T_yes:
2772  zone->SetIsFilled( true );
2773  break;
2774 
2775  case T_mode:
2776  token = NextTok();
2777 
2778  if( token != T_segment && token != T_polygon )
2779  Expecting( "segment or polygon" );
2780 
2781  // @todo Create an enum for fill modes.
2782  zone->SetFillMode( token == T_polygon ? 0 : 1 );
2783  NeedRIGHT();
2784  break;
2785 
2786  case T_arc_segments:
2787  zone->SetArcSegmentCount( parseInt( "arc segment count" ) );
2788  NeedRIGHT();
2789  break;
2790 
2791  case T_thermal_gap:
2792  zone->SetThermalReliefGap( parseBoardUnits( T_thermal_gap ) );
2793  NeedRIGHT();
2794  break;
2795 
2797  zone->SetThermalReliefCopperBridge( parseBoardUnits( T_thermal_bridge_width ) );
2798  NeedRIGHT();
2799  break;
2800 
2801  case T_smoothing:
2802  switch( NextTok() )
2803  {
2804  case T_none:
2805  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_NONE );
2806  break;
2807 
2808  case T_chamfer:
2809  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2810  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_CHAMFER );
2811  break;
2812 
2813  case T_fillet:
2814  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2815  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_FILLET );
2816  break;
2817 
2818  default:
2819  Expecting( "none, chamfer, or fillet" );
2820  }
2821  NeedRIGHT();
2822  break;
2823 
2824  case T_radius:
2825  tmp = parseBoardUnits( "corner radius" );
2826  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2827  zone->SetCornerRadius( tmp );
2828  NeedRIGHT();
2829  break;
2830 
2831  default:
2832  Expecting( "mode, arc_segments, thermal_gap, thermal_bridge_width, "
2833  "smoothing, or radius" );
2834  }
2835  }
2836  break;
2837 
2838  case T_keepout:
2839  zone->SetIsKeepout( true );
2840 
2841  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2842  {
2843  if( token == T_LEFT )
2844  token = NextTok();
2845 
2846  switch( token )
2847  {
2848  case T_tracks:
2849  token = NextTok();
2850 
2851  if( token != T_allowed && token != T_not_allowed )
2852  Expecting( "allowed or not_allowed" );
2853  zone->SetDoNotAllowTracks( token == T_not_allowed );
2854  break;
2855 
2856  case T_vias:
2857  token = NextTok();
2858 
2859  if( token != T_allowed && token != T_not_allowed )
2860  Expecting( "allowed or not_allowed" );
2861  zone->SetDoNotAllowVias( token == T_not_allowed );
2862  break;
2863 
2864  case T_copperpour:
2865  token = NextTok();
2866 
2867  if( token != T_allowed && token != T_not_allowed )
2868  Expecting( "allowed or not_allowed" );
2869  zone->SetDoNotAllowCopperPour( token == T_not_allowed );
2870  break;
2871 
2872  default:
2873  Expecting( "tracks, vias or copperpour" );
2874  }
2875 
2876  NeedRIGHT();
2877  }
2878 
2879  break;
2880 
2881  case T_polygon:
2882  {
2883  std::vector< wxPoint > corners;
2884 
2885  NeedLEFT();
2886  token = NextTok();
2887 
2888  if( token != T_pts )
2889  Expecting( T_pts );
2890 
2891  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2892  {
2893  corners.push_back( parseXY() );
2894  }
2895 
2896  NeedRIGHT();
2897 
2898  // Remark: The first polygon is the main outline.
2899  // Others are holes inside the main outline.
2900  zone->AddPolygon( corners );
2901  }
2902  break;
2903 
2904  case T_filled_polygon:
2905  {
2906  // "(filled_polygon (pts"
2907  NeedLEFT();
2908  token = NextTok();
2909 
2910  if( token != T_pts )
2911  Expecting( T_pts );
2912 
2913  pts.NewOutline();
2914 
2915  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2916  {
2917  pts.Append( parseXY() );
2918  }
2919 
2920  NeedRIGHT();
2921  }
2922  break;
2923 
2924  case T_fill_segments:
2925  {
2926  std::vector< SEGMENT > segs;
2927 
2928  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2929  {
2930  if( token != T_LEFT )
2931  Expecting( T_LEFT );
2932 
2933  token = NextTok();
2934 
2935  if( token != T_pts )
2936  Expecting( T_pts );
2937 
2938  SEGMENT segment( parseXY(), parseXY() );
2939  NeedRIGHT();
2940  segs.push_back( segment );
2941  }
2942 
2943  zone->AddFillSegments( segs );
2944  }
2945  break;
2946 
2947  default:
2948  Expecting( "net, layer, tstamp, hatch, priority, connect_pads, min_thickness, "
2949  "fill, polygon, filled_polygon, or fill_segments" );
2950  }
2951  }
2952 
2953  if( zone->GetNumCorners() > 2 )
2954  {
2955  if( !zone->IsOnCopperLayer() )
2956  {
2957  zone->SetFillMode( 0 );
2958  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
2959  }
2960 
2961  // Set hatch here, after outlines corners are read
2962  zone->SetHatch( hatchStyle, hatchPitch, true );
2963  }
2964 
2965  if( !pts.IsEmpty() )
2966  zone->AddFilledPolysList( pts );
2967 
2968  // Ensure keepout and non copper zones do not have a net
2969  // (which have no sense for these zones)
2970  // the netcode 0 is used for these zones
2971  bool zone_has_net = zone->IsOnCopperLayer() && !zone->GetIsKeepout();
2972 
2973  if( !zone_has_net )
2974  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
2975 
2976  // Ensure the zone net name is valid, and matches the net code, for copper zones
2977  if( zone_has_net && ( zone->GetNet()->GetNetname() != netnameFromfile ) )
2978  {
2979  // Can happens which old boards, with nonexistent nets ...
2980  // or after being edited by hand
2981  // We try to fix the mismatch.
2982  NETINFO_ITEM* net = m_board->FindNet( netnameFromfile );
2983 
2984  if( net ) // An existing net has the same net name. use it for the zone
2985  zone->SetNetCode( net->GetNet() );
2986  else // Not existing net: add a new net to keep trace of the zone netname
2987  {
2988  int newnetcode = m_board->GetNetCount();
2989  net = new NETINFO_ITEM( m_board, netnameFromfile, newnetcode );
2990  m_board->Add( net );
2991 
2992  // Store the new code mapping
2993  pushValueIntoMap( newnetcode, net->GetNet() );
2994  // and update the zone netcode
2995  zone->SetNetCode( net->GetNet() );
2996 
2997  // Prompt the user
2998  wxString msg;
2999  msg.Printf( _( "There is a zone that belongs to a not existing net\n"
3000  "\"%s\"\n"
3001  "you should verify and edit it (run DRC test)." ),
3002  GetChars( netnameFromfile ) );
3003  DisplayError( NULL, msg );
3004  }
3005  }
3006 
3007  return zone.release();
3008 }
3009 
3010 
3012 {
3013  wxCHECK_MSG( CurTok() == T_target, NULL,
3014  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) );
3015 
3016  wxPoint pt;
3017  T token;
3018 
3019  std::unique_ptr< PCB_TARGET > target( new PCB_TARGET( NULL ) );
3020 
3021  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3022  {
3023  if( token == T_LEFT )
3024  token = NextTok();
3025 
3026  switch( token )
3027  {
3028  case T_x:
3029  target->SetShape( 1 );
3030  break;
3031 
3032  case T_plus:
3033  target->SetShape( 0 );
3034  break;
3035 
3036  case T_at:
3037  pt.x = parseBoardUnits( "target x position" );
3038  pt.y = parseBoardUnits( "target y position" );
3039  target->SetPosition( pt );
3040  NeedRIGHT();
3041  break;
3042 
3043  case T_size:
3044  target->SetSize( parseBoardUnits( "target size" ) );
3045  NeedRIGHT();
3046  break;
3047 
3048  case T_width:
3049  target->SetWidth( parseBoardUnits( "target thickness" ) );
3050  NeedRIGHT();
3051  break;
3052 
3053  case T_layer:
3054  target->SetLayer( parseBoardItemLayer() );
3055  NeedRIGHT();
3056  break;
3057 
3058  case T_tstamp:
3059  target->SetTimeStamp( parseHex() );
3060  NeedRIGHT();
3061  break;
3062 
3063  default:
3064  Expecting( "x, plus, at, size, width, layer or tstamp" );
3065  }
3066  }
3067 
3068  return target.release();
3069 }
void SetComment1(const wxString &aComment)
void parseHeader()
Definition: pcb_parser.cpp:550
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:639
int parseVersion()
Parse a format version tag like (version 20160417) return the version.
Definition: pcb_parser.cpp:169
Class UTF8 is an 8 bit std::string that is assuredly encoded in UTF8, and supplies special conversion...
Definition: utf8.h:53
int Mm2mils(double x)
Convert mm to mils.
Definition: base_units.h:41
int m_SolderMaskMargin
Solder mask margin.
Struct VIA_DIMENSION is a small helper container to handle a stock of specific vias each with unique ...
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
LSET parseBoardItemLayersAsMask()
Function parseBoardItemLayersAsMask parses the layers definition of a BOARD_ITEM object.
Definition: pcb_parser.cpp:973
PCB_TARGET class definition.
double x
Definition: sg_base.h:70
wxPoint m_GridOrigin
origin for grid offsets
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
const wxPoint & GetTextPos() const
Definition: eda_text.h:224
wxString m_name
The name of the layer, there should be no spaces in this name.
Definition: class_board.h:108
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:63
int m_SolderPasteMargin
Solder paste margin absolute value.
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
This file is part of the common library.
Class PCB_PLOT_PARAMS_PARSER is the parser class for PCB_PLOT_PARAMS.
int m_ModuleTextWidth
Default footprint texts thickness.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
std::vector< int > m_TrackWidthList
Track width list.
S3D_INFO * parse3DModel()
Definition: pcb_parser.cpp:335
void SetRevision(const wxString &aRevision)
int m_ModuleSegmentWidth
Default width for all graphic lines.
TEXT_TYPE GetType() const
TRACK * parseTRACK()
VIA * parseVIA()
int m_PcbTextWidth
current Pcb (not module) Text width
Class BOARD to handle a board.
LAYER_T m_type
The type of the layer.
Definition: class_board.h:110
ZoneConnection
How pads are covered by copper in zone.
Definition: zones.h:55
polygon (not yet used for tracks, but could be in microwave apps)
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:59
wxPoint parseXY()
Function parseXY parses a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:206
void parseNETINFO_ITEM()
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:76
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
BOARD * parseBOARD()
Definition: pcb_parser.cpp:444
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:169
void SetDate(const wxString &aDate)
Function SetDate sets the date field, and defaults to the current time and date.
Classes to handle copper zones.
const wxPoint & GetPos0() const
Definition: class_pad.h:176
int Parse(const UTF8 &aId)
Function Parse.
Definition: lib_id.cpp:122
void parseEDA_TEXT(EDA_TEXT *aText)
Function parseEDA_TEXT parses the common settings for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:238
static const wxChar Custom[]
"User" defined page type
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:187
DIMENSION * parseDIMENSION()
void parseTITLE_BLOCK()
Definition: pcb_parser.cpp:687
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
double y
Definition: sg_base.h:71
SGPOINT m_Offset
an offset (unit = inch) for the 3D shape
Definition: 3d_info.h:44
Class LIB_ID.
Definition: lib_id.h:56
wxSize m_ModuleTextSize
Default footprint texts size.
#define cu(a)
Definition: auxiliary.h:88
Class TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout, or editing view.
static const int delta[8][2]
Definition: solve.cpp:112
void parseLayers()
Definition: pcb_parser.cpp:812
double GetTextAngle() const
Definition: eda_text.h:164
Functions relatives to tracks, vias and segments used to fill zones.
void SetComment4(const wxString &aComment)
This file contains miscellaneous commonly used macros and functions.
Pads are not covered.
Definition: zones.h:57
Class EDA_TEXT is a mix-in class (via multiple inheritance) that handles texts such as labels...
Definition: eda_text.h:114
void parsePAGE_INFO()
Definition: pcb_parser.cpp:631
int StrPrintf(std::string *result, const char *format,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:75
static double parseDouble(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseDouble.
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
bool parseBool()
Definition: pcb_parser.cpp:154
DIMENSION class definition.
PCB_LAYER_ID
A quick note on layer IDs:
wxString GetRequiredVersion()
Return a string representing the version of kicad required to open this file.
Definition: pcb_parser.cpp:182
Class LSET is a set of PCB_LAYER_IDs.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:133
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Function Name returns the fixed name association with aLayerId.
Definition: lset.cpp:73
#define MIN_VISIBILITY_MASK
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:213
Class SHAPE_POLY_SET.
wxSize m_PcbTextSize
current Pcb (not module) Text size
C++ does not put enum values in separate namespaces unless the enum itself is in a separate namespace...
Definition: pcb_lexer.h:23
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
int m_TrackMinWidth
track min value for width ((min copper size value
Arcs (with rounded ends)
int m_ViasMinSize
vias (not micro vias) min diameter
void SetNetCode(int aNetCode)
MODULE * parseMODULE_unchecked(wxArrayString *aInitialComments=0)
Function parseMODULE_unchecked Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERRO...
DRAWSEGMENT * parseDRAWSEGMENT()
int m_DrawSegmentWidth
current graphic line width (not EDGE layer)
PCB_TARGET * parsePCB_TARGET()
int m_ViasMinDrill
vias (not micro vias) min drill diameter
PCB_LAYER_ID parseBoardItemLayer()
Function parseBoardItemLayer parses the layer definition of a BOARD_ITEM object.
Definition: pcb_parser.cpp:958
void SetCompany(const wxString &aCompany)
bool m_visible
Definition: class_board.h:112
void SetSize(const wxSize &aSize)
Definition: class_pad.h:181
static unsigned long parseHex(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseHex.
int m_ZoneClearance
Clearance value.
TEXTE_PCB * parseTEXTE_PCB()
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
bool SetType(const wxString &aStandardPageDescriptionName, bool IsPortrait=false)
Function SetType sets the name of the page type and also the sizes and margins commonly associated wi...
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
HATCH_STYLE
Zone hatch styles.
Definition: class_zone.h:85
Bezier Curve.
int GetNet() const
Function GetNet.
static LAYER_T ParseType(const char *aType)
Function ParseType converts a string to a LAYER_T.
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:405
void SetTitle(const wxString &aTitle)
int m_MicroViasMinSize
micro vias (not vias) min diameter
Class PCB_PLOT_PARAMS handles plot parameters and options when plotting/printing a board...
void parseNETCLASS()
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:60
int NewOutline()
Creates a new empty polygon in the set and returns its index
void SetPortrait(bool isPortrait)
Function SetPortrait will rotate the paper page 90 degrees.
void SetHeightMils(int aHeightInMils)
Thermal relief only for THT pads.
Definition: zones.h:60
Pad object description.
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
Class ZONE_SETTINGS handles zones parameters.
BOARD * parseBOARD_unchecked()
Function parseBOARD_unchecked Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR...
Definition: pcb_parser.cpp:460
ZONE_CONTAINER * parseZONE_CONTAINER()
void parseLayer(LAYER *aLayer)
Definition: pcb_parser.cpp:770
virtual void SetPosition(const wxPoint &aPos) override
Class NETINFO_ITEM handles the data for a net.
void SetComment2(const wxString &aComment)
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller's report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:94
T
enum T contains all this lexer's tokens.
Definition: pcb_lexer.h:26
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
bool SyncLineReaderWith(DSNLEXER &aLexer)
Useable only for DSN lexers which share the same LINE_READER Synchronizes the pointers handling the d...
Definition: dsnlexer.cpp:169
EDGE_MODULE * parseEDGE_MODULE()
Class to handle a graphic segment.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
#define max(a, b)
Definition: auxiliary.h:86
Class LAYER holds information pertinent to a layer of a BOARD.
Definition: class_board.h:82
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:166
Virtual component: when created by copper shapes on board (Like edge card connectors, mounting hole...)
Definition: class_module.h:78
void parseGeneralSection()
Definition: pcb_parser.cpp:586
SGPOINT m_Rotation
an X,Y,Z rotation (unit = degrees) for the 3D shape
Definition: 3d_info.h:43
void init()
Function init clears and re-establishes m_layerMap with the default layer names.
Definition: pcb_parser.cpp:56
void SetWidthMils(int aWidthInMils)
void SetDrawCoord()
Set absolute coordinates.
D_PAD m_Pad_Master
A dummy pad to store all default parameters.
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
double z
Definition: sg_base.h:72
Usual pad.
Definition: pad_shapes.h:58
void SetVisibleElements(int aMask)
Function SetVisibleElements changes the bit-mask of visible element categories.
void pushValueIntoMap(int aIndex, int aValue)
function pushValueIntoMap Add aValue value in netcode mapping (m_netCodes) at index aIndex ensure the...
Definition: pcb_parser.cpp:113
The common library.
std::vector< VIA_DIMENSION > m_ViasDimensionsList
Vias size and drill list.
double parseDouble()
Function parseDouble parses the current token as an ASCII numeric string with possible leading whites...
Definition: pcb_parser.cpp:124
const char * name
const char * GetTokenText(T aTok)
Function GetTokenText is in the DSN namespace and returns the C string representing a SPECCTRA_DB::ke...
Definition: specctra.cpp:69
Struct SEGMENT is a simple container used when filling areas with segments.
Definition: class_zone.h:57
static int GetDefaultHatchPitchMils()
Function GetDefaultHatchPitchMils.
Definition: class_zone.h:680
Pcbnew s-expression file format parser definition.
void SetTextAngle(double aAngle)
SGPOINT m_Scale
scaling factors for the 3D footprint shape
Definition: 3d_info.h:42
Struct FUTURE_FORMAT_ERROR variant of PARSE_ERROR indicating that a syntax or related error was likel...
Definition: ki_exception.h:143
Module description (excepted pads)
void SetComment3(const wxString &aComment)
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
bool m_MicroViasAllowed
true to allow micro vias
TEXTE_MODULE * parseTEXTE_MODULE()
int m_number
Definition: class_board.h:114
D_PAD * parseD_PAD(MODULE *aParent=NULL)
MODULE * parseMODULE(wxArrayString *aInitialComments=0)
Function parseMODULE.
int m_MicroViasMinDrill
micro vias (not vias) min drill diameter
int m_EdgeSegmentWidth
current graphic line width (EDGE layer only)
double m_SolderPasteMarginRatio
Solder pask margin ratio value of pad size The final margin is the sum of these 2 values...
EDGE_MODULE class definition.
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:69
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
wxPoint m_AuxOrigin
origin for plot exports
Class DIMENSION.
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:73
void parseSetup()
Definition: pcb_parser.cpp:991
T lookUpLayer(const M &aMap)
Function lookUpLayer parses the current token for the layer definition of a BOARD_ITEM object...
Definition: pcb_parser.cpp:925
int m_SolderMaskMinWidth
Solder mask min width.
pads are covered by copper
Definition: zones.h:59
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
wxString m_Filename
The 3D shape filename in 3D library.
Definition: 3d_info.h:45
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline) ...