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_pcb_target.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 )
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:
299  break;
300 
301  case T_right:
303  break;
304 
305  case T_top:
307  break;
308 
309  case T_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 MODULE_3D_SETTINGS." ) );
339 
340  T token;
341 
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  /* Note:
363  * Prior to SEXPR_BOARD_FILE_VERSION 20171114,
364  * 3D model offset was read and written in inches
365  *
366  * Now, the offset is explicitly written in mm.
367  * If a board is read with an older version,
368  * the offset is converted from inches to mm
369  */
370 
371  n3D->m_Offset.x = parseDouble( "x value" );
372  n3D->m_Offset.y = parseDouble( "y value" );
373  n3D->m_Offset.z = parseDouble( "z value" );
374 
375  if(m_requiredVersion < 20171114L)
376  {
377  n3D->m_Offset.x *= 25.4f;
378  n3D->m_Offset.y *= 25.4f;
379  n3D->m_Offset.z *= 25.4f;
380  }
381 
382  NeedRIGHT();
383  break;
384 
385  case T_scale:
386  NeedLEFT();
387  token = NextTok();
388 
389  if( token != T_xyz )
390  Expecting( T_xyz );
391 
392  n3D->m_Scale.x = parseDouble( "x value" );
393  n3D->m_Scale.y = parseDouble( "y value" );
394  n3D->m_Scale.z = parseDouble( "z value" );
395  NeedRIGHT();
396  break;
397 
398  case T_rotate:
399  NeedLEFT();
400  token = NextTok();
401 
402  if( token != T_xyz )
403  Expecting( T_xyz );
404 
405  n3D->m_Rotation.x = parseDouble( "x value" );
406  n3D->m_Rotation.y = parseDouble( "y value" );
407  n3D->m_Rotation.z = parseDouble( "z value" );
408  NeedRIGHT();
409  break;
410 
411  default:
412  Expecting( "at, scale, or rotate" );
413  }
414 
415  NeedRIGHT();
416  }
417 
418  return n3D;
419 }
420 
421 
423 {
424  T token;
425  BOARD_ITEM* item;
426  LOCALE_IO toggle;
427 
428  // MODULEs can be prefixed with an initial block of single line comments and these
429  // are kept for Format() so they round trip in s-expression form. BOARDs might
430  // eventually do the same, but currently do not.
431  std::unique_ptr<wxArrayString> initial_comments( ReadCommentLines() );
432 
433  token = CurTok();
434 
435  if( token != T_LEFT )
436  Expecting( T_LEFT );
437 
438  switch( NextTok() )
439  {
440  case T_kicad_pcb:
441  if( m_board == NULL )
442  m_board = new BOARD();
443 
444  item = (BOARD_ITEM*) parseBOARD();
445  break;
446 
447  case T_module:
448  item = (BOARD_ITEM*) parseMODULE( initial_comments.release() );
449  break;
450 
451  default:
452  wxString err;
453  err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) );
454  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
455  }
456 
457  return item;
458 }
459 
460 
462 {
463  try
464  {
465  return parseBOARD_unchecked();
466  }
467  catch( const PARSE_ERROR& parse_error )
468  {
469  if( m_tooRecent )
470  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
471  else
472  throw;
473  }
474 }
475 
476 
478 {
479  T token;
480 
481  parseHeader();
482 
483  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
484  {
485  if( token != T_LEFT )
486  Expecting( T_LEFT );
487 
488  token = NextTok();
489 
490  switch( token )
491  {
492  case T_general:
493  parseGeneralSection();
494  break;
495 
496  case T_page:
497  parsePAGE_INFO();
498  break;
499 
500  case T_title_block:
501  parseTITLE_BLOCK();
502  break;
503 
504  case T_layers:
505  parseLayers();
506  break;
507 
508  case T_setup:
509  parseSetup();
510  break;
511 
512  case T_net:
513  parseNETINFO_ITEM();
514  break;
515 
516  case T_net_class:
517  parseNETCLASS();
518  break;
519 
520  case T_gr_arc:
521  case T_gr_circle:
522  case T_gr_curve:
523  case T_gr_line:
524  case T_gr_poly:
525  m_board->Add( parseDRAWSEGMENT(), ADD_APPEND );
526  break;
527 
528  case T_gr_text:
529  m_board->Add( parseTEXTE_PCB(), ADD_APPEND );
530  break;
531 
532  case T_dimension:
533  m_board->Add( parseDIMENSION(), ADD_APPEND );
534  break;
535 
536  case T_module:
537  m_board->Add( parseMODULE(), ADD_APPEND );
538  break;
539 
540  case T_segment:
541  m_board->Add( parseTRACK(), ADD_APPEND );
542  break;
543 
544  case T_via:
545  m_board->Add( parseVIA(), ADD_APPEND );
546  break;
547 
548  case T_zone:
549  m_board->Add( parseZONE_CONTAINER(), ADD_APPEND );
550  break;
551 
552  case T_target:
553  m_board->Add( parsePCB_TARGET(), ADD_APPEND );
554  break;
555 
556  default:
557  wxString err;
558  err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) );
559  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
560  }
561  }
562 
563  return m_board;
564 }
565 
566 
568 {
569  wxCHECK_RET( CurTok() == T_kicad_pcb,
570  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
571 
572  NeedLEFT();
573 
574  T tok = NextTok();
575  if( tok == T_version )
576  {
577  m_requiredVersion = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
578  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
579  NeedRIGHT();
580 
581  // Skip the host name and host build version information.
582  NeedLEFT();
583  NeedSYMBOL();
584  NeedSYMBOL();
585  NeedSYMBOL();
586  NeedRIGHT();
587  }
588  else
589  {
590  m_requiredVersion = SEXPR_BOARD_FILE_VERSION;
591  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
592 
593  // Skip the host name and host build version information.
594  NeedSYMBOL();
595  NeedSYMBOL();
596  NeedRIGHT();
597  }
598 
599  m_board->SetFileFormatVersionAtLoad( m_requiredVersion );
600 }
601 
602 
604 {
605  wxCHECK_RET( CurTok() == T_general,
606  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
607  wxT( " as a general section." ) );
608 
609  T token;
610 
611  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
612  {
613  if( token != T_LEFT )
614  Expecting( T_LEFT );
615 
616  token = NextTok();
617 
618  switch( token )
619  {
620  case T_thickness:
621  m_board->GetDesignSettings().SetBoardThickness( parseBoardUnits( T_thickness ) );
622  NeedRIGHT();
623  break;
624 
625  case T_nets:
626  m_netCodes.resize( parseInt( "nets number" ) );
627  NeedRIGHT();
628  break;
629 
630  case T_no_connects:
631  // ignore
632  parseInt( "no connect count" );
633  NeedRIGHT();
634  break;
635 
636  default: // Skip everything but the board thickness.
637  //wxLogDebug( wxT( "Skipping general section token %s " ), GetChars( GetTokenString( token ) ) );
638 
639  while( ( token = NextTok() ) != T_RIGHT )
640  {
641  if( !IsSymbol( token ) && token != T_NUMBER )
642  Expecting( "symbol or number" );
643  }
644  }
645  }
646 }
647 
648 
650 {
651  wxCHECK_RET( CurTok() == T_page,
652  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) );
653 
654  T token;
655  PAGE_INFO pageInfo;
656 
657  NeedSYMBOL();
658 
659  wxString pageType = FromUTF8();
660 
661  if( !pageInfo.SetType( pageType ) )
662  {
663  wxString err;
664  err.Printf( _( "page type \"%s\" is not valid " ), GetChars( FromUTF8() ) );
665  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
666  }
667 
668  if( pageType == PAGE_INFO::Custom )
669  {
670  double width = parseDouble( "width" ); // width in mm
671 
672  // Perform some controls to avoid crashes if the size is edited by hands
673  if( width < 100.0 )
674  width = 100.0;
675  else if( width > 1200.0 )
676  width = 1200.0;
677 
678  double height = parseDouble( "height" ); // height in mm
679 
680  if( height < 100.0 )
681  height = 100.0;
682  else if( height > 1200.0 )
683  height = 1200.0;
684 
685  pageInfo.SetWidthMils( Mm2mils( width ) );
686  pageInfo.SetHeightMils( Mm2mils( height ) );
687  }
688 
689  token = NextTok();
690 
691  if( token == T_portrait )
692  {
693  pageInfo.SetPortrait( true );
694  NeedRIGHT();
695  }
696  else if( token != T_RIGHT )
697  {
698  Expecting( "portrait|)" );
699  }
700 
701  m_board->SetPageSettings( pageInfo );
702 }
703 
704 
706 {
707  wxCHECK_RET( CurTok() == T_title_block,
708  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
709  wxT( " as TITLE_BLOCK." ) );
710 
711  T token;
712  TITLE_BLOCK titleBlock;
713 
714  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
715  {
716  if( token != T_LEFT )
717  Expecting( T_LEFT );
718 
719  token = NextTok();
720 
721  switch( token )
722  {
723  case T_title:
724  NextTok();
725  titleBlock.SetTitle( FromUTF8() );
726  break;
727 
728  case T_date:
729  NextTok();
730  titleBlock.SetDate( FromUTF8() );
731  break;
732 
733  case T_rev:
734  NextTok();
735  titleBlock.SetRevision( FromUTF8() );
736  break;
737 
738  case T_company:
739  NextTok();
740  titleBlock.SetCompany( FromUTF8() );
741  break;
742 
743  case T_comment:
744  {
745  int commentNumber = parseInt( "comment" );
746 
747  switch( commentNumber )
748  {
749  case 1:
750  NextTok();
751  titleBlock.SetComment1( FromUTF8() );
752  break;
753 
754  case 2:
755  NextTok();
756  titleBlock.SetComment2( FromUTF8() );
757  break;
758 
759  case 3:
760  NextTok();
761  titleBlock.SetComment3( FromUTF8() );
762  break;
763 
764  case 4:
765  NextTok();
766  titleBlock.SetComment4( FromUTF8() );
767  break;
768 
769  default:
770  wxString err;
771  err.Printf( wxT( "%d is not a valid title block comment number" ), commentNumber );
772  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
773  }
774  }
775  break;
776 
777  default:
778  Expecting( "title, date, rev, company, or comment" );
779  }
780 
781  NeedRIGHT();
782  }
783 
784  m_board->SetTitleBlock( titleBlock );
785 }
786 
787 
789 {
790  T token;
791 
792  std::string name;
793  std::string type;
794  bool isVisible = true;
795 
796  aLayer->clear();
797 
798  if( CurTok() != T_LEFT )
799  Expecting( T_LEFT );
800 
801  // this layer_num is not used, we DO depend on LAYER_T however.
802  LAYER_NUM layer_num = parseInt( "layer index" );
803 
804  NeedSYMBOLorNUMBER();
805  name = CurText();
806 
807  NeedSYMBOL();
808  type = CurText();
809 
810  token = NextTok();
811 
812  if( token == T_hide )
813  {
814  isVisible = false;
815  NeedRIGHT();
816  }
817  else if( token != T_RIGHT )
818  {
819  Expecting( "hide or )" );
820  }
821 
822  aLayer->m_name = FROM_UTF8( name.c_str() );
823  aLayer->m_type = LAYER::ParseType( type.c_str() );
824  aLayer->m_number = layer_num;
825  aLayer->m_visible = isVisible;
826 }
827 
828 
829 
831 {
832  wxCHECK_RET( CurTok() == T_layers,
833  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) );
834 
835  T token;
836  LSET visibleLayers;
837  LSET enabledLayers;
838  int copperLayerCount = 0;
839  LAYER layer;
840 
841  std::vector<LAYER> cu;
842 
843  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
844  {
845  parseLayer( &layer );
846 
847  if( layer.m_type == LT_UNDEFINED ) // it's a non-copper layer
848  break;
849 
850  cu.push_back( layer ); // it's copper
851  }
852 
853  // All Cu layers are parsed, but not the non-cu layers here.
854 
855  // The original *.kicad_pcb file format and the inverted
856  // Cu stack format both have all the Cu layers first, so use this
857  // trick to handle either. The layer number in the (layers ..)
858  // s-expression element are ignored.
859  if( cu.size() )
860  {
861  // Rework the layer numbers, which changed when the Cu stack
862  // was flipped. So we instead use position in the list.
863  cu[cu.size()-1].m_number = B_Cu;
864 
865  for( unsigned i=0; i < cu.size()-1; ++i )
866  {
867  cu[i].m_number = i;
868  }
869 
870  for( std::vector<LAYER>::const_iterator it = cu.begin(); it<cu.end(); ++it )
871  {
872  enabledLayers.set( it->m_number );
873 
874  if( it->m_visible )
875  visibleLayers.set( it->m_number );
876 
877  m_board->SetLayerDescr( PCB_LAYER_ID( it->m_number ), *it );
878 
879  UTF8 name = it->m_name;
880 
881  m_layerIndices[ name ] = PCB_LAYER_ID( it->m_number );
882  m_layerMasks[ name ] = LSET( PCB_LAYER_ID( it->m_number ) );
883  }
884 
885  copperLayerCount = cu.size();
886  }
887 
888  // process non-copper layers
889  while( token != T_RIGHT )
890  {
891  LAYER_ID_MAP::const_iterator it = m_layerIndices.find( UTF8( layer.m_name ) );
892 
893  if( it == m_layerIndices.end() )
894  {
895  wxString error = wxString::Format(
896  _( "Layer '%s' in file '%s' at line %d, is not in fixed layer hash" ),
897  GetChars( layer.m_name ),
898  GetChars( CurSource() ),
899  CurLineNumber(),
900  CurOffset()
901  );
902 
903  THROW_IO_ERROR( error );
904  }
905 
906  layer.m_number = it->second;
907 
908  enabledLayers.set( layer.m_number );
909 
910  if( layer.m_visible )
911  visibleLayers.set( layer.m_number );
912 
913  // DBG( printf( "aux m_visible:%s\n", layer.m_visible ? "true" : "false" );)
914 
915  m_board->SetLayerDescr( it->second, layer );
916 
917  token = NextTok();
918 
919  if( token != T_LEFT )
920  break;
921 
922  parseLayer( &layer );
923  }
924 
925  // We need at least 2 copper layers and there must be an even number of them.
926  if( copperLayerCount < 2 || (copperLayerCount % 2) != 0 )
927  {
928  wxString err = wxString::Format(
929  _( "%d is not a valid layer count" ), copperLayerCount );
930 
931  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
932  }
933 
934  m_board->SetCopperLayerCount( copperLayerCount );
935  m_board->SetEnabledLayers( enabledLayers );
936 
937  // call SetEnabledLayers before SetVisibleLayers()
938  m_board->SetVisibleLayers( visibleLayers );
939 }
940 
941 
942 template<class T, class M>
943 T PCB_PARSER::lookUpLayer( const M& aMap )
944 {
945  // avoid constructing another std::string, use lexer's directly
946  typename M::const_iterator it = aMap.find( curText );
947 
948  if( it == aMap.end() )
949  {
950 #if 0 && defined(DEBUG)
951  // dump the whole darn table, there's something wrong with it.
952  for( it = aMap.begin(); it != aMap.end(); ++it )
953  {
954  wxLogDebug( &aMap == (void*)&m_layerIndices ? wxT( "lm[%s] = %d" ) :
955  wxT( "lm[%s] = %08X" ), it->first.c_str(), it->second );
956  }
957 #endif
958 
959  wxString error = wxString::Format( _(
960  "Layer '%s' in file\n"
961  "'%s'\n"
962  "at line %d, position %d\n"
963  "was not defined in the layers section"
964  ),
965  GetChars( FROM_UTF8( CurText() ) ),
966  GetChars( CurSource() ),
967  CurLineNumber(), CurOffset() );
968 
969  THROW_IO_ERROR( error );
970  }
971 
972  return it->second;
973 }
974 
975 
977 {
978  wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER,
979  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) );
980 
981  NextTok();
982 
983  PCB_LAYER_ID layerIndex = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
984 
985  // Handle closing ) in object parser.
986 
987  return layerIndex;
988 }
989 
990 
992 {
993  wxCHECK_MSG( CurTok() == T_layers, LSET(),
994  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
995  wxT( " as item layer mask." ) );
996 
997  LSET layerMask;
998 
999  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
1000  {
1001  LSET mask = lookUpLayer<LSET>( m_layerMasks );
1002  layerMask |= mask;
1003  }
1004 
1005  return layerMask;
1006 }
1007 
1008 
1010 {
1011  wxCHECK_RET( CurTok() == T_setup,
1012  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
1013 
1014  T token;
1015  NETCLASSPTR defaultNetClass = m_board->GetDesignSettings().GetDefault();
1016  // TODO Orson: is it really necessary to first operate on a copy and then apply it?
1017  // would not it be better to use reference here and apply all the changes instantly?
1018  BOARD_DESIGN_SETTINGS designSettings = m_board->GetDesignSettings();
1019  ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings();
1020 
1021  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1022  {
1023  if( token != T_LEFT )
1024  Expecting( T_LEFT );
1025 
1026  token = NextTok();
1027 
1028  switch( token )
1029  {
1030  case T_last_trace_width: // not used now
1031  /* lastTraceWidth =*/ parseBoardUnits( T_last_trace_width );
1032  NeedRIGHT();
1033  break;
1034 
1035  case T_user_trace_width:
1036  designSettings.m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) );
1037  NeedRIGHT();
1038  break;
1039 
1040  case T_trace_clearance:
1041  defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) );
1042  NeedRIGHT();
1043  break;
1044 
1045  case T_zone_clearance:
1046  zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance );
1047  NeedRIGHT();
1048  break;
1049 
1050  case T_zone_45_only:
1051  zoneSettings.m_Zone_45_Only = parseBool();
1052  NeedRIGHT();
1053  break;
1054 
1055  case T_trace_min:
1056  designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min );
1057  NeedRIGHT();
1058  break;
1059 
1060  case T_segment_width:
1061  designSettings.m_DrawSegmentWidth = parseBoardUnits( T_segment_width );
1062  NeedRIGHT();
1063  break;
1064 
1065  case T_edge_width:
1066  designSettings.m_EdgeSegmentWidth = parseBoardUnits( T_edge_width );
1067  NeedRIGHT();
1068  break;
1069 
1070  case T_via_size:
1071  defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) );
1072  NeedRIGHT();
1073  break;
1074 
1075  case T_via_drill:
1076  defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) );
1077  NeedRIGHT();
1078  break;
1079 
1080  case T_via_min_size:
1081  designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size );
1082  NeedRIGHT();
1083  break;
1084 
1085  case T_via_min_drill:
1086  designSettings.m_ViasMinDrill = parseBoardUnits( T_via_min_drill );
1087  NeedRIGHT();
1088  break;
1089 
1090  case T_user_via:
1091  {
1092  int viaSize = parseBoardUnits( "user via size" );
1093  int viaDrill = parseBoardUnits( "user via drill" );
1094  designSettings.m_ViasDimensionsList.push_back( VIA_DIMENSION( viaSize, viaDrill ) );
1095  NeedRIGHT();
1096  }
1097  break;
1098 
1099  case T_uvia_size:
1100  defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) );
1101  NeedRIGHT();
1102  break;
1103 
1104  case T_uvia_drill:
1105  defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1106  NeedRIGHT();
1107  break;
1108 
1109  case T_uvias_allowed:
1110  designSettings.m_MicroViasAllowed = parseBool();
1111  NeedRIGHT();
1112  break;
1113 
1115  designSettings.m_BlindBuriedViaAllowed = parseBool();
1116  NeedRIGHT();
1117  break;
1118 
1119  case T_uvia_min_size:
1120  designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size );
1121  NeedRIGHT();
1122  break;
1123 
1124  case T_uvia_min_drill:
1125  designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill );
1126  NeedRIGHT();
1127  break;
1128 
1129  case T_pcb_text_width:
1130  designSettings.m_PcbTextWidth = parseBoardUnits( T_pcb_text_width );
1131  NeedRIGHT();
1132  break;
1133 
1134  case T_pcb_text_size:
1135  designSettings.m_PcbTextSize.x = parseBoardUnits( "pcb text width" );
1136  designSettings.m_PcbTextSize.y = parseBoardUnits( "pcb text height" );
1137  NeedRIGHT();
1138  break;
1139 
1140  case T_mod_edge_width:
1141  designSettings.m_ModuleSegmentWidth = parseBoardUnits( T_mod_edge_width );
1142  NeedRIGHT();
1143  break;
1144 
1145  case T_mod_text_size:
1146  designSettings.m_ModuleTextSize.x = parseBoardUnits( "module text width" );
1147  designSettings.m_ModuleTextSize.y = parseBoardUnits( "module text height" );
1148  NeedRIGHT();
1149  break;
1150 
1151  case T_mod_text_width:
1152  designSettings.m_ModuleTextWidth = parseBoardUnits( T_mod_text_width );
1153  NeedRIGHT();
1154  break;
1155 
1156  case T_pad_size:
1157  {
1158  wxSize sz;
1159  sz.SetWidth( parseBoardUnits( "master pad width" ) );
1160  sz.SetHeight( parseBoardUnits( "master pad height" ) );
1161  designSettings.m_Pad_Master.SetSize( sz );
1162  NeedRIGHT();
1163  }
1164  break;
1165 
1166  case T_pad_drill:
1167  {
1168  int drillSize = parseBoardUnits( T_pad_drill );
1169  designSettings.m_Pad_Master.SetDrillSize( wxSize( drillSize, drillSize ) );
1170  NeedRIGHT();
1171  }
1172  break;
1173 
1175  designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance );
1176  NeedRIGHT();
1177  break;
1178 
1180  designSettings.m_SolderMaskMinWidth = parseBoardUnits( T_solder_mask_min_width );
1181  NeedRIGHT();
1182  break;
1183 
1185  designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance );
1186  NeedRIGHT();
1187  break;
1188 
1191  NeedRIGHT();
1192  break;
1193 
1194  case T_aux_axis_origin:
1195  {
1196  int x = parseBoardUnits( "auxiliary origin X" );
1197  int y = parseBoardUnits( "auxiliary origin Y" );
1198  // m_board->SetAuxOrigin( wxPoint( x, y ) ); gets overwritten via SetDesignSettings below
1199  designSettings.m_AuxOrigin = wxPoint( x, y );
1200  NeedRIGHT();
1201  }
1202  break;
1203 
1204  case T_grid_origin:
1205  {
1206  int x = parseBoardUnits( "grid origin X" );
1207  int y = parseBoardUnits( "grid origin Y" );
1208  // m_board->SetGridOrigin( wxPoint( x, y ) ); gets overwritten SetDesignSettings below
1209  designSettings.m_GridOrigin = wxPoint( x, y );
1210  NeedRIGHT();
1211  }
1212  break;
1213 
1214  case T_visible_elements:
1215  designSettings.SetVisibleElements( parseHex() | MIN_VISIBILITY_MASK );
1216  NeedRIGHT();
1217  break;
1218 
1219  case T_pcbplotparams:
1220  {
1221  PCB_PLOT_PARAMS plotParams;
1222  PCB_PLOT_PARAMS_PARSER parser( reader );
1223  // parser must share the same current line as our current PCB parser
1224  // synchronize it.
1225  parser.SyncLineReaderWith( *this );
1226 
1227  plotParams.Parse( &parser );
1228  SyncLineReaderWith( parser );
1229 
1230  m_board->SetPlotOptions( plotParams );
1231  }
1232  break;
1233 
1234  default:
1235  Unexpected( CurText() );
1236  }
1237  }
1238 
1239  m_board->SetDesignSettings( designSettings );
1240  m_board->SetZoneSettings( zoneSettings );
1241 }
1242 
1243 
1245 {
1246  wxCHECK_RET( CurTok() == T_net,
1247  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) );
1248 
1249  int netCode = parseInt( "net number" );
1250 
1251  NeedSYMBOLorNUMBER();
1252  wxString name = FromUTF8();
1253 
1254  NeedRIGHT();
1255 
1256  // net 0 should be already in list, so store this net
1257  // if it is not the net 0, or if the net 0 does not exists.
1258  // (TODO: a better test.)
1259  if( netCode > NETINFO_LIST::UNCONNECTED || !m_board->FindNet( NETINFO_LIST::UNCONNECTED ) )
1260  {
1261  NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, netCode );
1262  m_board->Add( net );
1263 
1264  // Store the new code mapping
1265  pushValueIntoMap( netCode, net->GetNet() );
1266  }
1267 }
1268 
1269 
1271 {
1272  wxCHECK_RET( CurTok() == T_net_class,
1273  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) );
1274 
1275  T token;
1276 
1277  NETCLASSPTR nc = std::make_shared<NETCLASS>( wxEmptyString );
1278 
1279  // Read netclass name (can be a name or just a number like track width)
1280  NeedSYMBOLorNUMBER();
1281  nc->SetName( FromUTF8() );
1282  NeedSYMBOL();
1283  nc->SetDescription( FromUTF8() );
1284 
1285  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1286  {
1287  if( token != T_LEFT )
1288  Expecting( T_LEFT );
1289 
1290  token = NextTok();
1291 
1292  switch( token )
1293  {
1294  case T_clearance:
1295  nc->SetClearance( parseBoardUnits( T_clearance ) );
1296  break;
1297 
1298  case T_trace_width:
1299  nc->SetTrackWidth( parseBoardUnits( T_trace_width ) );
1300  break;
1301 
1302  case T_via_dia:
1303  nc->SetViaDiameter( parseBoardUnits( T_via_dia ) );
1304  break;
1305 
1306  case T_via_drill:
1307  nc->SetViaDrill( parseBoardUnits( T_via_drill ) );
1308  break;
1309 
1310  case T_uvia_dia:
1311  nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) );
1312  break;
1313 
1314  case T_uvia_drill:
1315  nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1316  break;
1317 
1318  case T_diff_pair_width:
1319  nc->SetDiffPairWidth( parseBoardUnits( T_diff_pair_width ) );
1320  break;
1321 
1322  case T_diff_pair_gap:
1323  nc->SetDiffPairGap( parseBoardUnits( T_diff_pair_gap ) );
1324  break;
1325 
1326  case T_add_net:
1327  NeedSYMBOLorNUMBER();
1328  nc->Add( FromUTF8() );
1329  break;
1330 
1331  default:
1332  Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, diff_pair_width, diff_pair_gap or add_net" );
1333  }
1334 
1335  NeedRIGHT();
1336  }
1337 
1338  if( !m_board->GetDesignSettings().m_NetClasses.Add( nc ) )
1339  {
1340  // Must have been a name conflict, this is a bad board file.
1341  // User may have done a hand edit to the file.
1342 
1343  // unique_ptr will delete nc on this code path
1344 
1345  wxString error;
1346  error.Printf( _( "duplicate NETCLASS name '%s' in file <%s> at line %d, offset %d" ),
1347  nc->GetName().GetData(), CurSource().GetData(), CurLineNumber(), CurOffset() );
1348  THROW_IO_ERROR( error );
1349  }
1350 }
1351 
1352 
1354 {
1355  wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
1356  CurTok() == T_gr_line || CurTok() == T_gr_poly, NULL,
1357  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DRAWSEGMENT." ) );
1358 
1359  T token;
1360  wxPoint pt;
1361  std::unique_ptr< DRAWSEGMENT > segment( new DRAWSEGMENT( NULL ) );
1362 
1363  switch( CurTok() )
1364  {
1365  case T_gr_arc:
1366  segment->SetShape( S_ARC );
1367  NeedLEFT();
1368  token = NextTok();
1369 
1370  // the start keyword actually gives the arc center
1371  // Allows also T_center for future change
1372  if( token != T_start && token != T_center )
1373  Expecting( T_start );
1374 
1375  pt.x = parseBoardUnits( "X coordinate" );
1376  pt.y = parseBoardUnits( "Y coordinate" );
1377  segment->SetCenter( pt );
1378  NeedRIGHT();
1379  NeedLEFT();
1380  token = NextTok();
1381 
1382  if( token != T_end ) // the end keyword actually gives the starting point of the arc
1383  Expecting( T_end );
1384 
1385  pt.x = parseBoardUnits( "X coordinate" );
1386  pt.y = parseBoardUnits( "Y coordinate" );
1387  segment->SetArcStart( pt );
1388  NeedRIGHT();
1389  break;
1390 
1391  case T_gr_circle:
1392  segment->SetShape( S_CIRCLE );
1393  NeedLEFT();
1394  token = NextTok();
1395 
1396  if( token != T_center )
1397  Expecting( T_center );
1398 
1399  pt.x = parseBoardUnits( "X coordinate" );
1400  pt.y = parseBoardUnits( "Y coordinate" );
1401  segment->SetCenter( pt );
1402  NeedRIGHT();
1403  NeedLEFT();
1404 
1405  token = NextTok();
1406 
1407  if( token != T_end )
1408  Expecting( T_end );
1409 
1410  pt.x = parseBoardUnits( "X coordinate" );
1411  pt.y = parseBoardUnits( "Y coordinate" );
1412  segment->SetEnd( pt );
1413  NeedRIGHT();
1414  break;
1415 
1416  case T_gr_curve:
1417  segment->SetShape( S_CURVE );
1418  NeedLEFT();
1419  token = NextTok();
1420 
1421  if( token != T_pts )
1422  Expecting( T_pts );
1423 
1424  segment->SetStart( parseXY() );
1425  segment->SetBezControl1( parseXY() );
1426  segment->SetBezControl2( parseXY() );
1427  segment->SetEnd( parseXY() );
1428  NeedRIGHT();
1429  break;
1430 
1431  case T_gr_line:
1432  // Default DRAWSEGMENT type is S_SEGMENT.
1433  NeedLEFT();
1434  token = NextTok();
1435 
1436  if( token != T_start )
1437  Expecting( T_start );
1438 
1439  pt.x = parseBoardUnits( "X coordinate" );
1440  pt.y = parseBoardUnits( "Y coordinate" );
1441  segment->SetStart( pt );
1442  NeedRIGHT();
1443  NeedLEFT();
1444  token = NextTok();
1445 
1446  if( token != T_end )
1447  Expecting( T_end );
1448 
1449  pt.x = parseBoardUnits( "X coordinate" );
1450  pt.y = parseBoardUnits( "Y coordinate" );
1451  segment->SetEnd( pt );
1452  NeedRIGHT();
1453  break;
1454 
1455  case T_gr_poly:
1456  {
1457  segment->SetShape( S_POLYGON );
1458  segment->SetWidth( 0 ); // this is the default value. will be (perhaps) modified later
1459  NeedLEFT();
1460  token = NextTok();
1461 
1462  if( token != T_pts )
1463  Expecting( T_pts );
1464 
1465  std::vector< wxPoint > pts;
1466 
1467  while( (token = NextTok()) != T_RIGHT )
1468  pts.push_back( parseXY() );
1469 
1470  segment->SetPolyPoints( pts );
1471  }
1472  break;
1473 
1474  default:
1475  Expecting( "gr_arc, gr_circle, gr_curve, gr_line, or gr_poly" );
1476  }
1477 
1478  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1479  {
1480  if( token != T_LEFT )
1481  Expecting( T_LEFT );
1482 
1483  token = NextTok();
1484 
1485  switch( token )
1486  {
1487  case T_angle:
1488  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
1489  break;
1490 
1491  case T_layer:
1492  segment->SetLayer( parseBoardItemLayer() );
1493  break;
1494 
1495  case T_width:
1496  segment->SetWidth( parseBoardUnits( T_width ) );
1497  break;
1498 
1499  case T_tstamp:
1500  segment->SetTimeStamp( parseHex() );
1501  break;
1502 
1503  case T_status:
1504  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
1505  break;
1506 
1507  default:
1508  Expecting( "layer, width, tstamp, or status" );
1509  }
1510 
1511  NeedRIGHT();
1512  }
1513 
1514  return segment.release();
1515 }
1516 
1517 
1519 {
1520  wxCHECK_MSG( CurTok() == T_gr_text, NULL,
1521  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TEXTE_PCB." ) );
1522 
1523  T token;
1524 
1525  std::unique_ptr<TEXTE_PCB> text( new TEXTE_PCB( m_board ) );
1526  NeedSYMBOLorNUMBER();
1527 
1528  text->SetText( FromUTF8() );
1529  NeedLEFT();
1530  token = NextTok();
1531 
1532  if( token != T_at )
1533  Expecting( T_at );
1534 
1535  wxPoint pt;
1536 
1537  pt.x = parseBoardUnits( "X coordinate" );
1538  pt.y = parseBoardUnits( "Y coordinate" );
1539  text->SetTextPos( pt );
1540 
1541  // If there is no orientation defined, then it is the default value of 0 degrees.
1542  token = NextTok();
1543 
1544  if( token == T_NUMBER )
1545  {
1546  text->SetTextAngle( parseDouble() * 10.0 );
1547  NeedRIGHT();
1548  }
1549  else if( token != T_RIGHT )
1550  {
1551  Unexpected( CurText() );
1552  }
1553 
1554  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1555  {
1556  if( token != T_LEFT )
1557  Expecting( T_LEFT );
1558 
1559  token = NextTok();
1560 
1561  switch( token )
1562  {
1563  case T_layer:
1564  text->SetLayer( parseBoardItemLayer() );
1565  NeedRIGHT();
1566  break;
1567 
1568  case T_tstamp:
1569  text->SetTimeStamp( parseHex() );
1570  NeedRIGHT();
1571  break;
1572 
1573  case T_effects:
1574  parseEDA_TEXT( (EDA_TEXT*) text.get() );
1575  break;
1576 
1577  default:
1578  Expecting( "layer, tstamp or effects" );
1579  }
1580  }
1581 
1582  return text.release();
1583 }
1584 
1585 
1587 {
1588  wxCHECK_MSG( CurTok() == T_dimension, NULL,
1589  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) );
1590 
1591  T token;
1592 
1593  std::unique_ptr<DIMENSION> dimension( new DIMENSION( NULL ) );
1594 
1595  dimension->SetValue( parseBoardUnits( "dimension value" ) );
1596  NeedLEFT();
1597  token = NextTok();
1598 
1599  if( token != T_width )
1600  Expecting( T_width );
1601 
1602  dimension->SetWidth( parseBoardUnits( "dimension width value" ) );
1603  NeedRIGHT();
1604 
1605  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1606  {
1607  if( token != T_LEFT )
1608  Expecting( T_LEFT );
1609 
1610  token = NextTok();
1611 
1612  switch( token )
1613  {
1614  case T_layer:
1615  dimension->SetLayer( parseBoardItemLayer() );
1616  NeedRIGHT();
1617  break;
1618 
1619  case T_tstamp:
1620  dimension->SetTimeStamp( parseHex() );
1621  NeedRIGHT();
1622  break;
1623 
1624  case T_gr_text:
1625  {
1626  TEXTE_PCB* text = parseTEXTE_PCB();
1627  dimension->Text() = *text;
1628  dimension->SetPosition( text->GetTextPos() );
1629  delete text;
1630  break;
1631  }
1632 
1633  case T_feature1:
1634  NeedLEFT();
1635  token = NextTok();
1636 
1637  if( token != T_pts )
1638  Expecting( T_pts );
1639 
1640  parseXY( &dimension->m_featureLineDO.x, &dimension->m_featureLineDO.y );
1641  parseXY( &dimension->m_featureLineDF.x, &dimension->m_featureLineDF.y );
1642  dimension->UpdateHeight();
1643  NeedRIGHT();
1644  NeedRIGHT();
1645  break;
1646 
1647  case T_feature2:
1648  NeedLEFT();
1649  token = NextTok();
1650 
1651  if( token != T_pts )
1652  Expecting( T_pts );
1653 
1654  parseXY( &dimension->m_featureLineGO.x, &dimension->m_featureLineGO.y );
1655  parseXY( &dimension->m_featureLineGF.x, &dimension->m_featureLineGF.y );
1656  dimension->UpdateHeight();
1657  NeedRIGHT();
1658  NeedRIGHT();
1659  break;
1660 
1661 
1662  case T_crossbar:
1663  NeedLEFT();
1664  token = NextTok();
1665 
1666  if( token != T_pts )
1667  Expecting( T_pts );
1668 
1669  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1670  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1671  dimension->UpdateHeight();
1672  NeedRIGHT();
1673  NeedRIGHT();
1674  break;
1675 
1676  case T_arrow1a:
1677  NeedLEFT();
1678  token = NextTok();
1679 
1680  if( token != T_pts )
1681  Expecting( T_pts );
1682 
1683  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1684  parseXY( &dimension->m_arrowD1F.x, &dimension->m_arrowD1F.y );
1685  NeedRIGHT();
1686  NeedRIGHT();
1687  break;
1688 
1689  case T_arrow1b:
1690  NeedLEFT();
1691  token = NextTok();
1692 
1693  if( token != T_pts )
1694  Expecting( T_pts );
1695 
1696  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1697  parseXY( &dimension->m_arrowD2F.x, &dimension->m_arrowD2F.y );
1698  NeedRIGHT();
1699  NeedRIGHT();
1700  break;
1701 
1702  case T_arrow2a:
1703  NeedLEFT();
1704  token = NextTok();
1705 
1706  if( token != T_pts )
1707  Expecting( T_pts );
1708 
1709  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1710  parseXY( &dimension->m_arrowG1F.x, &dimension->m_arrowG1F.y );
1711  NeedRIGHT();
1712  NeedRIGHT();
1713  break;
1714 
1715  case T_arrow2b:
1716  NeedLEFT();
1717  token = NextTok();
1718 
1719  if( token != T_pts )
1720  Expecting( T_pts );
1721 
1722  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1723  parseXY( &dimension->m_arrowG2F.x, &dimension->m_arrowG2F.y );
1724  NeedRIGHT();
1725  NeedRIGHT();
1726  break;
1727 
1728  default:
1729  Expecting( "layer, tstamp, gr_text, feature1, feature2 crossbar, arrow1a, "
1730  "arrow1b, arrow2a, or arrow2b" );
1731  }
1732  }
1733 
1734  return dimension.release();
1735 }
1736 
1737 
1738 MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments )
1739 {
1740  try
1741  {
1742  return parseMODULE_unchecked( aInitialComments );
1743  }
1744  catch( const PARSE_ERROR& parse_error )
1745  {
1746  if( m_tooRecent )
1747  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
1748  else
1749  throw;
1750  }
1751 }
1752 
1753 
1754 MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
1755 {
1756  wxCHECK_MSG( CurTok() == T_module, NULL,
1757  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) );
1758 
1759  wxString name;
1760  wxPoint pt;
1761  T token;
1762  LIB_ID fpid;
1763 
1764  std::unique_ptr<MODULE> module( new MODULE( m_board ) );
1765 
1766  module->SetInitialComments( aInitialComments );
1767 
1768  token = NextTok();
1769 
1770  if( !IsSymbol( token ) && token != T_NUMBER )
1771  Expecting( "symbol|number" );
1772 
1773  name = FromUTF8();
1774 
1775  if( !name.IsEmpty() && fpid.Parse( FromUTF8() ) >= 0 )
1776  {
1777  wxString error;
1778  error.Printf( _( "invalid footprint ID in\nfile: <%s>\nline: %d\noffset: %d" ),
1779  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
1780  THROW_IO_ERROR( error );
1781  }
1782 
1783  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1784  {
1785  if( token == T_LEFT )
1786  token = NextTok();
1787 
1788  switch( token )
1789  {
1790  case T_version:
1791  {
1792  // Theoretically a module nested in a PCB could declare its own version, though
1793  // as of writing this comment we don't do that. Just in case, take the greater
1794  // version.
1795  int this_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
1796  NeedRIGHT();
1797  m_requiredVersion = std::max( m_requiredVersion, this_version );
1798  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
1799  break;
1800  }
1801 
1802  case T_locked:
1803  module->SetLocked( true );
1804  break;
1805 
1806  case T_placed:
1807  module->SetIsPlaced( true );
1808  break;
1809 
1810  case T_layer:
1811  {
1812  // Footprints can be only on the front side or the back side.
1813  // but because we can find some stupid layer in file, ensure a
1814  // acceptable layer is set for the footprint
1815  PCB_LAYER_ID layer = parseBoardItemLayer();
1816  module->SetLayer( layer == B_Cu ? B_Cu : F_Cu );
1817  }
1818  NeedRIGHT();
1819  break;
1820 
1821  case T_tedit:
1822  module->SetLastEditTime( parseHex() );
1823  NeedRIGHT();
1824  break;
1825 
1826  case T_tstamp:
1827  module->SetTimeStamp( parseHex() );
1828  NeedRIGHT();
1829  break;
1830 
1831  case T_at:
1832  pt.x = parseBoardUnits( "X coordinate" );
1833  pt.y = parseBoardUnits( "Y coordinate" );
1834  module->SetPosition( pt );
1835  token = NextTok();
1836 
1837  if( token == T_NUMBER )
1838  {
1839  module->SetOrientation( parseDouble() * 10.0 );
1840  NeedRIGHT();
1841  }
1842  else if( token != T_RIGHT )
1843  {
1844  Expecting( T_RIGHT );
1845  }
1846 
1847  break;
1848 
1849  case T_descr:
1850  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
1851  module->SetDescription( FromUTF8() );
1852  NeedRIGHT();
1853  break;
1854 
1855  case T_tags:
1856  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
1857  module->SetKeywords( FromUTF8() );
1858  NeedRIGHT();
1859  break;
1860 
1861  case T_path:
1862  NeedSYMBOLorNUMBER(); // Paths can be numerical so a number is also a symbol here
1863  module->SetPath( FromUTF8() );
1864  NeedRIGHT();
1865  break;
1866 
1867  case T_autoplace_cost90:
1868  module->SetPlacementCost90( parseInt( "auto place cost at 90 degrees" ) );
1869  NeedRIGHT();
1870  break;
1871 
1872  case T_autoplace_cost180:
1873  module->SetPlacementCost180( parseInt( "auto place cost at 180 degrees" ) );
1874  NeedRIGHT();
1875  break;
1876 
1877  case T_solder_mask_margin:
1878  module->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) );
1879  NeedRIGHT();
1880  break;
1881 
1882  case T_solder_paste_margin:
1883  module->SetLocalSolderPasteMargin(
1884  parseBoardUnits( "local solder paste margin value" ) );
1885  NeedRIGHT();
1886  break;
1887 
1888  case T_solder_paste_ratio:
1889  module->SetLocalSolderPasteMarginRatio(
1890  parseDouble( "local solder paste margin ratio value" ) );
1891  NeedRIGHT();
1892  break;
1893 
1894  case T_clearance:
1895  module->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
1896  NeedRIGHT();
1897  break;
1898 
1899  case T_zone_connect:
1900  module->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) );
1901  NeedRIGHT();
1902  break;
1903 
1904  case T_thermal_width:
1905  module->SetThermalWidth( parseBoardUnits( "thermal width value" ) );
1906  NeedRIGHT();
1907  break;
1908 
1909  case T_thermal_gap:
1910  module->SetThermalGap( parseBoardUnits( "thermal gap value" ) );
1911  NeedRIGHT();
1912  break;
1913 
1914  case T_attr:
1915  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1916  {
1917  switch( token )
1918  {
1919  case T_smd:
1920  module->SetAttributes( module->GetAttributes() | MOD_CMS );
1921  break;
1922 
1923  case T_virtual:
1924  module->SetAttributes( module->GetAttributes() | MOD_VIRTUAL );
1925  break;
1926 
1927  default:
1928  Expecting( "smd and/or virtual" );
1929  }
1930  }
1931  break;
1932 
1933  case T_fp_text:
1934  {
1935  TEXTE_MODULE* text = parseTEXTE_MODULE();
1936  text->SetParent( module.get() );
1937  double orientation = text->GetTextAngle();
1938  orientation -= module->GetOrientation();
1939  text->SetTextAngle( orientation );
1940  text->SetDrawCoord();
1941 
1942  switch( text->GetType() )
1943  {
1945  module->Reference() = *text;
1946  delete text;
1947  break;
1948 
1950  module->Value() = *text;
1951  delete text;
1952  break;
1953 
1954  default:
1955  module->GraphicalItemsList().PushBack( text );
1956  }
1957  }
1958  break;
1959 
1960  case T_fp_arc:
1961  case T_fp_circle:
1962  case T_fp_curve:
1963  case T_fp_line:
1964  case T_fp_poly:
1965  {
1966  EDGE_MODULE* em = parseEDGE_MODULE();
1967  em->SetParent( module.get() );
1968  em->SetDrawCoord();
1969  module->GraphicalItemsList().PushBack( em );
1970  }
1971  break;
1972 
1973  case T_pad:
1974  {
1975  D_PAD* pad = parseD_PAD( module.get() );
1976  pt = pad->GetPos0();
1977 
1978  RotatePoint( &pt, module->GetOrientation() );
1979  pad->SetPosition( pt + module->GetPosition() );
1980  module->Add( pad, ADD_APPEND );
1981  }
1982  break;
1983 
1984  case T_model:
1985  module->Add3DModel( parse3DModel() );
1986  break;
1987 
1988  default:
1989  Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, "
1990  "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
1991  "solder_paste_margin, solder_paste_ratio, clearance, "
1992  "zone_connect, thermal_width, thermal_gap, attr, fp_text, "
1993  "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, or model" );
1994  }
1995  }
1996 
1997  module->SetFPID( fpid );
1998  module->CalculateBoundingBox();
1999 
2000  return module.release();
2001 }
2002 
2003 
2005 {
2006  wxCHECK_MSG( CurTok() == T_fp_text, NULL,
2007  wxString::Format( wxT( "Cannot parse %s as TEXTE_MODULE at line %d, offset %d." ),
2008  GetChars( GetTokenString( CurTok() ) ),
2009  CurLineNumber(), CurOffset() ) );
2010 
2011  T token = NextTok();
2012 
2013  std::unique_ptr<TEXTE_MODULE> text( new TEXTE_MODULE( NULL ) );
2014 
2015  switch( token )
2016  {
2017  case T_reference:
2018  text->SetType( TEXTE_MODULE::TEXT_is_REFERENCE );
2019  break;
2020 
2021  case T_value:
2022  text->SetType( TEXTE_MODULE::TEXT_is_VALUE );
2023  break;
2024 
2025  case T_user:
2026  break; // Default type is user text.
2027 
2028  default:
2029  THROW_IO_ERROR( wxString::Format( _( "cannot handle footprint text type %s" ),
2030  GetChars( FromUTF8() ) ) );
2031  }
2032 
2033  NeedSYMBOLorNUMBER();
2034 
2035  text->SetText( FromUTF8() );
2036  NeedLEFT();
2037  token = NextTok();
2038 
2039  if( token != T_at )
2040  Expecting( T_at );
2041 
2042  wxPoint pt;
2043 
2044  pt.x = parseBoardUnits( "X coordinate" );
2045  pt.y = parseBoardUnits( "Y coordinate" );
2046  text->SetPos0( pt );
2047  token = NextTok();
2048 
2049  // If there is no orientation defined, then it is the default value of 0 degrees.
2050  if( token == T_NUMBER )
2051  {
2052  text->SetTextAngle( parseDouble() * 10.0 );
2053  NeedRIGHT();
2054  }
2055  else if( token != T_RIGHT )
2056  {
2057  Unexpected( CurText() );
2058  }
2059 
2060  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2061  {
2062  if( token == T_LEFT )
2063  token = NextTok();
2064 
2065  switch( token )
2066  {
2067  case T_layer:
2068  text->SetLayer( parseBoardItemLayer() );
2069  NeedRIGHT();
2070  break;
2071 
2072  case T_hide:
2073  text->SetVisible( false );
2074  break;
2075 
2076  case T_effects:
2077  parseEDA_TEXT( (EDA_TEXT*) text.get() );
2078  break;
2079 
2080  default:
2081  Expecting( "hide or effects" );
2082  }
2083  }
2084 
2085  return text.release();
2086 }
2087 
2088 
2090 {
2091  wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
2092  CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL,
2093  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDGE_MODULE." ) );
2094 
2095  wxPoint pt;
2096  T token;
2097 
2098  std::unique_ptr< EDGE_MODULE > segment( new EDGE_MODULE( NULL ) );
2099 
2100  switch( CurTok() )
2101  {
2102  case T_fp_arc:
2103  segment->SetShape( S_ARC );
2104  NeedLEFT();
2105  token = NextTok();
2106 
2107  // the start keyword actually gives the arc center
2108  // Allows also T_center for future change
2109  if( token != T_start && token != T_center )
2110  Expecting( T_start );
2111 
2112  pt.x = parseBoardUnits( "X coordinate" );
2113  pt.y = parseBoardUnits( "Y coordinate" );
2114  segment->SetStart0( pt );
2115  NeedRIGHT();
2116  NeedLEFT();
2117  token = NextTok();
2118 
2119  if( token != T_end ) // end keyword actually gives the starting point of the arc
2120  Expecting( T_end );
2121 
2122  pt.x = parseBoardUnits( "X coordinate" );
2123  pt.y = parseBoardUnits( "Y coordinate" );
2124  segment->SetEnd0( pt );
2125  NeedRIGHT();
2126  NeedLEFT();
2127  token = NextTok();
2128 
2129  if( token != T_angle )
2130  Expecting( T_angle );
2131 
2132  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
2133  NeedRIGHT();
2134  break;
2135 
2136  case T_fp_circle:
2137  segment->SetShape( S_CIRCLE );
2138  NeedLEFT();
2139  token = NextTok();
2140 
2141  if( token != T_center )
2142  Expecting( T_center );
2143 
2144  pt.x = parseBoardUnits( "X coordinate" );
2145  pt.y = parseBoardUnits( "Y coordinate" );
2146  segment->SetStart0( pt );
2147  NeedRIGHT();
2148  NeedLEFT();
2149  token = NextTok();
2150 
2151  if( token != T_end )
2152  Expecting( T_end );
2153 
2154  pt.x = parseBoardUnits( "X coordinate" );
2155  pt.y = parseBoardUnits( "Y coordinate" );
2156  segment->SetEnd0( pt );
2157  NeedRIGHT();
2158  break;
2159 
2160  case T_fp_curve:
2161  segment->SetShape( S_CURVE );
2162  NeedLEFT();
2163  token = NextTok();
2164 
2165  if( token != T_pts )
2166  Expecting( T_pts );
2167 
2168  segment->SetStart0( parseXY() );
2169  segment->SetBezControl1( parseXY() );
2170  segment->SetBezControl2( parseXY() );
2171  segment->SetEnd0( parseXY() );
2172  NeedRIGHT();
2173  break;
2174 
2175  case T_fp_line:
2176  // Default DRAWSEGMENT type is S_SEGMENT.
2177  NeedLEFT();
2178  token = NextTok();
2179 
2180  if( token != T_start )
2181  Expecting( T_start );
2182 
2183  pt.x = parseBoardUnits( "X coordinate" );
2184  pt.y = parseBoardUnits( "Y coordinate" );
2185  segment->SetStart0( pt );
2186 
2187  NeedRIGHT();
2188  NeedLEFT();
2189  token = NextTok();
2190 
2191  if( token != T_end )
2192  Expecting( T_end );
2193 
2194  pt.x = parseBoardUnits( "X coordinate" );
2195  pt.y = parseBoardUnits( "Y coordinate" );
2196  segment->SetEnd0( pt );
2197  NeedRIGHT();
2198  break;
2199 
2200  case T_fp_poly:
2201  {
2202  segment->SetShape( S_POLYGON );
2203  NeedLEFT();
2204  token = NextTok();
2205 
2206  if( token != T_pts )
2207  Expecting( T_pts );
2208 
2209  std::vector< wxPoint > pts;
2210 
2211  while( (token = NextTok()) != T_RIGHT )
2212  pts.push_back( parseXY() );
2213 
2214  segment->SetPolyPoints( pts );
2215  }
2216  break;
2217 
2218  default:
2219  Expecting( "fp_arc, fp_circle, fp_curve, fp_line, or fp_poly" );
2220  }
2221 
2222  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2223  {
2224  if( token != T_LEFT )
2225  Expecting( T_LEFT );
2226 
2227  token = NextTok();
2228 
2229  switch( token )
2230  {
2231  case T_layer:
2232  segment->SetLayer( parseBoardItemLayer() );
2233  break;
2234 
2235  case T_width:
2236  segment->SetWidth( parseBoardUnits( T_width ) );
2237  break;
2238 
2239  case T_tstamp:
2240  segment->SetTimeStamp( parseHex() );
2241  break;
2242 
2243  case T_status:
2244  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2245  break;
2246 
2247  default:
2248  Expecting( "layer or width" );
2249  }
2250 
2251  NeedRIGHT();
2252  }
2253 
2254  return segment.release();
2255 }
2256 
2257 
2259 {
2260  wxCHECK_MSG( CurTok() == T_pad, NULL,
2261  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as D_PAD." ) );
2262 
2263  wxSize sz;
2264  wxPoint pt;
2265 
2266  std::unique_ptr< D_PAD > pad( new D_PAD( aParent ) );
2267 
2268  NeedSYMBOLorNUMBER();
2269  pad->SetName( FromUTF8() );
2270 
2271  T token = NextTok();
2272 
2273  switch( token )
2274  {
2275  case T_thru_hole:
2276  pad->SetAttribute( PAD_ATTRIB_STANDARD );
2277  break;
2278 
2279  case T_smd:
2280  pad->SetAttribute( PAD_ATTRIB_SMD );
2281 
2282  // Default D_PAD object is thru hole with drill.
2283  // SMD pads have no hole
2284  pad->SetDrillSize( wxSize( 0, 0 ) );
2285  break;
2286 
2287  case T_connect:
2288  pad->SetAttribute( PAD_ATTRIB_CONN );
2289 
2290  // Default D_PAD object is thru hole with drill.
2291  // CONN pads have no hole
2292  pad->SetDrillSize( wxSize( 0, 0 ) );
2293  break;
2294 
2295  case T_np_thru_hole:
2296  pad->SetAttribute( PAD_ATTRIB_HOLE_NOT_PLATED );
2297  break;
2298 
2299  default:
2300  Expecting( "thru_hole, smd, connect, or np_thru_hole" );
2301  }
2302 
2303  token = NextTok();
2304 
2305  switch( token )
2306  {
2307  case T_circle:
2308  pad->SetShape( PAD_SHAPE_CIRCLE );
2309  break;
2310 
2311  case T_rect:
2312  pad->SetShape( PAD_SHAPE_RECT );
2313  break;
2314 
2315  case T_oval:
2316  pad->SetShape( PAD_SHAPE_OVAL );
2317  break;
2318 
2319  case T_trapezoid:
2320  pad->SetShape( PAD_SHAPE_TRAPEZOID );
2321  break;
2322 
2323  case T_roundrect:
2324  pad->SetShape( PAD_SHAPE_ROUNDRECT );
2325  break;
2326 
2327  case T_custom:
2328  pad->SetShape( PAD_SHAPE_CUSTOM );
2329  break;
2330 
2331  default:
2332  Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
2333  }
2334 
2335  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2336  {
2337  if( token != T_LEFT )
2338  Expecting( T_LEFT );
2339 
2340  token = NextTok();
2341 
2342  switch( token )
2343  {
2344  case T_size:
2345  sz.SetWidth( parseBoardUnits( "width value" ) );
2346  sz.SetHeight( parseBoardUnits( "height value" ) );
2347  pad->SetSize( sz );
2348  NeedRIGHT();
2349  break;
2350 
2351  case T_at:
2352  pt.x = parseBoardUnits( "X coordinate" );
2353  pt.y = parseBoardUnits( "Y coordinate" );
2354  pad->SetPos0( pt );
2355  token = NextTok();
2356 
2357  if( token == T_NUMBER )
2358  {
2359  pad->SetOrientation( parseDouble() * 10.0 );
2360  NeedRIGHT();
2361  }
2362  else if( token != T_RIGHT )
2363  {
2364  Expecting( ") or angle value" );
2365  }
2366 
2367  break;
2368 
2369  case T_rect_delta:
2370  {
2371  wxSize delta;
2372  delta.SetWidth( parseBoardUnits( "rectangle delta width" ) );
2373  delta.SetHeight( parseBoardUnits( "rectangle delta height" ) );
2374  pad->SetDelta( delta );
2375  NeedRIGHT();
2376  }
2377  break;
2378 
2379  case T_drill:
2380  {
2381  bool haveWidth = false;
2382  wxSize drillSize = pad->GetDrillSize();
2383 
2384  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2385  {
2386  if( token == T_LEFT )
2387  token = NextTok();
2388 
2389  switch( token )
2390  {
2391  case T_oval:
2392  pad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG );
2393  break;
2394 
2395  case T_NUMBER:
2396  {
2397  if( !haveWidth )
2398  {
2399  drillSize.SetWidth( parseBoardUnits() );
2400 
2401  // If height is not defined the width and height are the same.
2402  drillSize.SetHeight( drillSize.GetWidth() );
2403  haveWidth = true;
2404  }
2405  else
2406  {
2407  drillSize.SetHeight( parseBoardUnits() );
2408  }
2409 
2410  }
2411  break;
2412 
2413  case T_offset:
2414  pt.x = parseBoardUnits( "drill offset x" );
2415  pt.y = parseBoardUnits( "drill offset y" );
2416  pad->SetOffset( pt );
2417  NeedRIGHT();
2418  break;
2419 
2420  default:
2421  Expecting( "oval, size, or offset" );
2422  }
2423  }
2424 
2425  // This fixes a bug caused by setting the default D_PAD drill size to a value
2426  // other than 0 used to fix a bunch of debug assertions even though it is defined
2427  // as a through hole pad. Wouldn't a though hole pad with no drill be a surface
2428  // mount pad (or a conn pad which is a smd pad with no solder paste)?
2429  if( ( pad->GetAttribute() != PAD_ATTRIB_SMD ) && ( pad->GetAttribute() != PAD_ATTRIB_CONN ) )
2430  pad->SetDrillSize( drillSize );
2431  else
2432  pad->SetDrillSize( wxSize( 0, 0 ) );
2433 
2434  }
2435  break;
2436 
2437  case T_layers:
2438  {
2439  LSET layerMask = parseBoardItemLayersAsMask();
2440  pad->SetLayerSet( layerMask );
2441  }
2442  break;
2443 
2444  case T_net:
2445  if( ! pad->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
2447  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2448  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2449  );
2450  NeedSYMBOLorNUMBER();
2451  if( m_board && FromUTF8() != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
2453  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2454  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2455  );
2456  NeedRIGHT();
2457  break;
2458 
2459  case T_die_length:
2460  pad->SetPadToDieLength( parseBoardUnits( T_die_length ) );
2461  NeedRIGHT();
2462  break;
2463 
2464  case T_solder_mask_margin:
2465  pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) );
2466  NeedRIGHT();
2467  break;
2468 
2469  case T_solder_paste_margin:
2470  pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) );
2471  NeedRIGHT();
2472  break;
2473 
2475  pad->SetLocalSolderPasteMarginRatio(
2476  parseDouble( "pad local solder paste margin ratio value" ) );
2477  NeedRIGHT();
2478  break;
2479 
2480  case T_clearance:
2481  pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
2482  NeedRIGHT();
2483  break;
2484 
2485  case T_zone_connect:
2486  pad->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) );
2487  NeedRIGHT();
2488  break;
2489 
2490  case T_thermal_width:
2491  pad->SetThermalWidth( parseBoardUnits( T_thermal_width ) );
2492  NeedRIGHT();
2493  break;
2494 
2495  case T_thermal_gap:
2496  pad->SetThermalGap( parseBoardUnits( T_thermal_gap ) );
2497  NeedRIGHT();
2498  break;
2499 
2500  case T_roundrect_rratio:
2501  pad->SetRoundRectRadiusRatio( parseDouble( "roundrect radius ratio" ) );
2502  NeedRIGHT();
2503  break;
2504 
2505  case T_options:
2506  parseD_PAD_option( pad.get() );
2507  break;
2508 
2509  case T_primitives:
2510  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2511  {
2512  if( token == T_LEFT )
2513  token = NextTok();
2514 
2515  // Currently, I am using parseDRAWSEGMENT() to read basic shapes parameters,
2516  // because they are the same as a DRAWSEGMENT.
2517  // However it could be better to write a specific parser, to avoid possible issues
2518  // if the DRAWSEGMENT parser is modified.
2519  DRAWSEGMENT* dummysegm = NULL;
2520 
2521  switch( token )
2522  {
2523  case T_gr_arc:
2524  dummysegm = parseDRAWSEGMENT();
2525  pad->AddPrimitive( dummysegm->GetCenter(), dummysegm->GetArcStart(),
2526  dummysegm->GetAngle(), dummysegm->GetWidth() );
2527  break;
2528 
2529  case T_gr_line:
2530  dummysegm = parseDRAWSEGMENT();
2531  pad->AddPrimitive( dummysegm->GetStart(), dummysegm->GetEnd(),
2532  dummysegm->GetWidth() );
2533  break;
2534 
2535  case T_gr_circle:
2536  dummysegm = parseDRAWSEGMENT();
2537  pad->AddPrimitive( dummysegm->GetCenter(), dummysegm->GetRadius(),
2538  dummysegm->GetWidth() );
2539  break;
2540 
2541  case T_gr_poly:
2542  dummysegm = parseDRAWSEGMENT();
2543  pad->AddPrimitive( dummysegm->GetPolyPoints(), dummysegm->GetWidth() );
2544  break;
2545 
2546  default:
2547  Expecting( "gr_line, gr_arc, gr_circle or gr_poly" );
2548  break;
2549  }
2550 
2551  delete dummysegm;
2552  }
2553  break;
2554 
2555  default:
2556  Expecting( "at, drill, layers, net, die_length, solder_mask_margin, roundrect_rratio,\n"
2557  "solder_paste_margin, solder_paste_margin_ratio, clearance,\n"
2558  "zone_connect, fp_poly, primitives, thermal_width, or thermal_gap" );
2559  }
2560  }
2561 
2562  // Be sure the custom shape polygon is built:
2563  if( pad->GetShape() == PAD_SHAPE_CUSTOM )
2564  pad->MergePrimitivesAsPolygon();
2565 
2566  return pad.release();
2567 }
2568 
2569 
2571 {
2572  // Parse only the (option ...) inside a pad description
2573  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
2574  {
2575  if( token != T_LEFT )
2576  Expecting( T_LEFT );
2577 
2578  token = NextTok();
2579 
2580  switch( token )
2581  {
2582  case T_anchor:
2583  token = NextTok();
2584  // Custom shaped pads have a "anchor pad", which is the reference
2585  // for connection calculations.
2586  // Because this is an anchor, only the 2 very basic shapes are managed:
2587  // circle and rect. The default is circle
2588  switch( token )
2589  {
2590  case T_circle: // default
2591  break;
2592 
2593  case T_rect:
2595  break;
2596 
2597  default:
2598  // Currently, because pad options is a moving target
2599  // just skip unknown keywords
2600  break;
2601  }
2602  NeedRIGHT();
2603  break;
2604 
2605  case T_clearance:
2606  token = NextTok();
2607  // Custom shaped pads have a clearance area that is the pad shape
2608  // (like usual pads) or the convew hull of the pad shape.
2609  switch( token )
2610  {
2611  case T_outline:
2613  break;
2614 
2615  case T_convexhull:
2617  break;
2618 
2619  default:
2620  // Currently, because pad options is a moving target
2621  // just skip unknown keywords
2622  break;
2623  }
2624  NeedRIGHT();
2625  break;
2626 
2627  default:
2628  // Currently, because pad options is a moving target
2629  // just skip unknown keywords
2630  while( (token = NextTok() ) != T_RIGHT )
2631  {}
2632  break;
2633  }
2634  }
2635 
2636  return true;
2637 }
2638 
2639 
2641 {
2642  wxCHECK_MSG( CurTok() == T_segment, NULL,
2643  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TRACK." ) );
2644 
2645  wxPoint pt;
2646  T token;
2647 
2648  std::unique_ptr< TRACK > track( new TRACK( m_board ) );
2649 
2650  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2651  {
2652  if( token != T_LEFT )
2653  Expecting( T_LEFT );
2654 
2655  token = NextTok();
2656 
2657  switch( token )
2658  {
2659  case T_start:
2660  pt.x = parseBoardUnits( "start x" );
2661  pt.y = parseBoardUnits( "start y" );
2662  track->SetStart( pt );
2663  break;
2664 
2665  case T_end:
2666  pt.x = parseBoardUnits( "end x" );
2667  pt.y = parseBoardUnits( "end y" );
2668  track->SetEnd( pt );
2669  break;
2670 
2671  case T_width:
2672  track->SetWidth( parseBoardUnits( "width" ) );
2673  break;
2674 
2675  case T_layer:
2676  track->SetLayer( parseBoardItemLayer() );
2677  break;
2678 
2679  case T_net:
2680  if( ! track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
2682  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2683  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2684  );
2685  break;
2686 
2687  case T_tstamp:
2688  track->SetTimeStamp( parseHex() );
2689  break;
2690 
2691  case T_status:
2692  track->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2693  break;
2694 
2695  default:
2696  Expecting( "start, end, width, layer, net, tstamp, or status" );
2697  }
2698 
2699  NeedRIGHT();
2700  }
2701 
2702  return track.release();
2703 }
2704 
2705 
2707 {
2708  wxCHECK_MSG( CurTok() == T_via, NULL,
2709  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as VIA." ) );
2710 
2711  wxPoint pt;
2712  T token;
2713 
2714  std::unique_ptr< VIA > via( new VIA( m_board ) );
2715 
2716  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2717  {
2718  if( token == T_LEFT )
2719  token = NextTok();
2720 
2721  switch( token )
2722  {
2723  case T_blind:
2724  via->SetViaType( VIA_BLIND_BURIED );
2725  break;
2726 
2727  case T_micro:
2728  via->SetViaType( VIA_MICROVIA );
2729  break;
2730 
2731  case T_at:
2732  pt.x = parseBoardUnits( "start x" );
2733  pt.y = parseBoardUnits( "start y" );
2734  via->SetStart( pt );
2735  via->SetEnd( pt );
2736  NeedRIGHT();
2737  break;
2738 
2739  case T_size:
2740  via->SetWidth( parseBoardUnits( "via width" ) );
2741  NeedRIGHT();
2742  break;
2743 
2744  case T_drill:
2745  via->SetDrill( parseBoardUnits( "drill diameter" ) );
2746  NeedRIGHT();
2747  break;
2748 
2749  case T_layers:
2750  {
2751  PCB_LAYER_ID layer1, layer2;
2752  NextTok();
2753  layer1 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
2754  NextTok();
2755  layer2 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
2756  via->SetLayerPair( layer1, layer2 );
2757  NeedRIGHT();
2758  }
2759  break;
2760 
2761  case T_net:
2762  if(! via->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true))
2764  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2765  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2766  );
2767  NeedRIGHT();
2768  break;
2769 
2770  case T_tstamp:
2771  via->SetTimeStamp( parseHex() );
2772  NeedRIGHT();
2773  break;
2774 
2775  case T_status:
2776  via->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2777  NeedRIGHT();
2778  break;
2779 
2780  default:
2781  Expecting( "blind, micro, at, size, drill, layers, net, tstamp, or status" );
2782  }
2783  }
2784 
2785  return via.release();
2786 }
2787 
2788 
2790 {
2791  wxCHECK_MSG( CurTok() == T_zone, NULL,
2792  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
2793  wxT( " as ZONE_CONTAINER." ) );
2794 
2796 
2797  int hatchPitch = ZONE_CONTAINER::GetDefaultHatchPitch();
2798  wxPoint pt;
2799  T token;
2800  int tmp;
2801  wxString netnameFromfile; // the zone net name find in file
2802 
2803  // bigger scope since each filled_polygon is concatenated in here
2804  SHAPE_POLY_SET pts;
2805 
2806  std::unique_ptr< ZONE_CONTAINER > zone( new ZONE_CONTAINER( m_board ) );
2807 
2808  zone->SetPriority( 0 );
2809 
2810  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2811  {
2812  if( token == T_LEFT )
2813  token = NextTok();
2814 
2815  switch( token )
2816  {
2817  case T_net:
2818  // Init the net code only, not the netname, to be sure
2819  // the zone net name is the name read in file.
2820  // (When mismatch, the user will be prompted in DRC, to fix the actual name)
2821  tmp = getNetCode( parseInt( "net number" ) );
2822 
2823  if( tmp < 0 )
2824  tmp = 0;
2825 
2826  if( ! zone->SetNetCode( tmp, /* aNoAssert */ true ) )
2828  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2829  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2830  );
2831 
2832  NeedRIGHT();
2833  break;
2834 
2835  case T_net_name:
2836  NeedSYMBOLorNUMBER();
2837  netnameFromfile = FromUTF8();
2838  NeedRIGHT();
2839  break;
2840 
2841  case T_layer: // keyword for zones that are on only one layer
2842  zone->SetLayer( parseBoardItemLayer() );
2843  NeedRIGHT();
2844  break;
2845 
2846  case T_layers: // keyword for zones that can live on a set of layer
2847  // currently: keepout zones
2848  zone->SetLayerSet( parseBoardItemLayersAsMask() );
2849  break;
2850 
2851  case T_tstamp:
2852  zone->SetTimeStamp( parseHex() );
2853  NeedRIGHT();
2854  break;
2855 
2856  case T_hatch:
2857  token = NextTok();
2858 
2859  if( token != T_none && token != T_edge && token != T_full )
2860  Expecting( "none, edge, or full" );
2861 
2862  switch( token )
2863  {
2864  default:
2865  case T_none: hatchStyle = ZONE_CONTAINER::NO_HATCH; break;
2866  case T_edge: hatchStyle = ZONE_CONTAINER::DIAGONAL_EDGE; break;
2867  case T_full: hatchStyle = ZONE_CONTAINER::DIAGONAL_FULL;
2868  }
2869 
2870  hatchPitch = parseBoardUnits( "hatch pitch" );
2871  NeedRIGHT();
2872  break;
2873 
2874  case T_priority:
2875  zone->SetPriority( parseInt( "zone priority" ) );
2876  NeedRIGHT();
2877  break;
2878 
2879  case T_connect_pads:
2880  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2881  {
2882  if( token == T_LEFT )
2883  token = NextTok();
2884 
2885  switch( token )
2886  {
2887  case T_yes:
2888  zone->SetPadConnection( PAD_ZONE_CONN_FULL );
2889  break;
2890 
2891  case T_no:
2892  zone->SetPadConnection( PAD_ZONE_CONN_NONE );
2893  break;
2894 
2895  case T_thru_hole_only:
2896  zone->SetPadConnection( PAD_ZONE_CONN_THT_THERMAL );
2897  break;
2898 
2899  case T_clearance:
2900  zone->SetZoneClearance( parseBoardUnits( "zone clearance" ) );
2901  NeedRIGHT();
2902  break;
2903 
2904  default:
2905  Expecting( "yes, no, or clearance" );
2906  }
2907  }
2908 
2909  break;
2910 
2911  case T_min_thickness:
2912  zone->SetMinThickness( parseBoardUnits( T_min_thickness ) );
2913  NeedRIGHT();
2914  break;
2915 
2916  case T_fill:
2917  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2918  {
2919  if( token == T_LEFT )
2920  token = NextTok();
2921 
2922  switch( token )
2923  {
2924  case T_yes:
2925  zone->SetIsFilled( true );
2926  break;
2927 
2928  case T_mode:
2929  token = NextTok();
2930 
2931  if( token != T_segment && token != T_polygon )
2932  Expecting( "segment or polygon" );
2933 
2934  // @todo Create an enum for fill modes.
2935  zone->SetFillMode( token == T_polygon ? 0 : 1 );
2936  NeedRIGHT();
2937  break;
2938 
2939  case T_arc_segments:
2940  zone->SetArcSegmentCount( parseInt( "arc segment count" ) );
2941  NeedRIGHT();
2942  break;
2943 
2944  case T_thermal_gap:
2945  zone->SetThermalReliefGap( parseBoardUnits( T_thermal_gap ) );
2946  NeedRIGHT();
2947  break;
2948 
2950  zone->SetThermalReliefCopperBridge( parseBoardUnits( T_thermal_bridge_width ) );
2951  NeedRIGHT();
2952  break;
2953 
2954  case T_smoothing:
2955  switch( NextTok() )
2956  {
2957  case T_none:
2958  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_NONE );
2959  break;
2960 
2961  case T_chamfer:
2962  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2963  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_CHAMFER );
2964  break;
2965 
2966  case T_fillet:
2967  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2968  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_FILLET );
2969  break;
2970 
2971  default:
2972  Expecting( "none, chamfer, or fillet" );
2973  }
2974  NeedRIGHT();
2975  break;
2976 
2977  case T_radius:
2978  tmp = parseBoardUnits( "corner radius" );
2979  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2980  zone->SetCornerRadius( tmp );
2981  NeedRIGHT();
2982  break;
2983 
2984  default:
2985  Expecting( "mode, arc_segments, thermal_gap, thermal_bridge_width, "
2986  "smoothing, or radius" );
2987  }
2988  }
2989  break;
2990 
2991  case T_keepout:
2992  zone->SetIsKeepout( true );
2993 
2994  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2995  {
2996  if( token == T_LEFT )
2997  token = NextTok();
2998 
2999  switch( token )
3000  {
3001  case T_tracks:
3002  token = NextTok();
3003 
3004  if( token != T_allowed && token != T_not_allowed )
3005  Expecting( "allowed or not_allowed" );
3006  zone->SetDoNotAllowTracks( token == T_not_allowed );
3007  break;
3008 
3009  case T_vias:
3010  token = NextTok();
3011 
3012  if( token != T_allowed && token != T_not_allowed )
3013  Expecting( "allowed or not_allowed" );
3014  zone->SetDoNotAllowVias( token == T_not_allowed );
3015  break;
3016 
3017  case T_copperpour:
3018  token = NextTok();
3019 
3020  if( token != T_allowed && token != T_not_allowed )
3021  Expecting( "allowed or not_allowed" );
3022  zone->SetDoNotAllowCopperPour( token == T_not_allowed );
3023  break;
3024 
3025  default:
3026  Expecting( "tracks, vias or copperpour" );
3027  }
3028 
3029  NeedRIGHT();
3030  }
3031 
3032  break;
3033 
3034  case T_polygon:
3035  {
3036  std::vector< wxPoint > corners;
3037 
3038  NeedLEFT();
3039  token = NextTok();
3040 
3041  if( token != T_pts )
3042  Expecting( T_pts );
3043 
3044  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3045  {
3046  corners.push_back( parseXY() );
3047  }
3048 
3049  NeedRIGHT();
3050 
3051  // Remark: The first polygon is the main outline.
3052  // Others are holes inside the main outline.
3053  zone->AddPolygon( corners );
3054  }
3055  break;
3056 
3057  case T_filled_polygon:
3058  {
3059  // "(filled_polygon (pts"
3060  NeedLEFT();
3061  token = NextTok();
3062 
3063  if( token != T_pts )
3064  Expecting( T_pts );
3065 
3066  pts.NewOutline();
3067 
3068  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3069  {
3070  pts.Append( parseXY() );
3071  }
3072 
3073  NeedRIGHT();
3074  }
3075  break;
3076 
3077  case T_fill_segments:
3078  {
3079  std::vector< SEGMENT > segs;
3080 
3081  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3082  {
3083  if( token != T_LEFT )
3084  Expecting( T_LEFT );
3085 
3086  token = NextTok();
3087 
3088  if( token != T_pts )
3089  Expecting( T_pts );
3090 
3091  SEGMENT segment( parseXY(), parseXY() );
3092  NeedRIGHT();
3093  segs.push_back( segment );
3094  }
3095 
3096  zone->AddFillSegments( segs );
3097  }
3098  break;
3099 
3100  default:
3101  Expecting( "net, layer/layers, tstamp, hatch, priority, connect_pads, min_thickness, "
3102  "fill, polygon, filled_polygon, or fill_segments" );
3103  }
3104  }
3105 
3106  if( zone->GetNumCorners() > 2 )
3107  {
3108  if( !zone->IsOnCopperLayer() )
3109  {
3110  zone->SetFillMode( 0 );
3111  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
3112  }
3113 
3114  // Set hatch here, after outlines corners are read
3115  zone->SetHatch( hatchStyle, hatchPitch, true );
3116  }
3117 
3118  if( !pts.IsEmpty() )
3119  zone->AddFilledPolysList( pts );
3120 
3121  // Ensure keepout and non copper zones do not have a net
3122  // (which have no sense for these zones)
3123  // the netcode 0 is used for these zones
3124  bool zone_has_net = zone->IsOnCopperLayer() && !zone->GetIsKeepout();
3125 
3126  if( !zone_has_net )
3127  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
3128 
3129  // Ensure the zone net name is valid, and matches the net code, for copper zones
3130  if( zone_has_net && ( zone->GetNet()->GetNetname() != netnameFromfile ) )
3131  {
3132  // Can happens which old boards, with nonexistent nets ...
3133  // or after being edited by hand
3134  // We try to fix the mismatch.
3135  NETINFO_ITEM* net = m_board->FindNet( netnameFromfile );
3136 
3137  if( net ) // An existing net has the same net name. use it for the zone
3138  zone->SetNetCode( net->GetNet() );
3139  else // Not existing net: add a new net to keep trace of the zone netname
3140  {
3141  int newnetcode = m_board->GetNetCount();
3142  net = new NETINFO_ITEM( m_board, netnameFromfile, newnetcode );
3143  m_board->Add( net );
3144 
3145  // Store the new code mapping
3146  pushValueIntoMap( newnetcode, net->GetNet() );
3147  // and update the zone netcode
3148  zone->SetNetCode( net->GetNet() );
3149 
3150  // FIXME: a call to any GUI item is not allowed in io plugins:
3151  // Change this code to generate a warning message outside this plugin
3152  // Prompt the user
3153  wxString msg;
3154  msg.Printf( _( "There is a zone that belongs to a not existing net\n"
3155  "\"%s\"\n"
3156  "you should verify and edit it (run DRC test)." ),
3157  GetChars( netnameFromfile ) );
3158  DisplayError( NULL, msg );
3159  }
3160  }
3161 
3162  return zone.release();
3163 }
3164 
3165 
3167 {
3168  wxCHECK_MSG( CurTok() == T_target, NULL,
3169  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) );
3170 
3171  wxPoint pt;
3172  T token;
3173 
3174  std::unique_ptr< PCB_TARGET > target( new PCB_TARGET( NULL ) );
3175 
3176  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3177  {
3178  if( token == T_LEFT )
3179  token = NextTok();
3180 
3181  switch( token )
3182  {
3183  case T_x:
3184  target->SetShape( 1 );
3185  break;
3186 
3187  case T_plus:
3188  target->SetShape( 0 );
3189  break;
3190 
3191  case T_at:
3192  pt.x = parseBoardUnits( "target x position" );
3193  pt.y = parseBoardUnits( "target y position" );
3194  target->SetPosition( pt );
3195  NeedRIGHT();
3196  break;
3197 
3198  case T_size:
3199  target->SetSize( parseBoardUnits( "target size" ) );
3200  NeedRIGHT();
3201  break;
3202 
3203  case T_width:
3204  target->SetWidth( parseBoardUnits( "target thickness" ) );
3205  NeedRIGHT();
3206  break;
3207 
3208  case T_layer:
3209  target->SetLayer( parseBoardItemLayer() );
3210  NeedRIGHT();
3211  break;
3212 
3213  case T_tstamp:
3214  target->SetTimeStamp( parseHex() );
3215  NeedRIGHT();
3216  break;
3217 
3218  default:
3219  Expecting( "x, plus, at, size, width, layer or tstamp" );
3220  }
3221  }
3222 
3223  return target.release();
3224 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:178
void SetComment1(const wxString &aComment)
void parseHeader()
Definition: pcb_parser.cpp:567
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:646
int parseVersion()
Parse a format version tag like (version 20160417) return the version.
Definition: pcb_parser.cpp:169
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
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:991
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:111
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:65
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:165
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.
void SetRevision(const wxString &aRevision)
const wxPoint GetCenter() const override
Function GetCenter()
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:113
void SetItalic(bool isItalic)
Definition: eda_text.h:169
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:61
wxPoint parseXY()
Function parseXY parses a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:206
void SetVisible(bool aVisible)
Definition: eda_text.h:175
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:461
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:219
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:263
bool parseD_PAD_option(D_PAD *aPad)
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:274
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:214
DIMENSION * parseDIMENSION()
void parseTITLE_BLOCK()
Definition: pcb_parser.cpp:705
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
Class LIB_ID.
Definition: lib_id.h:56
wxSize m_ModuleTextSize
Default footprint texts size.
#define cu(a)
Definition: auxiliary.h:88
const std::vector< wxPoint > GetPolyPoints() const
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
static int GetDefaultHatchPitch()
Function GetDefaultHatchPitchMils.
void parseLayers()
Definition: pcb_parser.cpp:830
double GetTextAngle() const
Definition: eda_text.h:164
Functions relatives to tracks, vias and segments used to fill zones.
void SetComment4(const wxString &aComment)
VECTOR3D m_Offset
3D model offset (mm)
Definition: class_module.h:100
This file contains miscellaneous commonly used macros and functions.
const wxPoint & GetArcStart() const
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:649
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:74
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.
void SetAnchorPadShape(PAD_SHAPE_T aShape)
Function SetAnchorPadShape Set the shape of the anchor pad for custm shped pads.
Definition: class_pad.h:253
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
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
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:227
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
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:194
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:976
void SetCompany(const wxString &aCompany)
bool m_visible
Definition: class_board.h:115
void SetSize(const wxSize &aSize)
Definition: class_pad.h:268
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...
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:422
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:62
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.
wxString m_Filename
The 3D shape filename in 3D library.
Definition: class_module.h:101
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:477
ZONE_CONTAINER * parseZONE_CONTAINER()
void clear()
Definition: class_board.h:92
void parseLayer(LAYER *aLayer)
Definition: pcb_parser.cpp:788
virtual void SetPosition(const wxPoint &aPos) override
Class NETINFO_ITEM handles the data for a net.
Definition: class_netinfo.h:69
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
double GetAngle() const
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
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: class_module.h:99
#define max(a, b)
Definition: auxiliary.h:86
Class LAYER holds information pertinent to a layer of a BOARD.
Definition: class_board.h:85
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:193
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:603
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.
Usual pad.
Definition: pad_shapes.h:60
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.
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
Definition: class_module.h:98
int GetWidth() const
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
PCB_TARGET class definition.
void SetCustomShapeInZoneOpt(CUST_PAD_SHAPE_IN_ZONE aOption)
Set the option for the custom pad shape to use as clearance area in copper zones. ...
Definition: class_pad.h:242
Pcbnew s-expression file format parser definition.
void SetTextAngle(double aAngle)
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:117
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)
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
void SetBold(bool aBold)
Definition: eda_text.h:172
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:73
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
wxPoint m_AuxOrigin
origin for plot exports
Class DIMENSION.
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:74
void parseSetup()
T lookUpLayer(const M &aMap)
Function lookUpLayer parses the current token for the layer definition of a BOARD_ITEM object...
Definition: pcb_parser.cpp:943
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:148
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.
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) ...
MODULE_3D_SETTINGS * parse3DModel()
Definition: pcb_parser.cpp:335