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