KiCad PCB EDA Suite
legacy_plugin.cpp
Go to the documentation of this file.
1 
2 /*
3  * This program source code file is part of KiCad, a free EDA CAD application.
4  *
5  * Copyright (C) 2007-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2004 Jean-Pierre Charras, jp.charras@wanadoo.fr
7  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 /*
28  This implements loading and saving a BOARD, behind the PLUGIN interface.
29 
30  The definitions:
31 
32  *) a Board Internal Unit (BIU) is a unit of length that is used only internally
33  to PCBNEW, and is nanometers when this work is done, but deci-mils until done.
34 
35  The philosophies:
36 
37  *) BIUs should be typed as such to distinguish them from ints. This is mostly
38  for human readability, and having the type nearby in the source supports this readability.
39  *) Do not assume that BIUs will always be int, doing a sscanf() into a BIU
40  does not make sense in case the size of the BIU changes.
41  *) variables are put onto the stack in an automatic, even when it might look
42  more efficient to do otherwise. This is so we can seem them with a debugger.
43  *) Global variables should not be touched from within a PLUGIN, since it will eventually
44  be in a DLL/DSO. This includes window information too. The PLUGIN API knows
45  nothing of wxFrame or globals and all error reporting must be done by throwing
46  an exception.
47  *) No wxWindowing calls are made in here, since the UI resides higher up than in here,
48  and is going to process a bucket of detailed information thrown from down here
49  in the form of an exception if an error happens.
50  *) Much of what we do in this source file is for human readability, not performance.
51  Simply avoiding strtok() more often than the old code washes out performance losses.
52  Remember strncmp() will bail as soon as a mismatch happens, not going all the way
53  to end of string unless a full match.
54  *) angles are in the process of migrating to doubles, and 'int' if used, is
55  only shortterm, and along with this a change, and transition from from
56  "tenths of degrees" to simply "degrees" in the double (which has no problem
57  representing any portion of a degree).
58 */
59 
60 
61 #include <cmath>
62 #include <stdio.h>
63 #include <string.h>
64 #include <errno.h>
65 #include <wx/ffile.h>
66 #include <wx/string.h>
67 #include <legacy_plugin.h> // implement this here
68 
69 #include <kicad_string.h>
70 #include <macros.h>
71 #include <properties.h>
72 #include <zones.h>
73 
74 #include <class_board.h>
75 #include <class_module.h>
76 #include <class_track.h>
77 #include <class_pcb_text.h>
78 #include <class_zone.h>
79 #include <class_dimension.h>
80 #include <class_drawsegment.h>
81 #include <class_pcb_target.h>
82 #include <class_edge_mod.h>
83 #include <3d_cache/3d_info.h>
84 #include <pcb_plot_params.h>
85 #include <pcb_plot_params_parser.h>
86 #include <convert_to_biu.h>
87 #include <trigo.h>
88 #include <build_version.h>
89 
90 
92 
93 
94 #define VERSION_ERROR_FORMAT _( "File \"%s\" is format version: %d.\nI only support format version <= %d.\nPlease upgrade Pcbnew to load this file." )
95 #define UNKNOWN_GRAPHIC_FORMAT _( "unknown graphic type: %d")
96 #define UNKNOWN_PAD_FORMAT _( "unknown pad type: %d")
97 #define UNKNOWN_PAD_ATTRIBUTE _( "unknown pad attribute: %d" )
98 
99 
100 typedef unsigned LEG_MASK;
101 
102 #define FIRST_LAYER 0
103 #define FIRST_COPPER_LAYER 0
104 #define LAYER_N_BACK 0
105 #define LAYER_N_2 1
106 #define LAYER_N_3 2
107 #define LAYER_N_4 3
108 #define LAYER_N_5 4
109 #define LAYER_N_6 5
110 #define LAYER_N_7 6
111 #define LAYER_N_8 7
112 #define LAYER_N_9 8
113 #define LAYER_N_10 9
114 #define LAYER_N_11 10
115 #define LAYER_N_12 11
116 #define LAYER_N_13 12
117 #define LAYER_N_14 13
118 #define LAYER_N_15 14
119 #define LAYER_N_FRONT 15
120 #define LAST_COPPER_LAYER LAYER_N_FRONT
121 
122 #define FIRST_NON_COPPER_LAYER 16
123 #define ADHESIVE_N_BACK 16
124 #define ADHESIVE_N_FRONT 17
125 #define SOLDERPASTE_N_BACK 18
126 #define SOLDERPASTE_N_FRONT 19
127 #define SILKSCREEN_N_BACK 20
128 #define SILKSCREEN_N_FRONT 21
129 #define SOLDERMASK_N_BACK 22
130 #define SOLDERMASK_N_FRONT 23
131 #define DRAW_N 24
132 #define COMMENT_N 25
133 #define ECO1_N 26
134 #define ECO2_N 27
135 #define EDGE_N 28
136 #define LAST_NON_COPPER_LAYER 28
137 
138 // Masks to identify a layer by a bit map
139 typedef unsigned LAYER_MSK;
140 #define LAYER_BACK (1 << LAYER_N_BACK)
141 #define LAYER_2 (1 << LAYER_N_2)
142 #define LAYER_3 (1 << LAYER_N_3)
143 #define LAYER_4 (1 << LAYER_N_4)
144 #define LAYER_5 (1 << LAYER_N_5)
145 #define LAYER_6 (1 << LAYER_N_6)
146 #define LAYER_7 (1 << LAYER_N_7)
147 #define LAYER_8 (1 << LAYER_N_8)
148 #define LAYER_9 (1 << LAYER_N_9)
149 #define LAYER_10 (1 << LAYER_N_10)
150 #define LAYER_11 (1 << LAYER_N_11)
151 #define LAYER_12 (1 << LAYER_N_12)
152 #define LAYER_13 (1 << LAYER_N_13)
153 #define LAYER_14 (1 << LAYER_N_14)
154 #define LAYER_15 (1 << LAYER_N_15)
155 #define LAYER_FRONT (1 << LAYER_N_FRONT)
156 #define ADHESIVE_LAYER_BACK (1 << ADHESIVE_N_BACK)
157 #define ADHESIVE_LAYER_FRONT (1 << ADHESIVE_N_FRONT)
158 #define SOLDERPASTE_LAYER_BACK (1 << SOLDERPASTE_N_BACK)
159 #define SOLDERPASTE_LAYER_FRONT (1 << SOLDERPASTE_N_FRONT)
160 #define SILKSCREEN_LAYER_BACK (1 << SILKSCREEN_N_BACK)
161 #define SILKSCREEN_LAYER_FRONT (1 << SILKSCREEN_N_FRONT)
162 #define SOLDERMASK_LAYER_BACK (1 << SOLDERMASK_N_BACK)
163 #define SOLDERMASK_LAYER_FRONT (1 << SOLDERMASK_N_FRONT)
164 #define DRAW_LAYER (1 << DRAW_N)
165 #define COMMENT_LAYER (1 << COMMENT_N)
166 #define ECO1_LAYER (1 << ECO1_N)
167 #define ECO2_LAYER (1 << ECO2_N)
168 #define EDGE_LAYER (1 << EDGE_N)
169 
170 // Helpful global layer masks:
171 // ALL_AUX_LAYERS layers are technical layers, ALL_NO_CU_LAYERS has user
172 // and edge layers too!
173 #define ALL_NO_CU_LAYERS 0x1FFF0000
174 #define ALL_CU_LAYERS 0x0000FFFF
175 #define FRONT_TECH_LAYERS (SILKSCREEN_LAYER_FRONT | SOLDERMASK_LAYER_FRONT \
176  | ADHESIVE_LAYER_FRONT | SOLDERPASTE_LAYER_FRONT)
177 #define BACK_TECH_LAYERS (SILKSCREEN_LAYER_BACK | SOLDERMASK_LAYER_BACK \
178  | ADHESIVE_LAYER_BACK | SOLDERPASTE_LAYER_BACK)
179 #define ALL_TECH_LAYERS (FRONT_TECH_LAYERS | BACK_TECH_LAYERS)
180 #define BACK_LAYERS (LAYER_BACK | BACK_TECH_LAYERS)
181 #define FRONT_LAYERS (LAYER_FRONT | FRONT_TECH_LAYERS)
182 
183 #define ALL_USER_LAYERS (DRAW_LAYER | COMMENT_LAYER | ECO1_LAYER | ECO2_LAYER )
184 
185 #define NO_LAYERS 0x00000000
186 
187 
188 // Old internal units definition (UI = decimil)
189 #define PCB_LEGACY_INTERNAL_UNIT 10000
190 
192 #define SZ( x ) (sizeof(x)-1)
193 
194 
195 static const char delims[] = " \t\r\n";
196 
197 
198 static bool inline isSpace( int c ) { return strchr( delims, c ) != 0; }
199 
200 #define MASK(x) (1<<(x))
201 
202 //-----<BOARD Load Functions>---------------------------------------------------
203 
205 #define TESTLINE( x ) ( !strncasecmp( line, x, SZ( x ) ) && isSpace( line[SZ( x )] ) )
206 
208 #define TESTSUBSTR( x ) ( !strncasecmp( line, x, SZ( x ) ) )
209 
210 
211 #if 1
212 #define READLINE( rdr ) rdr->ReadLine()
213 
214 #else
215 static inline char* ReadLine( LINE_READER* rdr, const char* caller )
219 {
220  char* ret = rdr->ReadLine();
221 
222  const char* line = rdr->Line();
223  printf( "%-6u %s: %s", rdr->LineNumber(), caller, line );
224 
225 #if 0 // trap
226  if( !strcmp( "loadSETUP", caller ) && !strcmp( "$EndSETUP\n", line ) )
227  {
228  int breakhere = 1;
229  }
230 #endif
231 
232  return ret;
233 }
234 #define READLINE( rdr ) ReadLine( rdr, __FUNCTION__ )
235 #endif
236 
237 
238 
239 using std::unique_ptr;
240 
241 
242 static EDA_TEXT_HJUSTIFY_T horizJustify( const char* horizontal )
243 {
244  if( !strcmp( "L", horizontal ) )
245  return GR_TEXT_HJUSTIFY_LEFT;
246  if( !strcmp( "R", horizontal ) )
247  return GR_TEXT_HJUSTIFY_RIGHT;
249 }
250 
251 static EDA_TEXT_VJUSTIFY_T vertJustify( const char* vertical )
252 {
253  if( !strcmp( "T", vertical ) )
254  return GR_TEXT_VJUSTIFY_TOP;
255  if( !strcmp( "B", vertical ) )
258 }
259 
260 
262 inline int layerMaskCountSet( LEG_MASK aMask )
263 {
264  int count = 0;
265 
266  for( int i = 0; aMask; ++i, aMask >>= 1 )
267  {
268  if( aMask & 1 )
269  ++count;
270  }
271 
272  return count;
273 }
274 
275 
276 // return true if aLegacyLayerNum is a valid copper layer legacy id, therefore
277 // top, bottom or inner activated layer
278 inline bool is_leg_copperlayer_valid( int aCu_Count, LAYER_NUM aLegacyLayerNum )
279 {
280  return ( aLegacyLayerNum == LAYER_N_FRONT ) || ( aLegacyLayerNum < aCu_Count );
281 }
282 
283 
285 {
286  int newid;
287  unsigned old = aLayerNum;
288 
289  // this is a speed critical function, be careful.
290 
291  if( unsigned( old ) <= unsigned( LAYER_N_FRONT ) )
292  {
293  if( old == LAYER_N_FRONT )
294  newid = F_Cu;
295  else if( old == LAYER_N_BACK )
296  newid = B_Cu;
297  else
298  {
299  newid = cu_count - 1 - old;
300  wxASSERT( newid >= 0 );
301  }
302  }
303  else
304  {
305  switch( old )
306  {
307  case ADHESIVE_N_BACK: newid = B_Adhes; break;
308  case ADHESIVE_N_FRONT: newid = F_Adhes; break;
309  case SOLDERPASTE_N_BACK: newid = B_Paste; break;
310  case SOLDERPASTE_N_FRONT: newid = F_Paste; break;
311  case SILKSCREEN_N_BACK: newid = B_SilkS; break;
312  case SILKSCREEN_N_FRONT: newid = F_SilkS; break;
313  case SOLDERMASK_N_BACK: newid = B_Mask; break;
314  case SOLDERMASK_N_FRONT: newid = F_Mask; break;
315  case DRAW_N: newid = Dwgs_User; break;
316  case COMMENT_N: newid = Cmts_User; break;
317  case ECO1_N: newid = Eco1_User; break;
318  case ECO2_N: newid = Eco2_User; break;
319  case EDGE_N: newid = Edge_Cuts; break;
320  default:
321 // wxASSERT( 0 );
322  // Remap all illegal non copper layers to comment layer
323  newid = Cmts_User;
324  }
325  }
326 
327  return PCB_LAYER_ID( newid );
328 }
329 
330 
331 LSET LEGACY_PLUGIN::leg_mask2new( int cu_count, unsigned aMask )
332 {
333  LSET ret;
334 
335  if( ( aMask & ALL_CU_LAYERS ) == ALL_CU_LAYERS )
336  {
337  ret = LSET::AllCuMask();
338 
339  aMask &= ~ALL_CU_LAYERS;
340  }
341 
342  for( int i=0; aMask; ++i, aMask >>= 1 )
343  {
344  if( aMask & 1 )
345  ret.set( leg_layer2new( cu_count, i ) );
346  }
347 
348  return ret;
349 }
350 
351 
359 static inline int intParse( const char* next, const char** out = NULL )
360 {
361  // please just compile this and be quiet, hide casting ugliness:
362  return (int) strtol( next, (char**) out, 10 );
363 }
364 
369 static inline LAYER_NUM layerParse( const char* next, const char** out = NULL )
370 {
371  return intParse( next, out );
372 }
373 
381 static inline long hexParse( const char* next, const char** out = NULL )
382 {
383  // please just compile this and be quiet, hide casting ugliness:
384  return strtol( next, (char**) out, 16 );
385 }
386 
387 
388 BOARD* LEGACY_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,
389  const PROPERTIES* aProperties )
390 {
391  LOCALE_IO toggle; // toggles on, then off, the C locale.
392 
393  init( aProperties );
394 
395  m_board = aAppendToMe ? aAppendToMe : new BOARD();
396 
397  // Give the filename to the board if it's new
398  if( !aAppendToMe )
399  m_board->SetFileName( aFileName );
400 
401  // delete on exception, iff I own m_board, according to aAppendToMe
402  unique_ptr<BOARD> deleter( aAppendToMe ? NULL : m_board );
403 
404  FILE_LINE_READER reader( aFileName );
405 
406  m_reader = &reader; // member function accessibility
407 
408  checkVersion();
409 
410  loadAllSections( bool( aAppendToMe ) );
411 
412  deleter.release();
413  return m_board;
414 }
415 
416 
417 void LEGACY_PLUGIN::loadAllSections( bool doAppend )
418 {
419  // $GENERAL section is first
420 
421  // $SHEETDESCR section is next
422 
423  // $SETUP section is next
424 
425  // Then follows $EQUIPOT and all the rest
426  char* line;
427 
428  while( ( line = READLINE( m_reader ) ) != NULL )
429  {
430  // put the more frequent ones at the top, but realize TRACKs are loaded as a group
431 
432  if( TESTLINE( "$MODULE" ) )
433  {
434  unique_ptr<MODULE> module( new MODULE( m_board ) );
435 
436  LIB_ID fpid;
437  std::string fpName = StrPurge( line + SZ( "$MODULE" ) );
438 
439  // The footprint names in legacy libraries can contain the '/' and ':'
440  // characters which will cause the FPID parser to choke.
441  ReplaceIllegalFileNameChars( &fpName );
442 
443  if( !fpName.empty() )
444  fpid.Parse( fpName, LIB_ID::ID_PCB, true );
445 
446  module->SetFPID( fpid );
447 
448  loadMODULE( module.get() );
449  m_board->Add( module.release(), ADD_APPEND );
450  }
451 
452  else if( TESTLINE( "$DRAWSEGMENT" ) )
453  {
454  loadPCB_LINE();
455  }
456 
457  else if( TESTLINE( "$EQUIPOT" ) )
458  {
460  }
461 
462  else if( TESTLINE( "$TEXTPCB" ) )
463  {
464  loadPCB_TEXT();
465  }
466 
467  else if( TESTLINE( "$TRACK" ) )
468  {
470  }
471 
472  else if( TESTLINE( "$NCLASS" ) )
473  {
474  loadNETCLASS();
475  }
476 
477  else if( TESTLINE( "$CZONE_OUTLINE" ) )
478  {
480  }
481 
482  else if( TESTLINE( "$COTATION" ) )
483  {
484  loadDIMENSION();
485  }
486 
487  else if( TESTLINE( "$PCB_TARGET" ) || TESTLINE( "$MIREPCB" ) )
488  {
489  loadPCB_TARGET();
490  }
491 
492  else if( TESTLINE( "$ZONE" ) )
493  {
495  }
496 
497  else if( TESTLINE( "$GENERAL" ) )
498  {
499  loadGENERAL();
500  }
501 
502  else if( TESTLINE( "$SHEETDESCR" ) )
503  {
504  loadSHEET();
505  }
506 
507  else if( TESTLINE( "$SETUP" ) )
508  {
509  if( !doAppend )
510  {
511  loadSETUP();
512  }
513  else
514  {
515  while( ( line = READLINE( m_reader ) ) != NULL )
516  {
517  // gobble until $EndSetup
518  if( TESTLINE( "$EndSETUP" ) )
519  break;
520  }
521  }
522  }
523 
524  else if( TESTLINE( "$EndBOARD" ) )
525  return; // preferred exit
526  }
527 
528  THROW_IO_ERROR( "Missing '$EndBOARD'" );
529 }
530 
531 
533 {
534  // Read first line and TEST if it is a PCB file format header like this:
535  // "PCBNEW-BOARD Version 1 ...."
536 
537  m_reader->ReadLine();
538 
539  char* line = m_reader->Line();
540 
541  if( !TESTLINE( "PCBNEW-BOARD" ) )
542  {
543  THROW_IO_ERROR( "Unknown file type" );
544  }
545 
546  int ver = 1; // if sccanf fails
547  sscanf( line, "PCBNEW-BOARD Version %d", &ver );
548 
549 #if !defined(DEBUG)
550  if( ver > LEGACY_BOARD_FILE_VERSION )
551  {
552  // "File \"%s\" is format version: %d.\nI only support format version <= %d.\nPlease upgrade Pcbnew to load this file."
554  m_reader->GetSource().GetData(), ver, LEGACY_BOARD_FILE_VERSION );
556  }
557 #endif
558 
561 }
562 
563 
565 {
566  char* line;
567  char* saveptr;
568  bool saw_LayerCount = false;
569 
570  while( ( line = READLINE( m_reader ) ) != NULL )
571  {
572  const char* data;
573 
574  if( TESTLINE( "Units" ) )
575  {
576  // what are the engineering units of the lengths in the BOARD?
577  data = strtok_r( line + SZ("Units"), delims, &saveptr );
578 
579  if( !strcmp( data, "mm" ) )
580  {
581  diskToBiu = IU_PER_MM;
582  }
583  }
584 
585  else if( TESTLINE( "LayerCount" ) )
586  {
587  int tmp = intParse( line + SZ( "LayerCount" ) );
589 
590  // This has to be set early so that leg_layer2new() works OK, and
591  // that means before parsing "EnabledLayers" and "VisibleLayers".
592  m_cu_count = tmp;
593 
594  saw_LayerCount = true;
595  }
596 
597  else if( TESTLINE( "EnabledLayers" ) )
598  {
599  if( !saw_LayerCount )
600  THROW_IO_ERROR( "Missing '$GENERAL's LayerCount" );
601 
602  LEG_MASK enabledLayers = hexParse( line + SZ( "EnabledLayers" ) );
603 
604  LSET new_mask = leg_mask2new( m_cu_count, enabledLayers );
605 
606  //DBG( printf( "EnabledLayers: %s\n", new_mask.FmtHex().c_str() );)
607 
608  m_board->SetEnabledLayers( new_mask );
609 
610  // layer visibility equals layer usage, unless overridden later via "VisibleLayers"
611  // Must call SetEnabledLayers() before calling SetVisibleLayers().
612  m_board->SetVisibleLayers( new_mask );
613  }
614 
615  else if( TESTLINE( "VisibleLayers" ) )
616  {
617  if( !saw_LayerCount )
618  THROW_IO_ERROR( "Missing '$GENERAL's LayerCount" );
619 
620  LEG_MASK visibleLayers = hexParse( line + SZ( "VisibleLayers" ) );
621 
622  LSET new_mask = leg_mask2new( m_cu_count, visibleLayers );
623 
624  m_board->SetVisibleLayers( new_mask );
625  }
626 
627  else if( TESTLINE( "Ly" ) ) // Old format for Layer count
628  {
629  if( !saw_LayerCount )
630  {
631  LEG_MASK layer_mask = hexParse( line + SZ( "Ly" ) );
632 
633  m_cu_count = layerMaskCountSet( layer_mask & ALL_CU_LAYERS );
634 
636 
637  saw_LayerCount = true;
638  }
639  }
640 
641  else if( TESTLINE( "BoardThickness" ) )
642  {
643  BIU thickn = biuParse( line + SZ( "BoardThickness" ) );
645  }
646 
647  /*
648  else if( TESTLINE( "Links" ) )
649  {
650  // Info only, do nothing, but only for a short while.
651  }
652  */
653 
654  else if( TESTLINE( "NoConn" ) )
655  {
656  // ignore
657  intParse( line + SZ( "NoConn" ) );
658  }
659 
660  else if( TESTLINE( "Di" ) )
661  {
662  biuParse( line + SZ( "Di" ), &data );
663  biuParse( data, &data );
664  biuParse( data, &data );
665  biuParse( data );
666  }
667 
668  /* This is no more usefull, so this info is no more parsed
669  // Read the number of segments of type DRAW, TRACK, ZONE
670  else if( TESTLINE( "Ndraw" ) )
671  {
672  NbDraw = intParse( line + SZ( "Ndraw" ) );
673  }
674 
675  else if( TESTLINE( "Ntrack" ) )
676  {
677  NbTrack = intParse( line + SZ( "Ntrack" ) );
678  }
679 
680  else if( TESTLINE( "Nzone" ) )
681  {
682  NbZone = intParse( line + SZ( "Nzone" ) );
683  }
684 
685  else if( TESTLINE( "Nmodule" ) )
686  {
687  NbMod = intParse( line + SZ( "Nmodule" ) );
688  }*/
689 
690  else if( TESTLINE( "Nnets" ) )
691  {
692  m_netCodes.resize( intParse( line + SZ( "Nnets" ) ) );
693  }
694 
695  else if( TESTLINE( "Nn" ) ) // id "Nnets" for old .brd files
696  {
697  m_netCodes.resize( intParse( line + SZ( "Nn" ) ) );
698  }
699 
700  else if( TESTLINE( "$EndGENERAL" ) )
701  return; // preferred exit
702  }
703 
704  THROW_IO_ERROR( "Missing '$EndGENERAL'" );
705 }
706 
707 
709 {
710  char buf[260];
711  TITLE_BLOCK tb;
712  char* line;
713  char* saveptr;
714 
715  while( ( line = READLINE( m_reader ) ) != NULL )
716  {
717  if( TESTLINE( "Sheet" ) )
718  {
719  // e.g. "Sheet A3 16535 11700"
720  // width and height are in 1/1000th of an inch, always
721 
722  PAGE_INFO page;
723  char* sname = strtok_r( line + SZ( "Sheet" ), delims, &saveptr );
724 
725  if( sname )
726  {
727  wxString wname = FROM_UTF8( sname );
728  if( !page.SetType( wname ) )
729  {
730  m_error.Printf( _( "Unknown sheet type \"%s\" on line:%d" ),
731  wname.GetData(), m_reader->LineNumber() );
733  }
734 
735  char* width = strtok_r( NULL, delims, &saveptr );
736  char* height = strtok_r( NULL, delims, &saveptr );
737  char* orient = strtok_r( NULL, delims, &saveptr );
738 
739  // only parse the width and height if page size is custom ("User")
740  if( wname == PAGE_INFO::Custom )
741  {
742  if( width && height )
743  {
744  // legacy disk file describes paper in mils
745  // (1/1000th of an inch)
746  int w = intParse( width );
747  int h = intParse( height );
748 
749  page.SetWidthMils( w );
750  page.SetHeightMils( h );
751  }
752  }
753 
754  if( orient && !strcmp( orient, "portrait" ) )
755  {
756  page.SetPortrait( true );
757  }
758 
759  m_board->SetPageSettings( page );
760  }
761  }
762 
763  else if( TESTLINE( "Title" ) )
764  {
765  ReadDelimitedText( buf, line, sizeof(buf) );
766  tb.SetTitle( FROM_UTF8( buf ) );
767  }
768 
769  else if( TESTLINE( "Date" ) )
770  {
771  ReadDelimitedText( buf, line, sizeof(buf) );
772  tb.SetDate( FROM_UTF8( buf ) );
773  }
774 
775  else if( TESTLINE( "Rev" ) )
776  {
777  ReadDelimitedText( buf, line, sizeof(buf) );
778  tb.SetRevision( FROM_UTF8( buf ) );
779  }
780 
781  else if( TESTLINE( "Comp" ) )
782  {
783  ReadDelimitedText( buf, line, sizeof(buf) );
784  tb.SetCompany( FROM_UTF8( buf ) );
785  }
786 
787  else if( TESTLINE( "Comment1" ) )
788  {
789  ReadDelimitedText( buf, line, sizeof(buf) );
790  tb.SetComment1( FROM_UTF8( buf ) );
791  }
792 
793  else if( TESTLINE( "Comment2" ) )
794  {
795  ReadDelimitedText( buf, line, sizeof(buf) );
796  tb.SetComment2( FROM_UTF8( buf ) );
797  }
798 
799  else if( TESTLINE( "Comment3" ) )
800  {
801  ReadDelimitedText( buf, line, sizeof(buf) );
802  tb.SetComment3( FROM_UTF8( buf ) );
803  }
804 
805  else if( TESTLINE( "Comment4" ) )
806  {
807  ReadDelimitedText( buf, line, sizeof(buf) );
808  tb.SetComment4( FROM_UTF8( buf ) );
809  }
810 
811  else if( TESTLINE( "$EndSHEETDESCR" ) )
812  {
813  m_board->SetTitleBlock( tb );
814  return; // preferred exit
815  }
816  }
817 
818  THROW_IO_ERROR( "Missing '$EndSHEETDESCR'" );
819 }
820 
821 
823 {
824  NETCLASSPTR netclass_default = m_board->GetDesignSettings().GetDefault();
825  // TODO Orson: is it really necessary to first operate on a copy and then apply it?
826  // would not it be better to use reference here and apply all the changes instantly?
829  char* line;
830  char* saveptr;
831 
832  while( ( line = READLINE( m_reader ) ) != NULL )
833  {
834  const char* data;
835 
836  if( TESTLINE( "PcbPlotParams" ) )
837  {
838  PCB_PLOT_PARAMS plot_opts;
839 
840  PCB_PLOT_PARAMS_PARSER parser( line + SZ( "PcbPlotParams" ), m_reader->GetSource() );
841 
842  plot_opts.Parse( &parser );
843 
844  m_board->SetPlotOptions( plot_opts );
845  }
846 
847  else if( TESTLINE( "AuxiliaryAxisOrg" ) )
848  {
849  BIU gx = biuParse( line + SZ( "AuxiliaryAxisOrg" ), &data );
850  BIU gy = biuParse( data );
851 
852  // m_board->SetAuxOrigin( wxPoint( gx, gy ) ); gets overwritten by SetDesignSettings() below
853  bds.m_AuxOrigin = wxPoint( gx, gy );
854  }
855 
856  /* Done from $General above's "LayerCount"
857  else if( TESTLINE( "Layers" ) )
858  {
859  int tmp = intParse( line + SZ( "Layers" ) );
860  m_board->SetCopperLayerCount( tmp );
861 
862  m_cu_count = tmp;
863  }
864  */
865 
866  else if( TESTSUBSTR( "Layer[" ) )
867  {
868  // eg: "Layer[n] <a_Layer_name_with_no_spaces> <LAYER_T>"
869 
870  LAYER_NUM layer_num = layerParse( line + SZ( "Layer[" ), &data );
871  PCB_LAYER_ID layer_id = leg_layer2new( m_cu_count, layer_num );
872 
873  /*
874  switch( layer_num )
875  {
876  case LAYER_N_BACK:
877  layer_id = B_Cu;
878  break;
879 
880  case LAYER_N_FRONT:
881  layer_id = F_Cu;
882  break;
883 
884  default:
885  layer_id = PCB_LAYER_ID( layer_num );
886  }
887  */
888 
889  data = strtok_r( (char*) data+1, delims, &saveptr ); // +1 for ']'
890  if( data )
891  {
892  wxString layerName = FROM_UTF8( data );
893  m_board->SetLayerName( layer_id, layerName );
894 
895  data = strtok_r( NULL, delims, &saveptr );
896  if( data ) // optional in old board files
897  {
898  LAYER_T type = LAYER::ParseType( data );
899  m_board->SetLayerType( layer_id, type );
900  }
901  }
902  }
903 
904  else if( TESTLINE( "TrackWidth" ) )
905  {
906  BIU tmp = biuParse( line + SZ( "TrackWidth" ) );
907  netclass_default->SetTrackWidth( tmp );
908  }
909 
910  else if( TESTLINE( "TrackWidthList" ) )
911  {
912  BIU tmp = biuParse( line + SZ( "TrackWidthList" ) );
913  bds.m_TrackWidthList.push_back( tmp );
914  }
915 
916  else if( TESTLINE( "TrackClearence" ) )
917  {
918  BIU tmp = biuParse( line + SZ( "TrackClearence" ) );
919  netclass_default->SetClearance( tmp );
920  }
921 
922  else if( TESTLINE( "TrackMinWidth" ) )
923  {
924  BIU tmp = biuParse( line + SZ( "TrackMinWidth" ) );
925  bds.m_TrackMinWidth = tmp;
926  }
927 
928  else if( TESTLINE( "ZoneClearence" ) )
929  {
930  BIU tmp = biuParse( line + SZ( "ZoneClearence" ) );
931  zs.m_ZoneClearance = tmp;
932  }
933 
934  else if( TESTLINE( "Zone_45_Only" ) )
935  {
936  bool tmp = (bool) intParse( line + SZ( "Zone_45_Only" ) );
937  zs.m_Zone_45_Only = tmp;
938  }
939 
940  else if( TESTLINE( "DrawSegmWidth" ) )
941  {
942  BIU tmp = biuParse( line + SZ( "DrawSegmWidth" ) );
943  bds.m_LineThickness[ LAYER_CLASS_COPPER ] = tmp;
944  }
945 
946  else if( TESTLINE( "EdgeSegmWidth" ) )
947  {
948  BIU tmp = biuParse( line + SZ( "EdgeSegmWidth" ) );
949  bds.m_LineThickness[ LAYER_CLASS_EDGES ] = tmp;
950  }
951 
952  else if( TESTLINE( "ViaMinSize" ) )
953  {
954  BIU tmp = biuParse( line + SZ( "ViaMinSize" ) );
955  bds.m_ViasMinSize = tmp;
956  }
957 
958  else if( TESTLINE( "MicroViaMinSize" ) )
959  {
960  BIU tmp = biuParse( line + SZ( "MicroViaMinSize" ) );
961  bds.m_MicroViasMinSize = tmp;
962  }
963 
964  else if( TESTLINE( "ViaSizeList" ) )
965  {
966  // e.g. "ViaSizeList DIAMETER [DRILL]"
967 
968  BIU drill = 0;
969  BIU diameter = biuParse( line + SZ( "ViaSizeList" ), &data );
970 
971  data = strtok_r( (char*) data, delims, &saveptr );
972  if( data ) // DRILL may not be present ?
973  drill = biuParse( data );
974 
975  bds.m_ViasDimensionsList.push_back( VIA_DIMENSION( diameter,
976  drill ) );
977  }
978 
979  else if( TESTLINE( "ViaSize" ) )
980  {
981  BIU tmp = biuParse( line + SZ( "ViaSize" ) );
982  netclass_default->SetViaDiameter( tmp );
983  }
984 
985  else if( TESTLINE( "ViaDrill" ) )
986  {
987  BIU tmp = biuParse( line + SZ( "ViaDrill" ) );
988  netclass_default->SetViaDrill( tmp );
989  }
990 
991  else if( TESTLINE( "ViaMinDrill" ) )
992  {
993  BIU tmp = biuParse( line + SZ( "ViaMinDrill" ) );
994  bds.m_ViasMinDrill = tmp;
995  }
996 
997  else if( TESTLINE( "MicroViaSize" ) )
998  {
999  BIU tmp = biuParse( line + SZ( "MicroViaSize" ) );
1000  netclass_default->SetuViaDiameter( tmp );
1001  }
1002 
1003  else if( TESTLINE( "MicroViaDrill" ) )
1004  {
1005  BIU tmp = biuParse( line + SZ( "MicroViaDrill" ) );
1006  netclass_default->SetuViaDrill( tmp );
1007  }
1008 
1009  else if( TESTLINE( "MicroViaMinDrill" ) )
1010  {
1011  BIU tmp = biuParse( line + SZ( "MicroViaMinDrill" ) );
1012  bds.m_MicroViasMinDrill = tmp;
1013  }
1014 
1015  else if( TESTLINE( "MicroViasAllowed" ) )
1016  {
1017  int tmp = intParse( line + SZ( "MicroViasAllowed" ) );
1018  bds.m_MicroViasAllowed = tmp;
1019  }
1020 
1021  else if( TESTLINE( "TextPcbWidth" ) )
1022  {
1023  BIU tmp = biuParse( line + SZ( "TextPcbWidth" ) );
1024  bds.m_TextThickness[ LAYER_CLASS_COPPER ] = tmp;
1025  }
1026 
1027  else if( TESTLINE( "TextPcbSize" ) )
1028  {
1029  BIU x = biuParse( line + SZ( "TextPcbSize" ), &data );
1030  BIU y = biuParse( data );
1031 
1032  bds.m_TextSize[ LAYER_CLASS_COPPER ] = wxSize( x, y );
1033  }
1034 
1035  else if( TESTLINE( "EdgeModWidth" ) )
1036  {
1037  BIU tmp = biuParse( line + SZ( "EdgeModWidth" ) );
1038  bds.m_LineThickness[ LAYER_CLASS_SILK ] = tmp;
1039  bds.m_LineThickness[ LAYER_CLASS_OTHERS ] = tmp;
1040  }
1041 
1042  else if( TESTLINE( "TextModWidth" ) )
1043  {
1044  BIU tmp = biuParse( line + SZ( "TextModWidth" ) );
1045  bds.m_TextThickness[ LAYER_CLASS_SILK ] = tmp;
1046  bds.m_TextThickness[ LAYER_CLASS_OTHERS ] = tmp;
1047  }
1048 
1049  else if( TESTLINE( "TextModSize" ) )
1050  {
1051  BIU x = biuParse( line + SZ( "TextModSize" ), &data );
1052  BIU y = biuParse( data );
1053 
1054  bds.m_TextSize[ LAYER_CLASS_SILK ] = wxSize( x, y );
1055  bds.m_TextSize[ LAYER_CLASS_OTHERS ] = wxSize( x, y );
1056  }
1057 
1058  else if( TESTLINE( "PadSize" ) )
1059  {
1060  BIU x = biuParse( line + SZ( "PadSize" ), &data );
1061  BIU y = biuParse( data );
1062 
1063  bds.m_Pad_Master.SetSize( wxSize( x, y ) );
1064  }
1065 
1066  else if( TESTLINE( "PadDrill" ) )
1067  {
1068  BIU tmp = biuParse( line + SZ( "PadDrill" ) );
1069  bds.m_Pad_Master.SetDrillSize( wxSize( tmp, tmp ) );
1070  }
1071 
1072  else if( TESTLINE( "Pad2MaskClearance" ) )
1073  {
1074  BIU tmp = biuParse( line + SZ( "Pad2MaskClearance" ) );
1075  bds.m_SolderMaskMargin = tmp;
1076  }
1077 
1078  else if( TESTLINE( "SolderMaskMinWidth" ) )
1079  {
1080  BIU tmp = biuParse( line + SZ( "SolderMaskMinWidth" ) );
1081  bds.m_SolderMaskMinWidth = tmp;
1082  }
1083 
1084  else if( TESTLINE( "Pad2PasteClearance" ) )
1085  {
1086  BIU tmp = biuParse( line + SZ( "Pad2PasteClearance" ) );
1087  bds.m_SolderPasteMargin = tmp;
1088  }
1089 
1090  else if( TESTLINE( "Pad2PasteClearanceRatio" ) )
1091  {
1092  double ratio = atof( line + SZ( "Pad2PasteClearanceRatio" ) );
1093  bds.m_SolderPasteMarginRatio = ratio;
1094  }
1095 
1096  else if( TESTLINE( "GridOrigin" ) )
1097  {
1098  BIU x = biuParse( line + SZ( "GridOrigin" ), &data );
1099  BIU y = biuParse( data );
1100 
1101  // m_board->SetGridOrigin( wxPoint( x, y ) ); gets overwritten by SetDesignSettings() below
1102  bds.m_GridOrigin = wxPoint( x, y );
1103  }
1104 
1105  else if( TESTLINE( "VisibleElements" ) )
1106  {
1107  int visibleElements = hexParse( line + SZ( "VisibleElements" ) );
1108  bds.SetVisibleElements( visibleElements );
1109  }
1110 
1111  else if( TESTLINE( "$EndSETUP" ) )
1112  {
1113  m_board->SetDesignSettings( bds );
1114  m_board->SetZoneSettings( zs );
1115 
1116  // Very old *.brd file does not have NETCLASSes
1117  // "TrackWidth", "ViaSize", "ViaDrill", "ViaMinSize",
1118  // and "TrackClearence", were defined in SETUP
1119  // these values are put into the default NETCLASS until later board load
1120  // code should override them. *.brd files which have been
1121  // saved with knowledge of NETCLASSes will override these
1122  // defaults, very old boards (before 2009) will not and use the setup values.
1123  // However these values should be the same as default NETCLASS.
1124 
1125  return; // preferred exit
1126  }
1127  }
1128 
1129  // @todo: this code is currently unreachable, would need a goto, to get here.
1130  // that may be better handled with an #ifdef
1131 
1132  /* Ensure tracks and vias sizes lists are ok:
1133  * Sort lists by by increasing value and remove duplicates
1134  * (the first value is not tested, because it is the netclass value
1135  */
1136  BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1137  sort( designSettings.m_ViasDimensionsList.begin() + 1, designSettings.m_ViasDimensionsList.end() );
1138  sort( designSettings.m_TrackWidthList.begin() + 1, designSettings.m_TrackWidthList.end() );
1139 
1140  for( unsigned ii = 1; ii < designSettings.m_ViasDimensionsList.size() - 1; ii++ )
1141  {
1142  if( designSettings.m_ViasDimensionsList[ii] == designSettings.m_ViasDimensionsList[ii + 1] )
1143  {
1144  designSettings.m_ViasDimensionsList.erase( designSettings.m_ViasDimensionsList.begin() + ii );
1145  ii--;
1146  }
1147  }
1148 
1149  for( unsigned ii = 1; ii < designSettings.m_TrackWidthList.size() - 1; ii++ )
1150  {
1151  if( designSettings.m_TrackWidthList[ii] == designSettings.m_TrackWidthList[ii + 1] )
1152  {
1153  designSettings.m_TrackWidthList.erase( designSettings.m_TrackWidthList.begin() + ii );
1154  ii--;
1155  }
1156  }
1157 }
1158 
1159 
1161 {
1162  char* line;
1163  char* saveptr;
1164 
1165  while( ( line = READLINE( m_reader ) ) != NULL )
1166  {
1167  const char* data;
1168 
1169  // most frequently encountered ones at the top
1170 
1171  if( TESTSUBSTR( "D" ) && strchr( "SCAP", line[1] ) ) // read a drawing item, e.g. "DS"
1172  {
1173  loadMODULE_EDGE( aModule );
1174  }
1175 
1176  else if( TESTLINE( "$PAD" ) )
1177  {
1178  loadPAD( aModule );
1179  }
1180 
1181  // Read a footprint text description (ref, value, or drawing)
1182  else if( TESTSUBSTR( "T" ) )
1183  {
1184  // e.g. "T1 6940 -16220 350 300 900 60 M I 20 N "CFCARD"\r\n"
1185 
1186  int tnum = intParse( line + SZ( "T" ) );
1187 
1188  TEXTE_MODULE* textm = 0;
1189 
1190  switch( tnum )
1191  {
1193  textm = &aModule->Reference();
1194  break;
1195 
1197  textm = &aModule->Value();
1198  break;
1199 
1200  // All other fields greater than 1.
1201  default:
1202  textm = new TEXTE_MODULE( aModule );
1203  aModule->GraphicalItemsList().PushBack( textm );
1204  }
1205 
1206  loadMODULE_TEXT( textm );
1207  }
1208 
1209  else if( TESTLINE( "Po" ) )
1210  {
1211  // e.g. "Po 19120 39260 900 0 4E823D06 46EAAFA5 ~~\r\n"
1212 
1213  // sscanf( PtLine, "%d %d %d %d %lX %lX %s", &m_Pos.x, &m_Pos.y, &m_Orient, &m_Layer, &m_LastEdit_Time, &m_TimeStamp, BufCar1 );
1214 
1215  BIU pos_x = biuParse( line + SZ( "Po" ), &data );
1216  BIU pos_y = biuParse( data, &data );
1217  int orient = intParse( data, &data );
1218 
1219  LAYER_NUM layer_num = layerParse( data, &data );
1220  PCB_LAYER_ID layer_id = leg_layer2new( m_cu_count, layer_num );
1221 
1222  long edittime = hexParse( data, &data );
1223  timestamp_t timestamp = hexParse( data, &data );
1224 
1225  data = strtok_r( (char*) data+1, delims, &saveptr );
1226 
1227  // data is now a two character long string
1228  // Note: some old files do not have this field
1229  if( data && data[0] == 'F' )
1230  aModule->SetLocked( true );
1231 
1232  if( data && data[1] == 'P' )
1233  aModule->SetIsPlaced( true );
1234 
1235  aModule->SetPosition( wxPoint( pos_x, pos_y ) );
1236  aModule->SetLayer( layer_id );
1237  aModule->SetOrientation( orient );
1238  aModule->SetTimeStamp( timestamp );
1239  aModule->SetLastEditTime( edittime );
1240  }
1241 
1242  /* footprint name set earlier, immediately after MODULE construction
1243  else if( TESTLINE( "Li" ) ) // Library name of footprint
1244  {
1245  // There can be whitespace in the footprint name on some old libraries.
1246  // Grab everything after "Li" up to end of line:
1247  //aModule->SetFPID( FROM_UTF8( StrPurge( line + SZ( "Li" ) ) ) );
1248  }
1249  */
1250 
1251  else if( TESTLINE( "Sc" ) ) // timestamp
1252  {
1253  timestamp_t timestamp = hexParse( line + SZ( "Sc" ) );
1254  aModule->SetTimeStamp( timestamp );
1255  }
1256 
1257  else if( TESTLINE( "Op" ) ) // (Op)tions for auto placement
1258  {
1259  int itmp1 = hexParse( line + SZ( "Op" ), &data );
1260  int itmp2 = hexParse( data );
1261 
1262  int cntRot180 = itmp2 & 0x0F;
1263  if( cntRot180 > 10 )
1264  cntRot180 = 10;
1265 
1266  aModule->SetPlacementCost180( cntRot180 );
1267 
1268  int cntRot90 = itmp1 & 0x0F;
1269  if( cntRot90 > 10 )
1270  cntRot90 = 0;
1271 
1272  itmp1 = (itmp1 >> 4) & 0x0F;
1273  if( itmp1 > 10 )
1274  itmp1 = 0;
1275 
1276  aModule->SetPlacementCost90( (itmp1 << 4) | cntRot90 );
1277  }
1278 
1279  else if( TESTLINE( "At" ) ) // (At)tributes of module
1280  {
1281  int attrs = MOD_DEFAULT;
1282 
1283  data = line + SZ( "At" );
1284 
1285  if( strstr( data, "SMD" ) )
1286  attrs |= MOD_CMS;
1287 
1288  if( strstr( data, "VIRTUAL" ) )
1289  attrs |= MOD_VIRTUAL;
1290 
1291  aModule->SetAttributes( attrs );
1292  }
1293 
1294  else if( TESTLINE( "AR" ) ) // Alternate Reference
1295  {
1296  // e.g. "AR /47BA2624/45525076"
1297  data = strtok_r( line + SZ( "AR" ), delims, &saveptr );
1298  if( data )
1299  aModule->SetPath( FROM_UTF8( data ) );
1300  }
1301 
1302  else if( TESTLINE( "$SHAPE3D" ) )
1303  {
1304  load3D( aModule );
1305  }
1306 
1307  else if( TESTLINE( "Cd" ) )
1308  {
1309  // e.g. "Cd Double rangee de contacts 2 x 4 pins\r\n"
1310  aModule->SetDescription( FROM_UTF8( StrPurge( line + SZ( "Cd" ) ) ) );
1311  }
1312 
1313  else if( TESTLINE( "Kw" ) ) // Key words
1314  {
1315  aModule->SetKeywords( FROM_UTF8( StrPurge( line + SZ( "Kw" ) ) ) );
1316  }
1317 
1318  else if( TESTLINE( ".SolderPasteRatio" ) )
1319  {
1320  double tmp = atof( line + SZ( ".SolderPasteRatio" ) );
1321  // Due to a bug in dialog editor in Modedit, fixed in BZR version 3565
1322  // this parameter can be broken.
1323  // It should be >= -50% (no solder paste) and <= 0% (full area of the pad)
1324 
1325  if( tmp < -0.50 )
1326  tmp = -0.50;
1327  if( tmp > 0.0 )
1328  tmp = 0.0;
1329  aModule->SetLocalSolderPasteMarginRatio( tmp );
1330  }
1331 
1332  else if( TESTLINE( ".SolderPaste" ) )
1333  {
1334  BIU tmp = biuParse( line + SZ( ".SolderPaste" ) );
1335  aModule->SetLocalSolderPasteMargin( tmp );
1336  }
1337 
1338  else if( TESTLINE( ".SolderMask" ) )
1339  {
1340  BIU tmp = biuParse( line + SZ( ".SolderMask" ) );
1341  aModule->SetLocalSolderMaskMargin( tmp );
1342  }
1343 
1344  else if( TESTLINE( ".LocalClearance" ) )
1345  {
1346  BIU tmp = biuParse( line + SZ( ".LocalClearance" ) );
1347  aModule->SetLocalClearance( tmp );
1348  }
1349 
1350  else if( TESTLINE( ".ZoneConnection" ) )
1351  {
1352  int tmp = intParse( line + SZ( ".ZoneConnection" ) );
1353  aModule->SetZoneConnection( (ZoneConnection)tmp );
1354  }
1355 
1356  else if( TESTLINE( ".ThermalWidth" ) )
1357  {
1358  BIU tmp = biuParse( line + SZ( ".ThermalWidth" ) );
1359  aModule->SetThermalWidth( tmp );
1360  }
1361 
1362  else if( TESTLINE( ".ThermalGap" ) )
1363  {
1364  BIU tmp = biuParse( line + SZ( ".ThermalGap" ) );
1365  aModule->SetThermalGap( tmp );
1366  }
1367 
1368  else if( TESTLINE( "$EndMODULE" ) )
1369  {
1370  aModule->CalculateBoundingBox();
1371 
1372  return; // preferred exit
1373  }
1374  }
1375 
1376  wxString msg = wxString::Format(
1377  _( "Missing '$EndMODULE' for MODULE \"%s\"" ),
1378  GetChars( aModule->GetFPID().GetLibItemName() ) );
1379 
1380  THROW_IO_ERROR( msg );
1381 }
1382 
1383 
1385 {
1386  unique_ptr<D_PAD> pad( new D_PAD( aModule ) );
1387  char* line;
1388  char* saveptr;
1389 
1390  while( ( line = READLINE( m_reader ) ) != NULL )
1391  {
1392  const char* data;
1393 
1394  if( TESTLINE( "Sh" ) ) // (Sh)ape and padname
1395  {
1396  // e.g. "Sh "A2" C 520 520 0 0 900"
1397  // or "Sh "1" R 157 1378 0 0 900"
1398 
1399  // mypadname is LATIN1/CRYLIC for BOARD_FORMAT_VERSION 1,
1400  // but for BOARD_FORMAT_VERSION 2, it is UTF8 from disk.
1401  // So we have to go through two code paths. Moving forward
1402  // padnames will be in UTF8 on disk, as are all KiCad strings on disk.
1403  char mypadname[50];
1404 
1405  data = line + SZ( "Sh" ) + 1; // +1 skips trailing whitespace
1406 
1407  data = data + ReadDelimitedText( mypadname, data, sizeof(mypadname) ) + 1; // +1 trailing whitespace
1408 
1409  // sscanf( PtLine, " %s %d %d %d %d %d", BufCar, &m_Size.x, &m_Size.y, &m_DeltaSize.x, &m_DeltaSize.y, &m_Orient );
1410  while( isSpace( *data ) )
1411  ++data;
1412 
1413  unsigned char padchar = (unsigned char) *data++;
1414  int padshape;
1415 
1416  BIU size_x = biuParse( data, &data );
1417  BIU size_y = biuParse( data, &data );
1418  BIU delta_x = biuParse( data, &data );
1419  BIU delta_y = biuParse( data, &data );
1420  double orient = degParse( data );
1421 
1422  switch( padchar )
1423  {
1424  case 'C': padshape = PAD_SHAPE_CIRCLE; break;
1425  case 'R': padshape = PAD_SHAPE_RECT; break;
1426  case 'O': padshape = PAD_SHAPE_OVAL; break;
1427  case 'T': padshape = PAD_SHAPE_TRAPEZOID; break;
1428  default:
1429  m_error.Printf( _( "Unknown padshape '%c=0x%02x' on line: %d of footprint: \"%s\"" ),
1430  padchar,
1431  padchar,
1432  m_reader->LineNumber(),
1433  GetChars( aModule->GetFPID().GetLibItemName() )
1434  );
1436  }
1437 
1438  // go through a wxString to establish a universal character set properly
1439  wxString padname;
1440 
1441  if( m_loading_format_version == 1 )
1442  {
1443  // add 8 bit bytes, file format 1 was KiCad font type byte,
1444  // simply promote those 8 bit bytes up into UNICODE. (subset of LATIN1)
1445  const unsigned char* cp = (unsigned char*) mypadname;
1446  while( *cp )
1447  {
1448  padname += *cp++; // unsigned, ls 8 bits only
1449  }
1450  }
1451  else
1452  {
1453  // version 2, which is UTF8.
1454  padname = FROM_UTF8( mypadname );
1455  }
1456  // chances are both were ASCII, but why take chances?
1457 
1458  pad->SetName( padname );
1459  pad->SetShape( PAD_SHAPE_T( padshape ) );
1460  pad->SetSize( wxSize( size_x, size_y ) );
1461  pad->SetDelta( wxSize( delta_x, delta_y ) );
1462  pad->SetOrientation( orient );
1463  }
1464 
1465  else if( TESTLINE( "Dr" ) ) // (Dr)ill
1466  {
1467  // e.g. "Dr 350 0 0" or "Dr 0 0 0 O 0 0"
1468  // sscanf( PtLine, "%d %d %d %s %d %d", &m_Drill.x, &m_Offset.x, &m_Offset.y, BufCar, &dx, &dy );
1469 
1470  BIU drill_x = biuParse( line + SZ( "Dr" ), &data );
1471  BIU drill_y = drill_x;
1472  BIU offs_x = biuParse( data, &data );
1473  BIU offs_y = biuParse( data, &data );
1474 
1476 
1477  data = strtok_r( (char*) data, delims, &saveptr );
1478  if( data ) // optional shape
1479  {
1480  if( data[0] == 'O' )
1481  {
1482  drShape = PAD_DRILL_SHAPE_OBLONG;
1483 
1484  data = strtok_r( NULL, delims, &saveptr );
1485  drill_x = biuParse( data );
1486 
1487  data = strtok_r( NULL, delims, &saveptr );
1488  drill_y = biuParse( data );
1489  }
1490  }
1491 
1492  pad->SetDrillShape( drShape );
1493  pad->SetOffset( wxPoint( offs_x, offs_y ) );
1494  pad->SetDrillSize( wxSize( drill_x, drill_y ) );
1495  }
1496 
1497  else if( TESTLINE( "At" ) ) // (At)tribute
1498  {
1499  // e.g. "At SMD N 00888000"
1500  // sscanf( PtLine, "%s %s %X", BufLine, BufCar, &m_layerMask );
1501 
1502  PAD_ATTR_T attribute;
1503 
1504  data = strtok_r( line + SZ( "At" ), delims, &saveptr );
1505 
1506  if( !strcmp( data, "SMD" ) )
1507  attribute = PAD_ATTRIB_SMD;
1508  else if( !strcmp( data, "CONN" ) )
1509  attribute = PAD_ATTRIB_CONN;
1510  else if( !strcmp( data, "HOLE" ) )
1511  attribute = PAD_ATTRIB_HOLE_NOT_PLATED;
1512  else
1513  attribute = PAD_ATTRIB_STANDARD;
1514 
1515  strtok_r( NULL, delims, &saveptr ); // skip BufCar
1516  data = strtok_r( NULL, delims, &saveptr );
1517 
1518  LEG_MASK layer_mask = hexParse( data );
1519 
1520  pad->SetLayerSet( leg_mask2new( m_cu_count, layer_mask ) );
1521  pad->SetAttribute( attribute );
1522  }
1523 
1524  else if( TESTLINE( "Ne" ) ) // (Ne)tname
1525  {
1526  // e.g. "Ne 461 "V5.0"
1527 
1528  char buf[1024]; // can be fairly long
1529  int netcode = intParse( line + SZ( "Ne" ), &data );
1530 
1531  // Store the new code mapping
1532  pad->SetNetCode( getNetCode( netcode ) );
1533 
1534  // read Netname
1535  ReadDelimitedText( buf, data, sizeof(buf) );
1536 #ifndef NDEBUG
1537  if( m_board )
1538  assert( m_board->FindNet( getNetCode( netcode ) )->GetNetname() ==
1539  FROM_UTF8( StrPurge( buf ) ) );
1540 #endif /* NDEBUG */
1541  }
1542 
1543  else if( TESTLINE( "Po" ) ) // (Po)sition
1544  {
1545  // e.g. "Po 500 -500"
1546  wxPoint pos;
1547 
1548  pos.x = biuParse( line + SZ( "Po" ), &data );
1549  pos.y = biuParse( data );
1550 
1551  pad->SetPos0( pos );
1552  // pad->SetPosition( pos ); set at function return
1553  }
1554 
1555  else if( TESTLINE( "Le" ) )
1556  {
1557  BIU tmp = biuParse( line + SZ( "Le" ) );
1558  pad->SetPadToDieLength( tmp );
1559  }
1560 
1561  else if( TESTLINE( ".SolderMask" ) )
1562  {
1563  BIU tmp = biuParse( line + SZ( ".SolderMask" ) );
1564  pad->SetLocalSolderMaskMargin( tmp );
1565  }
1566 
1567  else if( TESTLINE( ".SolderPasteRatio" ) )
1568  {
1569  double tmp = atof( line + SZ( ".SolderPasteRatio" ) );
1570  pad->SetLocalSolderPasteMarginRatio( tmp );
1571  }
1572 
1573  else if( TESTLINE( ".SolderPaste" ) )
1574  {
1575  BIU tmp = biuParse( line + SZ( ".SolderPaste" ) );
1576  pad->SetLocalSolderPasteMargin( tmp );
1577  }
1578 
1579  else if( TESTLINE( ".LocalClearance" ) )
1580  {
1581  BIU tmp = biuParse( line + SZ( ".LocalClearance" ) );
1582  pad->SetLocalClearance( tmp );
1583  }
1584 
1585  else if( TESTLINE( ".ZoneConnection" ) )
1586  {
1587  int tmp = intParse( line + SZ( ".ZoneConnection" ) );
1588  pad->SetZoneConnection( (ZoneConnection)tmp );
1589  }
1590 
1591  else if( TESTLINE( ".ThermalWidth" ) )
1592  {
1593  BIU tmp = biuParse( line + SZ( ".ThermalWidth" ) );
1594  pad->SetThermalWidth( tmp );
1595  }
1596 
1597  else if( TESTLINE( ".ThermalGap" ) )
1598  {
1599  BIU tmp = biuParse( line + SZ( ".ThermalGap" ) );
1600  pad->SetThermalGap( tmp );
1601  }
1602 
1603  else if( TESTLINE( "$EndPAD" ) )
1604  {
1605  // pad's "Position" is not relative to the module's,
1606  // whereas Pos0 is relative to the module's but is the unrotated coordinate.
1607 
1608  wxPoint padpos = pad->GetPos0();
1609 
1610  RotatePoint( &padpos, aModule->GetOrientation() );
1611 
1612  pad->SetPosition( padpos + aModule->GetPosition() );
1613 
1614  aModule->PadsList().PushBack( pad.release() );
1615  return; // preferred exit
1616  }
1617  }
1618 
1619  THROW_IO_ERROR( "Missing '$EndPAD'" );
1620 }
1621 
1622 
1624 {
1625  STROKE_T shape;
1626  char* line = m_reader->Line(); // obtain current (old) line
1627 
1628  switch( line[1] )
1629  {
1630  case 'S': shape = S_SEGMENT; break;
1631  case 'C': shape = S_CIRCLE; break;
1632  case 'A': shape = S_ARC; break;
1633  case 'P': shape = S_POLYGON; break;
1634  default:
1635  m_error.Printf( _( "Unknown EDGE_MODULE type:'%c=0x%02x' on line:%d of footprint:\"%s\"" ),
1636  (unsigned char) line[1],
1637  (unsigned char) line[1],
1638  m_reader->LineNumber(),
1639  GetChars( aModule->GetFPID().GetLibItemName() )
1640  );
1642  }
1643 
1644  unique_ptr<EDGE_MODULE> dwg( new EDGE_MODULE( aModule, shape ) ); // a drawing
1645 
1646  const char* data;
1647 
1648  // common to all cases, and we have to check their values uniformly at end
1649  BIU width = 1;
1651 
1652  switch( shape )
1653  {
1654  case S_ARC:
1655  {
1656  // sscanf( Line + 3, "%d %d %d %d %d %d %d", &m_Start0.x, &m_Start0.y, &m_End0.x, &m_End0.y, &m_Angle, &m_Width, &m_Layer );
1657  BIU start0_x = biuParse( line + SZ( "DA" ), &data );
1658  BIU start0_y = biuParse( data, &data );
1659  BIU end0_x = biuParse( data, &data );
1660  BIU end0_y = biuParse( data, &data );
1661  double angle = degParse( data, &data );
1662 
1663  width = biuParse( data, &data );
1664  layer = layerParse( data );
1665 
1666  dwg->SetAngle( angle );
1667  dwg->m_Start0 = wxPoint( start0_x, start0_y );
1668  dwg->m_End0 = wxPoint( end0_x, end0_y );
1669  }
1670  break;
1671 
1672  case S_SEGMENT:
1673  case S_CIRCLE:
1674  {
1675  // e.g. "DS -7874 -10630 7874 -10630 50 20\r\n"
1676  // sscanf( Line + 3, "%d %d %d %d %d %d", &m_Start0.x, &m_Start0.y, &m_End0.x, &m_End0.y, &m_Width, &m_Layer );
1677 
1678  BIU start0_x = biuParse( line + SZ( "DS" ), &data );
1679  BIU start0_y = biuParse( data, &data );
1680  BIU end0_x = biuParse( data, &data );
1681  BIU end0_y = biuParse( data, &data );
1682 
1683  width = biuParse( data, &data );
1684  layer = layerParse( data );
1685 
1686  dwg->m_Start0 = wxPoint( start0_x, start0_y );
1687  dwg->m_End0 = wxPoint( end0_x, end0_y );
1688  }
1689  break;
1690 
1691  case S_POLYGON:
1692  {
1693  // e.g. "DP %d %d %d %d %d %d %d\n"
1694  // sscanf( Line + 3, "%d %d %d %d %d %d %d", &m_Start0.x, &m_Start0.y, &m_End0.x, &m_End0.y, &pointCount, &m_Width, &m_Layer );
1695 
1696  BIU start0_x = biuParse( line + SZ( "DP" ), &data );
1697  BIU start0_y = biuParse( data, &data );
1698  BIU end0_x = biuParse( data, &data );
1699  BIU end0_y = biuParse( data, &data );
1700  int ptCount = intParse( data, &data );
1701 
1702  width = biuParse( data, &data );
1703  layer = layerParse( data );
1704 
1705  dwg->m_Start0 = wxPoint( start0_x, start0_y );
1706  dwg->m_End0 = wxPoint( end0_x, end0_y );
1707 
1708  std::vector<wxPoint> pts;
1709  pts.reserve( ptCount );
1710 
1711  for( int ii = 0; ii<ptCount; ++ii )
1712  {
1713  if( ( line = READLINE( m_reader ) ) == NULL )
1714  {
1715  THROW_IO_ERROR( "S_POLGON point count mismatch." );
1716  }
1717 
1718  // e.g. "Dl 23 44\n"
1719 
1720  if( !TESTLINE( "Dl" ) )
1721  {
1722  THROW_IO_ERROR( "Missing Dl point def" );
1723  }
1724 
1725  BIU x = biuParse( line + SZ( "Dl" ), &data );
1726  BIU y = biuParse( data );
1727 
1728  pts.push_back( wxPoint( x, y ) );
1729  }
1730 
1731  dwg->SetPolyPoints( pts );
1732  }
1733  break;
1734 
1735  default:
1736  // first switch code above prevents us from getting here.
1737  break;
1738  }
1739 
1740  // Check for a reasonable width:
1741 
1742  /* @todo no MAX_WIDTH in out of reach header.
1743  if( width <= 1 )
1744  width = 1;
1745  else if( width > MAX_WIDTH )
1746  width = MAX_WIDTH;
1747  */
1748 
1749  // Check for a reasonable layer:
1750  // m_Layer must be >= FIRST_NON_COPPER_LAYER, but because microwave footprints
1751  // can use the copper layers m_Layer < FIRST_NON_COPPER_LAYER is allowed.
1752  // @todo: changes use of EDGE_MODULE these footprints and allows only
1753  // m_Layer >= FIRST_NON_COPPER_LAYER
1754  if( layer < FIRST_LAYER || layer > LAST_NON_COPPER_LAYER )
1755  layer = SILKSCREEN_N_FRONT;
1756 
1757  dwg->SetWidth( width );
1758  dwg->SetLayer( leg_layer2new( m_cu_count, layer ) );
1759 
1760  EDGE_MODULE* em = dwg.release();
1761 
1762  aModule->GraphicalItemsList().PushBack( em );
1763 
1764  // this had been done at the MODULE level before, presumably because the
1765  // EDGE_MODULE needs to be already added to a module before this function will work.
1766  em->SetDrawCoord();
1767 }
1768 
1769 
1771 {
1772  const char* data;
1773  const char* txt_end;
1774  const char* line = m_reader->Line(); // current (old) line
1775  char* saveptr;
1776 
1777  // sscanf( line + 1, "%d %d %d %d %d %d %d %s %s %d %s",
1778  // &type, &m_Pos0.x, &m_Pos0.y, &m_Size.y, &m_Size.x,
1779  // &m_Orient, &m_Thickness, BufCar1, BufCar2, &layer, BufCar3 ) >= 10 )
1780 
1781  // e.g. "T1 6940 -16220 350 300 900 60 M I 20 N "CFCARD"\r\n"
1782  // or T1 0 500 600 400 900 80 M V 20 N"74LS245"
1783  // ouch, the last example has no space between N and "74LS245" !
1784  // that is an older version.
1785 
1786  int type = intParse( line+1, &data );
1787  BIU pos0_x = biuParse( data, &data );
1788  BIU pos0_y = biuParse( data, &data );
1789  BIU size0_y = biuParse( data, &data );
1790  BIU size0_x = biuParse( data, &data );
1791  double orient = degParse( data, &data );
1792  BIU thickn = biuParse( data, &data );
1793 
1794  // read the quoted text before the first call to strtok() which introduces
1795  // NULs into the string and chops it into mutliple C strings, something
1796  // ReadDelimitedText() cannot traverse.
1797 
1798  // convert the "quoted, escaped, UTF8, text" to a wxString, find it by skipping
1799  // as far forward as needed until the first double quote.
1800  txt_end = data + ReadDelimitedText( &m_field, data );
1801 
1802  aText->SetText( m_field );
1803 
1804  // after switching to strtok, there's no easy coming back because of the
1805  // embedded nul(s?) placed to the right of the current field.
1806  // (that's the reason why strtok was deprecated...)
1807  char* mirror = strtok_r( (char*) data, delims, &saveptr );
1808  char* hide = strtok_r( NULL, delims, &saveptr );
1809  char* tmp = strtok_r( NULL, delims, &saveptr );
1810 
1811  LAYER_NUM layer_num = tmp ? layerParse( tmp ) : SILKSCREEN_N_FRONT;
1812 
1813  char* italic = strtok_r( NULL, delims, &saveptr );
1814 
1815  char* hjust = strtok_r( (char*) txt_end, delims, &saveptr );
1816  char* vjust = strtok_r( NULL, delims, &saveptr );
1817 
1819  && type != TEXTE_MODULE::TEXT_is_VALUE )
1821 
1822  aText->SetType( static_cast<TEXTE_MODULE::TEXT_TYPE>( type ) );
1823 
1824  aText->SetPos0( wxPoint( pos0_x, pos0_y ) );
1825  aText->SetTextSize( wxSize( size0_x, size0_y ) );
1826 
1827  orient -= ( static_cast<MODULE*>( aText->GetParent() ) )->GetOrientation();
1828 
1829  aText->SetTextAngle( orient );
1830 
1831  // @todo put in accessors?
1832  // Set a reasonable width:
1833  if( thickn < 1 )
1834  thickn = 1;
1835 
1836  /* this is better left to the dialogs UIs
1837  aText->SetThickness( Clamp_Text_PenSize( thickn, aText->GetSize() ) );
1838  */
1839 
1840  aText->SetThickness( thickn );
1841 
1842  aText->SetMirrored( mirror && *mirror == 'M' );
1843 
1844  aText->SetVisible( !(hide && *hide == 'I') );
1845 
1846  aText->SetItalic( italic && *italic == 'I' );
1847 
1848  if( hjust )
1849  aText->SetHorizJustify( horizJustify( hjust ) );
1850 
1851  if( vjust )
1852  aText->SetVertJustify( vertJustify( vjust ) );
1853 
1854  if( layer_num < FIRST_LAYER )
1855  layer_num = FIRST_LAYER;
1856  else if( layer_num > LAST_NON_COPPER_LAYER )
1857  layer_num = LAST_NON_COPPER_LAYER;
1858  else if( layer_num == LAYER_N_BACK )
1859  layer_num = SILKSCREEN_N_BACK;
1860  else if( layer_num == LAYER_N_FRONT )
1861  layer_num = SILKSCREEN_N_FRONT;
1862 
1863  aText->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
1864 
1865  // Calculate the actual position.
1866  aText->SetDrawCoord();
1867 }
1868 
1869 
1871 {
1872  MODULE_3D_SETTINGS t3D;
1873 
1874  char* line;
1875  while( ( line = READLINE( m_reader ) ) != NULL )
1876  {
1877  if( TESTLINE( "Na" ) ) // Shape File Name
1878  {
1879  char buf[512];
1880  ReadDelimitedText( buf, line + SZ( "Na" ), sizeof(buf) );
1881  t3D.m_Filename = buf;
1882  }
1883 
1884  else if( TESTLINE( "Sc" ) ) // Scale
1885  {
1886  sscanf( line + SZ( "Sc" ), "%lf %lf %lf\n",
1887  &t3D.m_Scale.x,
1888  &t3D.m_Scale.y,
1889  &t3D.m_Scale.z );
1890  }
1891 
1892  else if( TESTLINE( "Of" ) ) // Offset
1893  {
1894  sscanf( line + SZ( "Of" ), "%lf %lf %lf\n",
1895  &t3D.m_Offset.x,
1896  &t3D.m_Offset.y,
1897  &t3D.m_Offset.z );
1898  }
1899 
1900  else if( TESTLINE( "Ro" ) ) // Rotation
1901  {
1902  sscanf( line + SZ( "Ro" ), "%lf %lf %lf\n",
1903  &t3D.m_Rotation.x,
1904  &t3D.m_Rotation.y,
1905  &t3D.m_Rotation.z );
1906  }
1907 
1908  else if( TESTLINE( "$EndSHAPE3D" ) )
1909  {
1910  aModule->Models().push_back( t3D );
1911  return; // preferred exit
1912  }
1913  }
1914 
1915  THROW_IO_ERROR( "Missing '$EndSHAPE3D'" );
1916 }
1917 
1918 
1920 {
1921  /* example:
1922  $DRAWSEGMENT
1923  Po 0 57500 -1000 57500 0 150
1924  De 24 0 900 0 0
1925  $EndDRAWSEGMENT
1926  */
1927 
1928  unique_ptr<DRAWSEGMENT> dseg( new DRAWSEGMENT( m_board ) );
1929 
1930  char* line;
1931  char* saveptr;
1932 
1933  while( ( line = READLINE( m_reader ) ) != NULL )
1934  {
1935  const char* data;
1936 
1937  if( TESTLINE( "Po" ) )
1938  {
1939  // sscanf( line + 2, " %d %d %d %d %d %d", &m_Shape, &m_Start.x, &m_Start.y, &m_End.x, &m_End.y, &m_Width );
1940  int shape = intParse( line + SZ( "Po" ), &data );
1941  BIU start_x = biuParse( data, &data );
1942  BIU start_y = biuParse( data, &data );
1943  BIU end_x = biuParse( data, &data );
1944  BIU end_y = biuParse( data, &data );
1945  BIU width = biuParse( data );
1946 
1947  if( width < 0 )
1948  width = 0;
1949 
1950  dseg->SetShape( STROKE_T( shape ) );
1951  dseg->SetWidth( width );
1952  dseg->SetStart( wxPoint( start_x, start_y ) );
1953  dseg->SetEnd( wxPoint( end_x, end_y ) );
1954  }
1955 
1956  else if( TESTLINE( "De" ) )
1957  {
1958  BIU x = 0;
1959  BIU y;
1960 
1961  data = strtok_r( line + SZ( "De" ), delims, &saveptr );
1962  for( int i = 0; data; ++i, data = strtok_r( NULL, delims, &saveptr ) )
1963  {
1964  switch( i )
1965  {
1966  case 0:
1967  LAYER_NUM layer;
1968  layer = layerParse( data );
1969 
1970  if( layer < FIRST_NON_COPPER_LAYER )
1971  layer = FIRST_NON_COPPER_LAYER;
1972 
1973  else if( layer > LAST_NON_COPPER_LAYER )
1974  layer = LAST_NON_COPPER_LAYER;
1975 
1976  dseg->SetLayer( leg_layer2new( m_cu_count, layer ) );
1977  break;
1978  case 1:
1979  int mtype;
1980  mtype = intParse( data );
1981  dseg->SetType( mtype ); // m_Type
1982  break;
1983  case 2:
1984  double angle;
1985  angle = degParse( data );
1986  dseg->SetAngle( angle ); // m_Angle
1987  break;
1988  case 3:
1989  timestamp_t timestamp;
1990  timestamp = hexParse( data );
1991  dseg->SetTimeStamp( timestamp );
1992  break;
1993  case 4:
1994  STATUS_FLAGS state;
1995  state = static_cast<STATUS_FLAGS>( hexParse( data ) );
1996  dseg->SetState( state, true );
1997  break;
1998 
1999  // Bezier Control Points
2000  case 5:
2001  x = biuParse( data );
2002  break;
2003  case 6:
2004  y = biuParse( data );
2005  dseg->SetBezControl1( wxPoint( x, y ) );
2006  break;
2007 
2008  case 7:
2009  x = biuParse( data );
2010  break;
2011  case 8:
2012  y = biuParse( data );
2013  dseg->SetBezControl2( wxPoint( x, y ) );
2014  break;
2015 
2016  default:
2017  break;
2018  }
2019  }
2020  }
2021 
2022  else if( TESTLINE( "$EndDRAWSEGMENT" ) )
2023  {
2024  m_board->Add( dseg.release(), ADD_APPEND );
2025  return; // preferred exit
2026  }
2027  }
2028 
2029  THROW_IO_ERROR( "Missing '$EndDRAWSEGMENT'" );
2030 }
2031 
2033 {
2034  /* a net description is something like
2035  * $EQUIPOT
2036  * Na 5 "/BIT1"
2037  * St ~
2038  * $EndEQUIPOT
2039  */
2040 
2041  char buf[1024];
2042 
2043  NETINFO_ITEM* net = NULL;
2044  char* line;
2045  int netCode = 0;
2046 
2047  while( ( line = READLINE( m_reader ) ) != NULL )
2048  {
2049  const char* data;
2050 
2051  if( TESTLINE( "Na" ) )
2052  {
2053  // e.g. "Na 58 "/cpu.sch/PAD7"\r\n"
2054 
2055  netCode = intParse( line + SZ( "Na" ), &data );
2056 
2057  ReadDelimitedText( buf, data, sizeof(buf) );
2058 
2059  if( net == NULL )
2060  net = new NETINFO_ITEM( m_board, FROM_UTF8( buf ), netCode );
2061  else
2062  {
2063  THROW_IO_ERROR( "Two net definitions in '$EQUIPOT' block" );
2064  }
2065  }
2066 
2067  else if( TESTLINE( "$EndEQUIPOT" ) )
2068  {
2069  // net 0 should be already in list, so store this net
2070  // if it is not the net 0, or if the net 0 does not exists.
2071  if( net && ( net->GetNet() > 0 || m_board->FindNet( 0 ) == NULL ) )
2072  {
2073  m_board->Add( net );
2074 
2075  // Be sure we have room to store the net in m_netCodes
2076  if( (int)m_netCodes.size() <= netCode )
2077  m_netCodes.resize( netCode+1 );
2078 
2079  m_netCodes[netCode] = net->GetNet();
2080  net = NULL;
2081  }
2082  else
2083  {
2084  delete net;
2085  net = NULL; // Avoid double deletion.
2086  }
2087 
2088  return; // preferred exit
2089  }
2090  }
2091 
2092  // If we are here, there is an error.
2093  delete net;
2094  THROW_IO_ERROR( "Missing '$EndEQUIPOT'" );
2095 }
2096 
2097 
2099 {
2100  /* examples:
2101  For a single line text:
2102  ----------------------
2103  $TEXTPCB
2104  Te "Text example"
2105  Po 66750 53450 600 800 150 0
2106  De 24 1 0 Italic
2107  $EndTEXTPCB
2108 
2109  For a multi line text:
2110  ---------------------
2111  $TEXTPCB
2112  Te "Text example"
2113  Nl "Line 2"
2114  Po 66750 53450 600 800 150 0
2115  De 24 1 0 Italic
2116  $EndTEXTPCB
2117  Nl "line nn" is a line added to the current text
2118  */
2119 
2120  char text[1024];
2121 
2122  // maybe someday a constructor that takes all this data in one call?
2123  TEXTE_PCB* pcbtxt = new TEXTE_PCB( m_board );
2124  m_board->Add( pcbtxt, ADD_APPEND );
2125 
2126  char* line;
2127  char* saveptr;
2128 
2129  while( ( line = READLINE( m_reader ) ) != NULL )
2130  {
2131  const char* data;
2132 
2133  if( TESTLINE( "Te" ) ) // Text line (or first line for multi line texts)
2134  {
2135  ReadDelimitedText( text, line + SZ( "Te" ), sizeof(text) );
2136  pcbtxt->SetText( FROM_UTF8( text ) );
2137  }
2138 
2139  else if( TESTLINE( "nl" ) ) // next line of the current text
2140  {
2141  ReadDelimitedText( text, line + SZ( "nl" ), sizeof(text) );
2142  pcbtxt->SetText( pcbtxt->GetText() + wxChar( '\n' ) + FROM_UTF8( text ) );
2143  }
2144 
2145  else if( TESTLINE( "Po" ) )
2146  {
2147  // sscanf( line + 2, " %d %d %d %d %d %d", &m_Pos.x, &m_Pos.y, &m_Size.x, &m_Size.y, &m_Thickness, &m_Orient );
2148  wxSize size;
2149 
2150  BIU pos_x = biuParse( line + SZ( "Po" ), &data );
2151  BIU pos_y = biuParse( data, &data );
2152  size.x = biuParse( data, &data );
2153  size.y = biuParse( data, &data );
2154  BIU thickn = biuParse( data, &data );
2155  double angle = degParse( data );
2156 
2157  // Ensure the text has minimal size to see this text on screen:
2158 
2159  /* @todo wait until we are firmly in the nanometer world
2160  if( sz.x < 5 )
2161  sz.x = 5;
2162 
2163  if( sz.y < 5 )
2164  sz.y = 5;
2165  */
2166 
2167  pcbtxt->SetTextSize( size );
2168 
2169  /* @todo move into an accessor
2170  // Set a reasonable width:
2171  if( thickn < 1 )
2172  thickn = 1;
2173 
2174  thickn = Clamp_Text_PenSize( thickn, size );
2175  */
2176 
2177  pcbtxt->SetThickness( thickn );
2178  pcbtxt->SetTextAngle( angle );
2179 
2180  pcbtxt->SetTextPos( wxPoint( pos_x, pos_y ) );
2181  }
2182 
2183  else if( TESTLINE( "De" ) )
2184  {
2185  // e.g. "De 21 1 0 Normal C\r\n"
2186  // sscanf( line + 2, " %d %d %lX %s %c\n", &m_Layer, &normal_display, &m_TimeStamp, style, &hJustify );
2187 
2188  LAYER_NUM layer_num = layerParse( line + SZ( "De" ), &data );
2189  int notMirrored = intParse( data, &data );
2190  timestamp_t timestamp = hexParse( data, &data );
2191  char* style = strtok_r( (char*) data, delims, &saveptr );
2192  char* hJustify = strtok_r( NULL, delims, &saveptr );
2193  char* vJustify = strtok_r( NULL, delims, &saveptr );
2194 
2195  pcbtxt->SetMirrored( !notMirrored );
2196  pcbtxt->SetTimeStamp( timestamp );
2197  pcbtxt->SetItalic( !strcmp( style, "Italic" ) );
2198 
2199  if( hJustify )
2200  pcbtxt->SetHorizJustify( horizJustify( hJustify ) );
2201  else
2202  {
2203  // boom, somebody changed a constructor, I was relying on this:
2204  wxASSERT( pcbtxt->GetHorizJustify() == GR_TEXT_HJUSTIFY_CENTER );
2205  }
2206 
2207  if( vJustify )
2208  pcbtxt->SetVertJustify( vertJustify( vJustify ) );
2209 
2210  if( layer_num < FIRST_COPPER_LAYER )
2211  layer_num = FIRST_COPPER_LAYER;
2212  else if( layer_num > LAST_NON_COPPER_LAYER )
2213  layer_num = LAST_NON_COPPER_LAYER;
2214 
2215  if( layer_num >= FIRST_NON_COPPER_LAYER ||
2216  is_leg_copperlayer_valid( m_cu_count, layer_num ) )
2217  pcbtxt->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2218  else // not perfect, but putting this text on front layer is a workaround
2219  pcbtxt->SetLayer( F_Cu );
2220  }
2221 
2222  else if( TESTLINE( "$EndTEXTPCB" ) )
2223  {
2224  return; // preferred exit
2225  }
2226  }
2227 
2228  THROW_IO_ERROR( "Missing '$EndTEXTPCB'" );
2229 }
2230 
2231 
2232 void LEGACY_PLUGIN::loadTrackList( int aStructType )
2233 {
2234  char* line;
2235  char* saveptr;
2236 
2237  while( ( line = READLINE( m_reader ) ) != NULL )
2238  {
2239  // read two lines per loop iteration, each loop is one TRACK or VIA
2240  // example first line:
2241  // e.g. "Po 0 23994 28800 24400 28800 150 -1" for a track
2242  // e.g. "Po 3 21086 17586 21086 17586 180 -1" for a via (uses sames start and end)
2243 
2244  const char* data;
2245 
2246  if( line[0] == '$' ) // $EndTRACK
2247  return; // preferred exit
2248 
2249  // int arg_count = sscanf( line + 2, " %d %d %d %d %d %d %d", &shape, &tempStartX, &tempStartY, &tempEndX, &tempEndY, &width, &drill );
2250 
2251  assert( TESTLINE( "Po" ) );
2252 
2253  VIATYPE_T viatype = static_cast<VIATYPE_T>( intParse( line + SZ( "Po" ), &data ));
2254  BIU start_x = biuParse( data, &data );
2255  BIU start_y = biuParse( data, &data );
2256  BIU end_x = biuParse( data, &data );
2257  BIU end_y = biuParse( data, &data );
2258  BIU width = biuParse( data, &data );
2259 
2260  // optional 7th drill parameter (must be optional in an old format?)
2261  data = strtok_r( (char*) data, delims, &saveptr );
2262 
2263  BIU drill = data ? biuParse( data ) : -1; // SetDefault() if < 0
2264 
2265  // Read the 2nd line to determine the exact type, one of:
2266  // PCB_TRACE_T, PCB_VIA_T, or PCB_SEGZONE_T. The type field in 2nd line
2267  // differentiates between PCB_TRACE_T and PCB_VIA_T. With virtual
2268  // functions in use, it is critical to instantiate the PCB_VIA_T
2269  // exactly.
2270  READLINE( m_reader );
2271 
2272  line = m_reader->Line();
2273 
2274  // example second line:
2275  // "De 0 0 463 0 800000\r\n"
2276 
2277 #if 1
2278  assert( TESTLINE( "De" ) );
2279 #else
2280  if( !TESTLINE( "De" ) )
2281  {
2282  // mandatory 2nd line is missing
2283  THROW_IO_ERROR( "Missing 2nd line of a TRACK def" );
2284  }
2285 #endif
2286 
2287  int makeType;
2288  unsigned long timeStamp;
2289  LAYER_NUM layer_num;
2290  int type, net_code, flags_int;
2291 
2292  // parse the 2nd line to determine the type of object
2293  // e.g. "De 15 1 7 0 0" for a via
2294  sscanf( line + SZ( "De" ), " %d %d %d %lX %X", &layer_num, &type, &net_code,
2295  &timeStamp, &flags_int );
2296 
2297  STATUS_FLAGS flags;
2298 
2299  flags = static_cast<STATUS_FLAGS>( flags_int );
2300 
2301  if( aStructType==PCB_TRACE_T && type==1 )
2302  makeType = PCB_VIA_T;
2303  else
2304  makeType = aStructType;
2305 
2306  TRACK* newTrack;
2307 
2308  switch( makeType )
2309  {
2310  default:
2311  case PCB_TRACE_T:
2312  newTrack = new TRACK( m_board );
2313  break;
2314 
2315  case PCB_VIA_T:
2316  newTrack = new VIA( m_board );
2317  break;
2318 
2319  case PCB_SEGZONE_T: // this is now deprecated, but exist in old boards
2320  newTrack = new SEGZONE( m_board );
2321  break;
2322  }
2323 
2324  newTrack->SetTimeStamp( (timestamp_t)timeStamp );
2325  newTrack->SetPosition( wxPoint( start_x, start_y ) );
2326  newTrack->SetEnd( wxPoint( end_x, end_y ) );
2327 
2328  newTrack->SetWidth( width );
2329 
2330  if( makeType == PCB_VIA_T ) // Ensure layers are OK when possible:
2331  {
2332  VIA *via = static_cast<VIA*>( newTrack );
2333  via->SetViaType( viatype );
2334 
2335  if( drill < 0 )
2336  via->SetDrillDefault();
2337  else
2338  via->SetDrill( drill );
2339 
2340  if( via->GetViaType() == VIA_THROUGH )
2341  via->SetLayerPair( F_Cu, B_Cu );
2342  else
2343  {
2344  PCB_LAYER_ID back = leg_layer2new( m_cu_count, (layer_num >> 4) & 0xf );
2345  PCB_LAYER_ID front = leg_layer2new( m_cu_count, layer_num & 0xf );
2346 
2347  if( is_leg_copperlayer_valid( m_cu_count, back ) &&
2349  via->SetLayerPair( front, back );
2350  else
2351  {
2352  delete via;
2353  newTrack = NULL;
2354  }
2355  }
2356  }
2357  else
2358  {
2359  // A few legacy boards can have tracks on non existent layers, because
2360  // reducing the number of layers does not remove tracks on removed layers
2361  // If happens, skip them
2362  if( is_leg_copperlayer_valid( m_cu_count, layer_num ) )
2363  newTrack->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2364  else
2365  {
2366  delete newTrack;
2367  newTrack = NULL;
2368  }
2369  }
2370 
2371  if( newTrack )
2372  {
2373  newTrack->SetNetCode( getNetCode( net_code ) );
2374  newTrack->SetState( flags, true );
2375 
2376  m_board->Add( newTrack );
2377  }
2378  }
2379 
2380  THROW_IO_ERROR( "Missing '$EndTRACK'" );
2381 }
2382 
2383 
2385 {
2386  char buf[1024];
2387  wxString netname;
2388  char* line;
2389 
2390  // create an empty NETCLASS without a name, but do not add it to the BOARD
2391  // yet since that would bypass duplicate netclass name checking within the BOARD.
2392  // store it temporarily in an unique_ptr until successfully inserted into the BOARD
2393  // just before returning.
2394  NETCLASSPTR nc = std::make_shared<NETCLASS>( wxEmptyString );
2395 
2396  while( ( line = READLINE( m_reader ) ) != NULL )
2397  {
2398  if( TESTLINE( "AddNet" ) ) // most frequent type of line
2399  {
2400  // e.g. "AddNet "V3.3D"\n"
2401  ReadDelimitedText( buf, line + SZ( "AddNet" ), sizeof(buf) );
2402  netname = FROM_UTF8( buf );
2403  nc->Add( netname );
2404  }
2405 
2406  else if( TESTLINE( "Clearance" ) )
2407  {
2408  BIU tmp = biuParse( line + SZ( "Clearance" ) );
2409  nc->SetClearance( tmp );
2410  }
2411 
2412  else if( TESTLINE( "TrackWidth" ) )
2413  {
2414  BIU tmp = biuParse( line + SZ( "TrackWidth" ) );
2415  nc->SetTrackWidth( tmp );
2416  }
2417 
2418  else if( TESTLINE( "ViaDia" ) )
2419  {
2420  BIU tmp = biuParse( line + SZ( "ViaDia" ) );
2421  nc->SetViaDiameter( tmp );
2422  }
2423 
2424  else if( TESTLINE( "ViaDrill" ) )
2425  {
2426  BIU tmp = biuParse( line + SZ( "ViaDrill" ) );
2427  nc->SetViaDrill( tmp );
2428  }
2429 
2430  else if( TESTLINE( "uViaDia" ) )
2431  {
2432  BIU tmp = biuParse( line + SZ( "uViaDia" ) );
2433  nc->SetuViaDiameter( tmp );
2434  }
2435 
2436  else if( TESTLINE( "uViaDrill" ) )
2437  {
2438  BIU tmp = biuParse( line + SZ( "uViaDrill" ) );
2439  nc->SetuViaDrill( tmp );
2440  }
2441 
2442  else if( TESTLINE( "Name" ) )
2443  {
2444  ReadDelimitedText( buf, line + SZ( "Name" ), sizeof(buf) );
2445  nc->SetName( FROM_UTF8( buf ) );
2446  }
2447 
2448  else if( TESTLINE( "Desc" ) )
2449  {
2450  ReadDelimitedText( buf, line + SZ( "Desc" ), sizeof(buf) );
2451  nc->SetDescription( FROM_UTF8( buf ) );
2452  }
2453 
2454  else if( TESTLINE( "$EndNCLASS" ) )
2455  {
2456  if( !m_board->GetDesignSettings().m_NetClasses.Add( nc ) )
2457  {
2458  // Must have been a name conflict, this is a bad board file.
2459  // User may have done a hand edit to the file.
2460 
2461  // unique_ptr will delete nc on this code path
2462 
2463  m_error.Printf( _( "duplicate NETCLASS name \"%s\"" ), nc->GetName().GetData() );
2465  }
2466 
2467  return; // preferred exit
2468  }
2469  }
2470 
2471  THROW_IO_ERROR( "Missing '$EndNCLASS'" );
2472 }
2473 
2474 
2476 {
2477  unique_ptr<ZONE_CONTAINER> zc( new ZONE_CONTAINER( m_board ) );
2478 
2480  bool endContour = false;
2481  int holeIndex = -1; // -1 is the main outline; holeIndex >= 0 = hole index
2482  char buf[1024];
2483  char* line;
2484  char* saveptr;
2485 
2486  while( ( line = READLINE( m_reader ) ) != NULL )
2487  {
2488  const char* data;
2489 
2490  if( TESTLINE( "ZCorner" ) ) // new corner of the zone outlines found
2491  {
2492  // e.g. "ZCorner 25650 49500 0"
2493  BIU x = biuParse( line + SZ( "ZCorner" ), &data );
2494  BIU y = biuParse( data, &data );
2495 
2496  if( endContour )
2497  {
2498  // the previous corner was the last corner of a contour.
2499  // so this corner is the first of a new hole
2500  endContour = false;
2501  zc->NewHole();
2502  holeIndex++;
2503  }
2504 
2505  zc->AppendCorner( wxPoint( x, y ), holeIndex );
2506 
2507  // Is this corner the end of current contour?
2508  // the next corner (if any) will be stored in a new contour (a hole)
2509  // intParse( data )returns 0 = usual corner, 1 = last corner of the current contour:
2510  endContour = intParse( data );
2511  }
2512 
2513  else if( TESTLINE( "ZInfo" ) ) // general info found
2514  {
2515  // e.g. 'ZInfo 479194B1 310 "COMMON"'
2516  timestamp_t timestamp = hexParse( line + SZ( "ZInfo" ), &data );
2517  int netcode = intParse( data, &data );
2518 
2519  if( ReadDelimitedText( buf, data, sizeof(buf) ) > (int) sizeof(buf) )
2520  {
2521  THROW_IO_ERROR( "ZInfo netname too long" );
2522  }
2523 
2524  zc->SetTimeStamp( timestamp );
2525  // Init the net code only, not the netname, to be sure
2526  // the zone net name is the name read in file.
2527  // (When mismatch, the user will be prompted in DRC, to fix the actual name)
2528  zc->BOARD_CONNECTED_ITEM::SetNetCode( getNetCode( netcode ) );
2529  }
2530 
2531  else if( TESTLINE( "ZLayer" ) ) // layer found
2532  {
2533  LAYER_NUM layer_num = layerParse( line + SZ( "ZLayer" ) );
2534  zc->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2535  }
2536 
2537  else if( TESTLINE( "ZAux" ) ) // aux info found
2538  {
2539  // e.g. "ZAux 7 E"
2540  int ignore = intParse( line + SZ( "ZAux" ), &data );
2541  char* hopt = strtok_r( (char*) data, delims, &saveptr );
2542 
2543  if( !hopt )
2544  {
2545  m_error.Printf( _( "Bad ZAux for CZONE_CONTAINER \"%s\"" ), zc->GetNetname().GetData() );
2547  }
2548 
2549  switch( *hopt ) // upper case required
2550  {
2551  case 'N': outline_hatch = ZONE_CONTAINER::NO_HATCH; break;
2552  case 'E': outline_hatch = ZONE_CONTAINER::DIAGONAL_EDGE; break;
2553  case 'F': outline_hatch = ZONE_CONTAINER::DIAGONAL_FULL; break;
2554 
2555  default:
2556  m_error.Printf( _( "Bad ZAux for CZONE_CONTAINER \"%s\"" ), zc->GetNetname().GetData() );
2558  }
2559 
2560  (void) ignore;
2561 
2562  // Set hatch mode later, after reading corner outline data
2563  }
2564 
2565  else if( TESTLINE( "ZSmoothing" ) )
2566  {
2567  // e.g. "ZSmoothing 0 0"
2568  int smoothing = intParse( line + SZ( "ZSmoothing" ), &data );
2569  BIU cornerRadius = biuParse( data );
2570 
2571  if( smoothing >= ZONE_SETTINGS::SMOOTHING_LAST || smoothing < 0 )
2572  {
2573  m_error.Printf( _( "Bad ZSmoothing for CZONE_CONTAINER \"%s\"" ), zc->GetNetname().GetData() );
2575  }
2576 
2577  zc->SetCornerSmoothingType( smoothing );
2578  zc->SetCornerRadius( cornerRadius );
2579  }
2580 
2581  else if( TESTLINE( "ZKeepout" ) )
2582  {
2583  zc->SetIsKeepout( true );
2584  // e.g. "ZKeepout tracks N vias N pads Y"
2585  data = strtok_r( line + SZ( "ZKeepout" ), delims, &saveptr );
2586 
2587  while( data )
2588  {
2589  if( !strcmp( data, "tracks" ) )
2590  {
2591  data = strtok_r( NULL, delims, &saveptr );
2592  zc->SetDoNotAllowTracks( data && *data == 'N' );
2593  }
2594  else if( !strcmp( data, "vias" ) )
2595  {
2596  data = strtok_r( NULL, delims, &saveptr );
2597  zc->SetDoNotAllowVias( data && *data == 'N' );
2598  }
2599  else if( !strcmp( data, "copperpour" ) )
2600  {
2601  data = strtok_r( NULL, delims, &saveptr );
2602  zc->SetDoNotAllowCopperPour( data && *data == 'N' );
2603  }
2604 
2605  data = strtok_r( NULL, delims, &saveptr );
2606  }
2607  }
2608 
2609  else if( TESTLINE( "ZOptions" ) )
2610  {
2611  // e.g. "ZOptions 0 32 F 200 200"
2612  int fillmode = intParse( line + SZ( "ZOptions" ), &data );
2613  int arcsegcount = intParse( data, &data );
2614  char fillstate = data[1]; // here e.g. " F"
2615  BIU thermalReliefGap = biuParse( data += 2 , &data ); // +=2 for " F"
2616  BIU thermalReliefCopperBridge = biuParse( data );
2617 
2618  zc->SetFillMode( fillmode ? ZFM_SEGMENTS : ZFM_POLYGONS );
2619 
2620  // @todo ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF: don't really want pcbnew.h
2621  // in here, after all, its a PLUGIN and global data is evil.
2622  // put in accessor
2623  if( arcsegcount >= 32 )
2624  arcsegcount = 32;
2625 
2626  zc->SetArcSegmentCount( arcsegcount );
2627  zc->SetIsFilled( fillstate == 'S' );
2628  zc->SetThermalReliefGap( thermalReliefGap );
2629  zc->SetThermalReliefCopperBridge( thermalReliefCopperBridge );
2630  }
2631 
2632  else if( TESTLINE( "ZClearance" ) ) // Clearance and pad options info found
2633  {
2634  // e.g. "ZClearance 40 I"
2635  BIU clearance = biuParse( line + SZ( "ZClearance" ), &data );
2636  char* padoption = strtok_r( (char*) data, delims, &saveptr ); // data: " I"
2637 
2638  ZoneConnection popt;
2639  switch( *padoption )
2640  {
2641  case 'I': popt = PAD_ZONE_CONN_FULL; break;
2642  case 'T': popt = PAD_ZONE_CONN_THERMAL; break;
2643  case 'H': popt = PAD_ZONE_CONN_THT_THERMAL; break;
2644  case 'X': popt = PAD_ZONE_CONN_NONE; break;
2645 
2646  default:
2647  m_error.Printf( _( "Bad ZClearance padoption for CZONE_CONTAINER \"%s\"" ),
2648  zc->GetNetname().GetData() );
2650  }
2651 
2652  zc->SetZoneClearance( clearance );
2653  zc->SetPadConnection( popt );
2654  }
2655 
2656  else if( TESTLINE( "ZMinThickness" ) )
2657  {
2658  BIU thickness = biuParse( line + SZ( "ZMinThickness" ) );
2659  zc->SetMinThickness( thickness );
2660  }
2661 
2662  else if( TESTLINE( "ZPriority" ) )
2663  {
2664  int priority = intParse( line + SZ( "ZPriority" ) );
2665  zc->SetPriority( priority );
2666  }
2667 
2668  else if( TESTLINE( "$POLYSCORNERS" ) )
2669  {
2670  // Read the PolysList (polygons that are the solid areas in the filled zone)
2671  SHAPE_POLY_SET polysList;
2672 
2673  bool makeNewOutline = true;
2674 
2675  while( ( line = READLINE( m_reader ) ) != NULL )
2676  {
2677  if( TESTLINE( "$endPOLYSCORNERS" ) )
2678  break;
2679 
2680  // e.g. "39610 43440 0 0"
2681  BIU x = biuParse( line, &data );
2682  BIU y = biuParse( data, &data );
2683 
2684  if( makeNewOutline )
2685  polysList.NewOutline();
2686 
2687  polysList.Append( x, y );
2688 
2689  bool end_contour = intParse( data, &data ); // end_countour was a bool when file saved, so '0' or '1' here
2690  intParse( data ); // skip corner utility flag
2691 
2692  makeNewOutline = end_contour;
2693  }
2694 
2695  zc->SetFilledPolysList( polysList );
2696  }
2697 
2698  else if( TESTLINE( "$FILLSEGMENTS" ) )
2699  {
2700  while( ( line = READLINE( m_reader ) ) != NULL )
2701  {
2702  if( TESTLINE( "$endFILLSEGMENTS" ) )
2703  break;
2704 
2705  // e.g. ""%d %d %d %d\n"
2706  BIU sx = biuParse( line, &data );
2707  BIU sy = biuParse( data, &data );
2708  BIU ex = biuParse( data, &data );
2709  BIU ey = biuParse( data );
2710 
2711  zc->FillSegments().push_back( SEG( VECTOR2I( sx, sy ), VECTOR2I( ex, ey ) ) );
2712  }
2713  }
2714 
2715  else if( TESTLINE( "$endCZONE_OUTLINE" ) )
2716  {
2717  // Ensure keepout does not have a net
2718  // (which have no sense for a keepout zone)
2719  if( zc->GetIsKeepout() )
2720  zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2721 
2722  // should always occur, but who knows, a zone without two corners
2723  // is no zone at all, it's a spot?
2724 
2725  if( zc->GetNumCorners() > 2 )
2726  {
2727  if( !zc->IsOnCopperLayer() )
2728  {
2729  zc->SetFillMode( ZFM_POLYGONS );
2730  zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2731  }
2732 
2733  // Hatch here, after outlines corners are read
2734  // Set hatch here, after outlines corners are read
2735  zc->SetHatch( outline_hatch, ZONE_CONTAINER::GetDefaultHatchPitch(),
2736  true );
2737 
2738  m_board->Add( zc.release() );
2739  }
2740 
2741  return; // preferred exit
2742  }
2743  }
2744 
2745  THROW_IO_ERROR( "Missing '$endCZONE_OUTLINE'" );
2746 }
2747 
2748 
2750 {
2751  unique_ptr<DIMENSION> dim( new DIMENSION( m_board ) );
2752 
2753  char* line;
2754  char* saveptr;
2755 
2756  while( ( line = READLINE( m_reader ) ) != NULL )
2757  {
2758  const char* data;
2759 
2760  if( TESTLINE( "$endCOTATION" ) )
2761  {
2762  m_board->Add( dim.release(), ADD_APPEND );
2763  return; // preferred exit
2764  }
2765 
2766  else if( TESTLINE( "Va" ) )
2767  {
2768  BIU value = biuParse( line + SZ( "Va" ) );
2769  dim->SetValue( value );
2770  }
2771 
2772  else if( TESTLINE( "Ge" ) )
2773  {
2774  LAYER_NUM layer_num;
2775  unsigned long timestamp;
2776  int shape;
2777  int ilayer;
2778 
2779  sscanf( line + SZ( "Ge" ), " %d %d %lX", &shape, &ilayer, &timestamp );
2780 
2781  if( ilayer < FIRST_NON_COPPER_LAYER )
2782  layer_num = FIRST_NON_COPPER_LAYER;
2783  else if( ilayer > LAST_NON_COPPER_LAYER )
2784  layer_num = LAST_NON_COPPER_LAYER;
2785  else
2786  layer_num = ilayer;
2787 
2788  dim->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2789  dim->SetTimeStamp( (timestamp_t) timestamp );
2790  dim->SetShape( shape );
2791  }
2792 
2793  else if( TESTLINE( "Te" ) )
2794  {
2795  char buf[2048];
2796 
2797  ReadDelimitedText( buf, line + SZ( "Te" ), sizeof(buf) );
2798  dim->SetText( FROM_UTF8( buf ) );
2799  }
2800 
2801  else if( TESTLINE( "Po" ) )
2802  {
2803  // sscanf( Line + 2, " %d %d %d %d %d %d %d", &m_Text->m_Pos.x, &m_Text->m_Pos.y,
2804  // &m_Text->m_Size.x, &m_Text->m_Size.y, &thickness, &orientation, &normal_display );
2805 
2806  BIU pos_x = biuParse( line + SZ( "Po" ), &data );
2807  BIU pos_y = biuParse( data, &data );
2808  BIU width = biuParse( data, &data );
2809  BIU height = biuParse( data, &data );
2810  BIU thickn = biuParse( data, &data );
2811  double orient = degParse( data, &data );
2812  char* mirror = strtok_r( (char*) data, delims, &saveptr );
2813 
2814  // This sets both DIMENSION's position and internal m_Text's.
2815  // @todo: But why do we even know about internal m_Text?
2816  dim->SetPosition( wxPoint( pos_x, pos_y ) );
2817  dim->SetTextSize( wxSize( width, height ) );
2818 
2819  dim->Text().SetMirrored( mirror && *mirror == '0' );
2820  dim->Text().SetThickness( thickn );
2821  dim->Text().SetTextAngle( orient );
2822  }
2823 
2824  else if( TESTLINE( "Sb" ) )
2825  {
2826  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_crossBarOx, &m_crossBarOy, &m_crossBarFx, &m_crossBarFy, &m_Width );
2827 
2828  int ignore = biuParse( line + SZ( "Sb" ), &data );
2829  BIU crossBarOx = biuParse( data, &data );
2830  BIU crossBarOy = biuParse( data, &data );
2831  BIU crossBarFx = biuParse( data, &data );
2832  BIU crossBarFy = biuParse( data, &data );
2833  BIU width = biuParse( data );
2834 
2835  dim->m_crossBarO.x = crossBarOx;
2836  dim->m_crossBarO.y = crossBarOy;
2837  dim->m_crossBarF.x = crossBarFx;
2838  dim->m_crossBarF.y = crossBarFy;
2839  dim->SetWidth( width );
2840  (void) ignore;
2841  }
2842 
2843  else if( TESTLINE( "Sd" ) )
2844  {
2845  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_featureLineDOx, &m_featureLineDOy, &m_featureLineDFx, &m_featureLineDFy, &Dummy );
2846 
2847  int ignore = intParse( line + SZ( "Sd" ), &data );
2848  BIU featureLineDOx = biuParse( data, &data );
2849  BIU featureLineDOy = biuParse( data, &data );
2850  BIU featureLineDFx = biuParse( data, &data );
2851  BIU featureLineDFy = biuParse( data );
2852 
2853  dim->m_featureLineDO.x = featureLineDOx;
2854  dim->m_featureLineDO.y = featureLineDOy;
2855  dim->m_featureLineDF.x = featureLineDFx;
2856  dim->m_featureLineDF.y = featureLineDFy;
2857  (void) ignore;
2858  }
2859 
2860  else if( TESTLINE( "Sg" ) )
2861  {
2862  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_featureLineGOx, &m_featureLineGOy, &m_featureLineGFx, &m_featureLineGFy, &Dummy );
2863 
2864  int ignore = intParse( line + SZ( "Sg" ), &data );
2865  BIU featureLineGOx = biuParse( data, &data );
2866  BIU featureLineGOy = biuParse( data, &data );
2867  BIU featureLineGFx = biuParse( data, &data );
2868  BIU featureLineGFy = biuParse( data );
2869 
2870  dim->m_featureLineGO.x = featureLineGOx;
2871  dim->m_featureLineGO.y = featureLineGOy;
2872  dim->m_featureLineGF.x = featureLineGFx;
2873  dim->m_featureLineGF.y = featureLineGFy;
2874  (void) ignore;
2875  }
2876 
2877  else if( TESTLINE( "S1" ) )
2878  {
2879  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowD1Ox, &m_arrowD1Oy, &m_arrowD1Fx, &m_arrowD1Fy, &Dummy );
2880 
2881  int ignore = intParse( line + SZ( "S1" ), &data );
2882  biuParse( data, &data ); // skipping excessive data
2883  biuParse( data, &data ); // skipping excessive data
2884  BIU arrowD1Fx = biuParse( data, &data );
2885  BIU arrowD1Fy = biuParse( data );
2886 
2887  dim->m_arrowD1F.x = arrowD1Fx;
2888  dim->m_arrowD1F.y = arrowD1Fy;
2889  (void) ignore;
2890  }
2891 
2892  else if( TESTLINE( "S2" ) )
2893  {
2894  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowD2Ox, &m_arrowD2Oy, &m_arrowD2Fx, &m_arrowD2Fy, &Dummy );
2895 
2896  int ignore = intParse( line + SZ( "S2" ), &data );
2897  biuParse( data, &data ); // skipping excessive data
2898  biuParse( data, &data ); // skipping excessive data
2899  BIU arrowD2Fx = biuParse( data, &data );
2900  BIU arrowD2Fy = biuParse( data, &data );
2901 
2902  dim->m_arrowD2F.x = arrowD2Fx;
2903  dim->m_arrowD2F.y = arrowD2Fy;
2904  (void) ignore;
2905  }
2906 
2907  else if( TESTLINE( "S3" ) )
2908  {
2909  // sscanf( Line + 2, " %d %d %d %d %d %d\n", &Dummy, &m_arrowG1Ox, &m_arrowG1Oy, &m_arrowG1Fx, &m_arrowG1Fy, &Dummy );
2910  int ignore = intParse( line + SZ( "S3" ), &data );
2911  biuParse( data, &data ); // skipping excessive data
2912  biuParse( data, &data ); // skipping excessive data
2913  BIU arrowG1Fx = biuParse( data, &data );
2914  BIU arrowG1Fy = biuParse( data, &data );
2915 
2916  dim->m_arrowG1F.x = arrowG1Fx;
2917  dim->m_arrowG1F.y = arrowG1Fy;
2918  (void) ignore;
2919  }
2920 
2921  else if( TESTLINE( "S4" ) )
2922  {
2923  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowG2Ox, &m_arrowG2Oy, &m_arrowG2Fx, &m_arrowG2Fy, &Dummy );
2924  int ignore = intParse( line + SZ( "S4" ), &data );
2925  biuParse( data, &data ); // skipping excessive data
2926  biuParse( data, &data ); // skipping excessive data
2927  BIU arrowG2Fx = biuParse( data, &data );
2928  BIU arrowG2Fy = biuParse( data, &data );
2929 
2930  dim->m_arrowG2F.x = arrowG2Fx;
2931  dim->m_arrowG2F.y = arrowG2Fy;
2932  (void) ignore;
2933  }
2934  }
2935 
2936  THROW_IO_ERROR( "Missing '$endCOTATION'" );
2937 }
2938 
2939 
2941 {
2942  char* line;
2943 
2944  while( ( line = READLINE( m_reader ) ) != NULL )
2945  {
2946  const char* data;
2947 
2948  if( TESTLINE( "$EndPCB_TARGET" ) || TESTLINE( "$EndMIREPCB" ) )
2949  {
2950  return; // preferred exit
2951  }
2952 
2953  else if( TESTLINE( "Po" ) )
2954  {
2955  // sscanf( Line + 2, " %X %d %d %d %d %d %lX", &m_Shape, &m_Layer, &m_Pos.x, &m_Pos.y, &m_Size, &m_Width, &m_TimeStamp );
2956 
2957  int shape = intParse( line + SZ( "Po" ), &data );
2958 
2959  LAYER_NUM layer_num = layerParse( data, &data );
2960 
2961  BIU pos_x = biuParse( data, &data );
2962  BIU pos_y = biuParse( data, &data );
2963  BIU size = biuParse( data, &data );
2964  BIU width = biuParse( data, &data );
2965  timestamp_t timestamp = hexParse( data );
2966 
2967  if( layer_num < FIRST_NON_COPPER_LAYER )
2968  layer_num = FIRST_NON_COPPER_LAYER;
2969 
2970  else if( layer_num > LAST_NON_COPPER_LAYER )
2971  layer_num = LAST_NON_COPPER_LAYER;
2972 
2973  PCB_TARGET* t = new PCB_TARGET( m_board, shape, leg_layer2new( m_cu_count, layer_num ),
2974  wxPoint( pos_x, pos_y ), size, width );
2975  m_board->Add( t, ADD_APPEND );
2976 
2977  t->SetTimeStamp( timestamp );
2978  }
2979  }
2980 
2981  THROW_IO_ERROR( "Missing '$EndDIMENSION'" );
2982 }
2983 
2984 
2985 BIU LEGACY_PLUGIN::biuParse( const char* aValue, const char** nptrptr )
2986 {
2987  char* nptr;
2988 
2989  errno = 0;
2990 
2991  double fval = strtod( aValue, &nptr );
2992 
2993  if( errno )
2994  {
2995  m_error.Printf( _( "invalid float number in file: \"%s\"\nline: %d, offset: %d" ),
2996  m_reader->GetSource().GetData(),
2997  m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
2998 
3000  }
3001 
3002  if( aValue == nptr )
3003  {
3004  m_error.Printf( _( "missing float number in file: \"%s\"\nline: %d, offset: %d" ),
3005  m_reader->GetSource().GetData(),
3006  m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
3007 
3009  }
3010 
3011  if( nptrptr )
3012  *nptrptr = nptr;
3013 
3014  fval *= diskToBiu;
3015 
3016  // fval is up into the whole number realm here, and should be bounded
3017  // within INT_MIN to INT_MAX since BIU's are nanometers.
3018  return KiROUND( fval );
3019 }
3020 
3021 
3022 double LEGACY_PLUGIN::degParse( const char* aValue, const char** nptrptr )
3023 {
3024  char* nptr;
3025 
3026  errno = 0;
3027 
3028  double fval = strtod( aValue, &nptr );
3029 
3030  if( errno )
3031  {
3032  m_error.Printf( _( "invalid float number in file: \"%s\"\nline: %d, offset: %d" ),
3033  m_reader->GetSource().GetData(), m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
3034 
3036  }
3037 
3038  if( aValue == nptr )
3039  {
3040  m_error.Printf( _( "missing float number in file: \"%s\"\nline: %d, offset: %d" ),
3041  m_reader->GetSource().GetData(), m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
3042 
3044  }
3045 
3046  if( nptrptr )
3047  *nptrptr = nptr;
3048 
3049  return fval;
3050 }
3051 
3052 
3053 void LEGACY_PLUGIN::init( const PROPERTIES* aProperties )
3054 {
3056  m_cu_count = 16;
3057  m_board = NULL;
3058  m_props = aProperties;
3059 
3060  // conversion factor for saving RAM BIUs to KICAD legacy file format.
3061  biuToDisk = 1.0/IU_PER_MM; // BIUs are nanometers & file is mm
3062 
3063  // Conversion factor for loading KICAD legacy file format into BIUs in RAM
3064  // Start by assuming the *.brd file is in deci-mils.
3065  // If we see "Units mm" in the $GENERAL section, set diskToBiu to 1000000.0
3066  // then, during the file loading process, to start a conversion from
3067  // mm to nanometers. The deci-mil legacy files have no such "Units" marker
3068  // so we must assume the file is in deci-mils until told otherwise.
3069 
3070  diskToBiu = IU_PER_MILS / 10; // BIUs are nanometers
3071 }
3072 
3073 
3074 void LEGACY_PLUGIN::SaveModule3D( const MODULE* me ) const
3075 {
3076  auto sM = me->Models().begin();
3077  auto eM = me->Models().end();
3078 
3079  while( sM != eM )
3080  {
3081  if( sM->m_Filename.empty() )
3082  {
3083  ++sM;
3084  continue;
3085  }
3086 
3087  fprintf( m_fp, "$SHAPE3D\n" );
3088 
3089  fprintf( m_fp, "Na %s\n", EscapedUTF8( sM->m_Filename ).c_str() );
3090 
3091  fprintf(m_fp,
3092 #if defined(DEBUG)
3093  // use old formats for testing, just to verify compatibility
3094  // using "diff", then switch to more concise form for release builds.
3095  "Sc %lf %lf %lf\n",
3096 #else
3097  "Sc %.10g %.10g %.10g\n",
3098 #endif
3099  sM->m_Scale.x,
3100  sM->m_Scale.y,
3101  sM->m_Scale.z );
3102 
3103  fprintf(m_fp,
3104 #if defined(DEBUG)
3105  "Of %lf %lf %lf\n",
3106 #else
3107  "Of %.10g %.10g %.10g\n",
3108 #endif
3109  sM->m_Offset.x,
3110  sM->m_Offset.y,
3111  sM->m_Offset.z );
3112 
3113  fprintf(m_fp,
3114 #if defined(DEBUG)
3115  "Ro %lf %lf %lf\n",
3116 #else
3117  "Ro %.10g %.10g %.10g\n",
3118 #endif
3119  sM->m_Rotation.x,
3120  sM->m_Rotation.y,
3121  sM->m_Rotation.z );
3122 
3123  fprintf( m_fp, "$EndSHAPE3D\n" );
3124 
3125  ++sM;
3126  }
3127 
3128  return;
3129 }
3130 
3131 
3132 //-----<FOOTPRINT LIBRARY FUNCTIONS>--------------------------------------------
3133 
3134 /*
3135 
3136  The legacy file format is being obsoleted and this code will have a short
3137  lifetime, so it only needs to be good enough for a short duration of time.
3138  Caching all the MODULEs is a bit memory intensive, but it is a considerably
3139  faster way of fulfilling the API contract. Otherwise, without the cache, you
3140  would have to re-read the file when searching for any MODULE, and this would
3141  be very problematic filling a FOOTPRINT_LIST via this PLUGIN API. If memory
3142  becomes a concern, consider the cache lifetime policy, which determines the
3143  time that a LP_CACHE is in RAM. Note PLUGIN lifetime also plays a role in
3144  cache lifetime.
3145 
3146 */
3147 
3148 
3149 #include <boost/ptr_container/ptr_map.hpp>
3150 #include <wx/filename.h>
3151 
3152 typedef boost::ptr_map< std::string, MODULE > MODULE_MAP;
3153 typedef MODULE_MAP::iterator MODULE_ITER;
3154 typedef MODULE_MAP::const_iterator MODULE_CITER;
3155 
3156 
3163 struct LP_CACHE
3164 {
3165  LEGACY_PLUGIN* m_owner; // my owner, I need its LEGACY_PLUGIN::loadMODULE()
3166  wxString m_lib_path;
3167  MODULE_MAP m_modules; // map or tuple of footprint_name vs. MODULE*
3169 
3170  bool m_cache_dirty; // Stored separately because it's expensive to check
3171  // m_cache_timestamp against all the files.
3172  long long m_cache_timestamp; // A hash of the timestamps for all the footprint
3173  // files.
3174 
3175  LP_CACHE( LEGACY_PLUGIN* aOwner, const wxString& aLibraryPath );
3176 
3177  // Most all functions in this class throw IO_ERROR exceptions. There are no
3178  // error codes nor user interface calls from here, nor in any PLUGIN.
3179  // Catch these exceptions higher up please.
3180 
3181  void Load();
3182 
3183  void ReadAndVerifyHeader( LINE_READER* aReader );
3184 
3185  void SkipIndex( LINE_READER* aReader );
3186 
3187  void LoadModules( LINE_READER* aReader );
3188 
3189  bool IsModified();
3190  static long long GetTimestamp( const wxString& aLibPath );
3191 };
3192 
3193 
3194 LP_CACHE::LP_CACHE( LEGACY_PLUGIN* aOwner, const wxString& aLibraryPath ) :
3195  m_owner( aOwner ),
3196  m_lib_path( aLibraryPath ),
3197  m_writable( true ),
3198  m_cache_dirty( true ),
3199  m_cache_timestamp( 0 )
3200 {
3201 }
3202 
3203 
3205 {
3207 
3208  return m_cache_dirty;
3209 }
3210 
3211 
3212 long long LP_CACHE::GetTimestamp( const wxString& aLibPath )
3213 {
3214  return wxFileName( aLibPath ).GetModificationTime().GetValue().GetValue();
3215 }
3216 
3217 
3219 {
3220  m_cache_dirty = false;
3221 
3222  FILE_LINE_READER reader( m_lib_path );
3223 
3224  ReadAndVerifyHeader( &reader );
3225  SkipIndex( &reader );
3226  LoadModules( &reader );
3227 
3228  // Remember the file modification time of library file when the
3229  // cache snapshot was made, so that in a networked environment we will
3230  // reload the cache as needed.
3232 }
3233 
3234 
3236 {
3237  char* line = aReader->ReadLine();
3238  char* saveptr;
3239 
3240  if( !line )
3241  goto L_bad_library;
3242 
3243  if( !TESTLINE( "PCBNEW-LibModule-V1" ) )
3244  goto L_bad_library;
3245 
3246  while( ( line = aReader->ReadLine() ) != NULL )
3247  {
3248  if( TESTLINE( "Units" ) )
3249  {
3250  const char* units = strtok_r( line + SZ( "Units" ), delims, &saveptr );
3251 
3252  if( !strcmp( units, "mm" ) )
3253  {
3254  m_owner->diskToBiu = IU_PER_MM;
3255  }
3256 
3257  }
3258  else if( TESTLINE( "$INDEX" ) )
3259  return;
3260  }
3261 
3262 L_bad_library:
3263  THROW_IO_ERROR( wxString::Format( _( "File \"%s\" is empty or is not a legacy library" ),
3264  m_lib_path.GetData() ) );
3265 }
3266 
3267 
3269 {
3270  // Some broken INDEX sections have more than one section, due to prior bugs.
3271  // So we must read the next line after $EndINDEX tag,
3272  // to see if this is not a new $INDEX tag.
3273  bool exit = false;
3274  char* line = aReader->Line();
3275 
3276  do
3277  {
3278  if( TESTLINE( "$INDEX" ) )
3279  {
3280  exit = false;
3281 
3282  while( ( line = aReader->ReadLine() ) != NULL )
3283  {
3284  if( TESTLINE( "$EndINDEX" ) )
3285  {
3286  exit = true;
3287  break;
3288  }
3289  }
3290  }
3291  else if( exit )
3292  break;
3293  } while( ( line = aReader->ReadLine() ) != NULL );
3294 }
3295 
3296 
3298 {
3299  m_owner->SetReader( aReader );
3300 
3301  char* line = aReader->Line();
3302 
3303  do
3304  {
3305  // test first for the $MODULE, even before reading because of INDEX bug.
3306  if( TESTLINE( "$MODULE" ) )
3307  {
3308  unique_ptr<MODULE> module( new MODULE( m_owner->m_board ) );
3309 
3310  std::string footprintName = StrPurge( line + SZ( "$MODULE" ) );
3311 
3312  // The footprint names in legacy libraries can contain the '/' and ':'
3313  // characters which will cause the LIB_ID parser to choke.
3314  ReplaceIllegalFileNameChars( &footprintName );
3315 
3316  // set the footprint name first thing, so exceptions can use name.
3317  module->SetFPID( LIB_ID( wxEmptyString, footprintName ) );
3318 
3319  m_owner->loadMODULE( module.get() );
3320 
3321  MODULE* m = module.release(); // exceptions after this are not expected.
3322 
3323  // Not sure why this is asserting on debug builds. The debugger shows the
3324  // strings are the same. If it's not really needed maybe it can be removed.
3325 // wxASSERT( footprintName == m->GetFPID().GetLibItemName() );
3326 
3327  /*
3328 
3329  There was a bug in old legacy library management code
3330  (pre-LEGACY_PLUGIN) which was introducing duplicate footprint names
3331  in legacy libraries without notification. To best recover from such
3332  bad libraries, and use them to their fullest, there are a few
3333  strategies that could be used. (Note: footprints must have unique
3334  names to be accepted into this cache.) The strategy used here is to
3335  append a differentiating version counter to the end of the name as:
3336  _v2, _v3, etc.
3337 
3338  */
3339 
3340  MODULE_CITER it = m_modules.find( footprintName );
3341 
3342  if( it == m_modules.end() ) // footprintName is not present in cache yet.
3343  {
3344  std::pair<MODULE_ITER, bool> r = m_modules.insert( footprintName, m );
3345 
3346  wxASSERT_MSG( r.second, wxT( "error doing cache insert using guaranteed unique name" ) );
3347  (void) r;
3348  }
3349 
3350  // Bad library has a duplicate of this footprintName, generate a
3351  // unique footprint name and load it anyway.
3352  else
3353  {
3354  bool nameOK = false;
3355  int version = 2;
3356  char buf[48];
3357 
3358  while( !nameOK )
3359  {
3360  std::string newName = footprintName;
3361 
3362  newName += "_v";
3363  sprintf( buf, "%d", version++ );
3364  newName += buf;
3365 
3366  it = m_modules.find( newName );
3367 
3368  if( it == m_modules.end() )
3369  {
3370  nameOK = true;
3371 
3372  m->SetFPID( LIB_ID( wxEmptyString, newName ) );
3373  std::pair<MODULE_ITER, bool> r = m_modules.insert( newName, m );
3374 
3375  wxASSERT_MSG( r.second, wxT( "error doing cache insert using guaranteed unique name" ) );
3376  (void) r;
3377  }
3378  }
3379  }
3380  }
3381 
3382  } while( ( line = aReader->ReadLine() ) != NULL );
3383 }
3384 
3385 
3386 long long LEGACY_PLUGIN::GetLibraryTimestamp( const wxString& aLibraryPath ) const
3387 {
3388  return LP_CACHE::GetTimestamp( aLibraryPath );
3389 }
3390 
3391 
3392 void LEGACY_PLUGIN::cacheLib( const wxString& aLibraryPath )
3393 {
3394  if( !m_cache || m_cache->m_lib_path != aLibraryPath || m_cache->IsModified() )
3395  {
3396  // a spectacular episode in memory management:
3397  delete m_cache;
3398  m_cache = new LP_CACHE( this, aLibraryPath );
3399  m_cache->Load();
3400  }
3401 }
3402 
3403 
3404 void LEGACY_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames,
3405  const wxString& aLibraryPath,
3406  const PROPERTIES* aProperties )
3407 {
3408  LOCALE_IO toggle; // toggles on, then off, the C locale.
3409 
3410  init( aProperties );
3411 
3412  cacheLib( aLibraryPath );
3413 
3414  const MODULE_MAP& mods = m_cache->m_modules;
3415 
3416  for( MODULE_CITER it = mods.begin(); it != mods.end(); ++it )
3417  {
3418  aFootprintNames.Add( FROM_UTF8( it->first.c_str() ) );
3419  }
3420 }
3421 
3422 
3423 MODULE* LEGACY_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
3424  const wxString& aFootprintName, const PROPERTIES* aProperties )
3425 {
3426  LOCALE_IO toggle; // toggles on, then off, the C locale.
3427 
3428  init( aProperties );
3429 
3430  cacheLib( aLibraryPath );
3431 
3432  const MODULE_MAP& mods = m_cache->m_modules;
3433 
3434  MODULE_CITER it = mods.find( TO_UTF8( aFootprintName ) );
3435 
3436  if( it == mods.end() )
3437  {
3438  /*
3439  THROW_IO_ERROR( wxString::Format( _( "No \"%s\" footprint in library \"%s\"" ),
3440  aFootprintName.GetData(), aLibraryPath.GetData() ) );
3441  */
3442 
3443  return NULL;
3444  }
3445 
3446  // copy constructor to clone the already loaded MODULE
3447  return new MODULE( *it->second );
3448 }
3449 
3450 
3451 bool LEGACY_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
3452 {
3453  wxFileName fn = aLibraryPath;
3454 
3455  if( !fn.FileExists() )
3456  return false;
3457 
3458  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
3459  // we don't want that. we want bare metal portability with no UI here.
3460  if( wxRemove( aLibraryPath ) )
3461  {
3463  _( "library \"%s\" cannot be deleted" ),
3464  aLibraryPath.GetData() ) );
3465  }
3466 
3467  if( m_cache && m_cache->m_lib_path == aLibraryPath )
3468  {
3469  delete m_cache;
3470  m_cache = 0;
3471  }
3472 
3473  return true;
3474 }
3475 
3476 
3477 bool LEGACY_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
3478 {
3479 #if 0 // no support for 32 Cu layers in legacy format
3480  return false;
3481 #else
3482  LOCALE_IO toggle;
3483 
3484  init( NULL );
3485 
3486  cacheLib( aLibraryPath );
3487 
3488  return m_cache->m_writable;
3489 #endif
3490 }
3491 
3492 
3494  m_cu_count( 16 ), // for FootprintLoad()
3495  m_board( 0 ),
3496  m_props( 0 ),
3497  m_reader( 0 ),
3498  m_fp( 0 ),
3499  m_cache( 0 ),
3500  m_mapping( new NETINFO_MAPPING() )
3501 {
3502  init( NULL );
3503 }
3504 
3505 
3507 {
3508  delete m_cache;
3509  delete m_mapping;
3510 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:191
void SetComment1(const wxString &aComment)
Definition: title_block.h:117
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
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory)...
CITER next(CITER it)
Definition: ptree.cpp:130
void SetPlacementCost90(int aCost)
Definition: class_module.h:584
int m_SolderMaskMargin
Solder mask margin.
void SetFileFormatVersionAtLoad(int aVersion)
Definition: class_board.h:280
BOARD_ITEM_CONTAINER * GetParent() const
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
void SetZoneSettings(const ZONE_SETTINGS &aSettings)
Definition: class_board.h:563
#define SILKSCREEN_N_BACK
void SetTextAngle(double aAngle)
Class LINE_READER is an abstract class from which implementation specific LINE_READERs may be derived...
Definition: richio.h:81
TEXTE_MODULE & Reference()
Definition: class_module.h:513
void SetThermalGap(int aGap)
Definition: class_module.h:223
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:62
const ZONE_SETTINGS & GetZoneSettings() const
Definition: class_board.h:562
unsigned LAYER_MSK
NETCLASSPTR GetDefault() const
Function GetDefault.
virtual unsigned LineNumber() const
Function Line Number returns the line number of the last line read from this LINE_READER.
Definition: richio.h:159
wxPoint m_GridOrigin
origin for grid offsets
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
TEXTE_PCB class definition.
void cacheLib(const wxString &aLibraryPath)
we only cache one footprint library for now, this determines which one.
MODULE_MAP::const_iterator MODULE_CITER
char * StrPurge(char *text)
Function StrPurge removes leading and training spaces, tabs and end of line chars in text return a po...
Definition: string.cpp:271
long timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: common.h:52
void SetViaType(VIATYPE_T aViaType)
Definition: class_track.h:458
void SetLocalClearance(int aClearance)
Definition: class_module.h:209
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:120
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
PAD_ATTR_T
Enum PAD_ATTR_T is the set of pad shapes, used with D_PAD::{Set,Get}Attribute() The double name is fo...
Definition: pad_shapes.h:58
LP_CACHE(LEGACY_PLUGIN *aOwner, const wxString &aLibraryPath)
void loadMODULE_TEXT(TEXTE_MODULE *aText)
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
void SetPlacementCost180(int aCost)
Definition: class_module.h:581
Class PCB_PLOT_PARAMS_PARSER is the parser class for PCB_PLOT_PARAMS.
void SetEnd(const wxPoint &aEnd)
Definition: class_track.h:118
std::vector< int > m_TrackWidthList
static int intParse(const char *next, const char **out=NULL)
Function intParse parses an ASCII integer string with possible leading whitespace into an integer and...
void SetRevision(const wxString &aRevision)
Definition: title_block.h:84
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: class_board.h:560
#define LAYER_N_BACK
void CalculateBoundingBox()
Function CalculateBoundingBox calculates the bounding box in board coordinates.
Class BOARD to handle a board.
LEGACY_PLUGIN * m_owner
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: class_board.h:554
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)
boost::ptr_map< std::string, MODULE > MODULE_MAP
#define COMMENT_N
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:61
#define EDGE_N
#define ADHESIVE_N_FRONT
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:236
static const char delims[]
void SetVisible(bool aVisible)
Definition: eda_text.h:188
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
void SetCopperLayerCount(int aCount)
static LAYER_NUM layerParse(const char *next, const char **out=NULL)
Function layerParse Like intParse but returns a LAYER_NUM.
void loadMODULE(MODULE *aModule)
friend struct LP_CACHE
Definition: legacy_plugin.h:68
void SkipIndex(LINE_READER *aReader)
BOARD * Load(const wxString &aFileName, BOARD *aAppendToMe, const PROPERTIES *aProperties=NULL) override
Function Load loads information from some input file format that this PLUGIN implementation knows abo...
bool FootprintLibDelete(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintLibDelete deletes an existing footprint library and returns true, or if library does not exist returns false, or throws an exception if library exists but is read only or cannot be deleted for some other reason.
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Function ReplaceIllegalFileNameChars checks aName for illegal file name characters.
Definition: string.cpp:650
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.
bool IsModified()
void SetZoneConnection(ZoneConnection aType)
Definition: class_module.h:217
usual segment : line with rounded ends
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:78
#define READLINE(rdr)
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:274
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:227
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
static PCB_LAYER_ID leg_layer2new(int cu_count, LAYER_NUM aLayerNum)
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Function SetLayerType changes the type of the layer given by aLayer.
#define SOLDERMASK_N_FRONT
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
VIATYPE_T
Definition: class_track.h:50
wxString m_field
reused to stuff MODULE fields.
Class PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
void SetBoardThickness(int aThickness)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
defines the basic data associated with a single 3D model.
Class TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout, or editing view.
Definition: title_block.h:40
PAD_DRILL_SHAPE_T
Enum PAD_DRILL_SHAPE_T is the set of pad drill shapes, used with D_PAD::{Set,Get}DrillShape() ...
Definition: pad_shapes.h:46
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:203
void SetLocalSolderPasteMarginRatio(double aRatio)
Definition: class_module.h:215
int m_loading_format_version
which BOARD_FORMAT_VERSION am I Load()ing?
#define ECO2_N
static int GetDefaultHatchPitch()
Function GetDefaultHatchPitchMils.
PAD_SHAPE_T
Enum PAD_SHAPE_T is the set of pad shapes, used with D_PAD::{Set,Get}Shape()
Definition: pad_shapes.h:31
#define SOLDERMASK_N_BACK
void SetReader(LINE_READER *aReader)
Functions relatives to tracks, vias and segments used to fill zones.
void SetComment4(const wxString &aComment)
Definition: title_block.h:120
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
VECTOR3D m_Offset
3D model offset (mm)
Definition: class_module.h:102
#define ADHESIVE_N_BACK
FILE * m_fp
no ownership here.
This file contains miscellaneous commonly used macros and functions.
void load3D(MODULE *aModule)
void SetWidth(int aWidth)
Definition: class_track.h:115
bool m_cache_dirty
double biuToDisk
convert from BIUs to disk engineering units with this scale factor
Class LP_CACHE assists only for the footprint portion of the PLUGIN API, and only for the LEGACY_PLUG...
void PushBack(T *aNewElement)
Function PushBack puts aNewElement at the end of the list sequence.
Definition: dlist.h:250
void SaveModule3D(const MODULE *aModule) const
Pads are not covered.
Definition: zones.h:52
#define SILKSCREEN_N_FRONT
const LIB_ID & GetFPID() const
Definition: class_module.h:193
#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]
BIU biuParse(const char *aValue, const char **nptrptr=NULL)
Function biuParse parses an ASCII decimal floating point value and scales it into a BIU according to ...
std::vector< int > m_netCodes
net codes mapping for boards being loaded
DIMENSION class definition.
std::string EscapedUTF8(const wxString &aString)
Function EscapedUTF8 returns an 8 bit UTF8 string given aString in unicode form.
Definition: string.cpp:214
PCB_LAYER_ID
A quick note on layer IDs:
LINE_READER * m_reader
no ownership here.
Class FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:180
int m_TextThickness[LAYER_CLASS_COUNT]
static EDA_TEXT_HJUSTIFY_T horizJustify(const char *horizontal)
bool is_leg_copperlayer_valid(int aCu_Count, LAYER_NUM aLegacyLayerNum)
Class LSET is a set of PCB_LAYER_IDs.
VIATYPE_T GetViaType() const
Definition: class_track.h:457
void init(const PROPERTIES *aProperties)
initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed.
double GetOrientation() const
Definition: class_module.h:189
Class SHAPE_POLY_SET.
bool IsFootprintLibWritable(const wxString &aLibraryPath) override
Function IsFootprintLibWritable returns true iff the library at aLibraryPath is writable.
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:512
void SetVisibleLayers(LSET aLayerMask)
Function SetVisibleLayers is a proxy function that calls the correspondent function in m_BoardSetting...
Class LEGACY_PLUGIN is a PLUGIN derivation which could possibly be put into a DLL/DSO.
Definition: legacy_plugin.h:66
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
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
char * Line() const
Function Line returns a pointer to the last line that was read in.
Definition: richio.h:139
void loadMODULE_EDGE(MODULE *aModule)
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
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
LAYER_T
Enum LAYER_T gives the allowed types of layers, same as Specctra DSN spec.
Definition: class_board.h:72
void LoadModules(LINE_READER *aReader)
void SetLastEditTime(timestamp_t aTime)
Definition: class_module.h:314
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Function SetLayerName changes the name of the layer given by aLayer.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_INSERT) override
Adds an item to the container.
int m_ViasMinDrill
vias (not micro vias) min drill diameter
void SetCompany(const wxString &aCompany)
Definition: title_block.h:94
unsigned STATUS_FLAGS
Definition: base_struct.h:147
void SetThermalWidth(int aWidth)
Definition: class_module.h:220
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:538
void SetSize(const wxSize &aSize)
Definition: class_pad.h:268
int m_ZoneClearance
Clearance value.
Definition: zone_settings.h:63
STROKE_T
Enum STROKE_T is the set of shapes for segments (graphic segments and tracks) which are often in the ...
#define ECO1_N
bool SetNetCode(int aNetCode, bool aNoAssert=false)
Function SetNetCode sets net using a net code.
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
void SetDesignSettings(const BOARD_DESIGN_SETTINGS &aDesignSettings)
Function SetDesignSettings.
Definition: class_board.h:548
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_Layer contains the top layer, the other layer is in m_BottomLayer...
#define ALL_CU_LAYERS
#define THROW_IO_ERROR(msg)
unsigned LEG_MASK
std::map< wxString, MODULE * > MODULE_MAP
Definition: eagle_plugin.h:36
void SetIsPlaced(bool isPlaced)
Definition: class_module.h:287
LEGACY_PLUGIN::BIU BIU
HATCH_STYLE
Zone hatch styles.
Definition: class_zone.h:67
void SetFileName(const wxString &aFileName)
Definition: class_board.h:235
void SetPosition(const wxPoint &aPos) override
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: class_board.h:557
double diskToBiu
convert from disk engineering units to BIUs with this scale factor
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.
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...
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
BOARD * m_board
which BOARD, no ownership here
void SetType(TEXT_TYPE aType)
int m_LineThickness[LAYER_CLASS_COUNT]
#define TESTSUBSTR(x)
C sub-string compare test for a specific length of characters.
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:253
Thermal relief only for THT pads.
Definition: zones.h:55
void SetLocalSolderMaskMargin(int aMargin)
Definition: class_module.h:206
void SetPos0(const wxPoint &aPos)
void SetDrillDefault()
Function SetDrillDefault sets the drill value for vias to the default value UNDEFINED_DRILL_DIAMETER...
Definition: class_track.h:486
void loadAllSections(bool doAppend)
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
default
Definition: class_module.h:76
static bool isSpace(int c)
Class ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:48
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:69
void loadZONE_CONTAINER()
Definition: seg.h:36
double degParse(const char *aValue, const char **nptrptr=NULL)
Function degParse parses an ASCII decimal floating point value which is certainly an angle...
bool Add(const NETCLASSPTR &aNetclass)
Function Add takes aNetclass and puts it into this NETCLASSES container.
Definition: netclass.cpp:104
#define LAYER_N_FRONT
static LSET leg_mask2new(int cu_count, unsigned aMask)
Class NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:69
void SetLocalSolderPasteMargin(int aMargin)
Definition: class_module.h:212
MODULE_MAP::const_iterator MODULE_CITER
std::list< MODULE_3D_SETTINGS > & Models()
Definition: class_module.h:179
void SetComment2(const wxString &aComment)
Definition: title_block.h:118
long long m_cache_timestamp
virtual char * ReadLine()=0
Function ReadLine reads a line of text into the buffer and increments the line number counter...
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
#define FIRST_LAYER
void SetState(int type, int state)
Definition: base_struct.h:245
void SetLocked(bool isLocked) override
Function SetLocked sets the MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition: class_module.h:278
Class to handle a graphic segment.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: class_module.h:101
#define VERSION_ERROR_FORMAT
static EDA_TEXT_VJUSTIFY_T vertJustify(const char *vertical)
int layerMaskCountSet(LEG_MASK aMask)
Count the number of set layers in the mask.
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
wxString m_lib_path
void SetOrientation(double newangle)
Virtual component: when created by copper shapes on board (Like edge card connectors, mounting hole...)
Definition: class_module.h:79
wxString m_error
for throwing exceptions
void SetPosition(const wxPoint &aPos) override
Definition: class_track.h:112
#define LAST_NON_COPPER_LAYER
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
static long hexParse(const char *next, const char **out=NULL)
Function hexParse parses an ASCII hex integer string with possible leading whitespace into a long int...
#define SOLDERPASTE_N_FRONT
size_t i
Definition: json11.cpp:597
#define DRAW_N
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:239
void SetDrawCoord()
Set absolute coordinates.
virtual const wxString & GetSource() const
Function GetSource returns the name of the source of the lines in an abstract sense.
Definition: richio.h:130
D_PAD m_Pad_Master
A dummy pad to store all default parameters.
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
char * strtok_r(char *str, const char *delim, char **nextp)
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: class_track.h:465
static long long GetTimestamp(const wxString &aLibPath)
Usual pad.
Definition: pad_shapes.h:60
void SetVisibleElements(int aMask)
Function SetVisibleElements changes the bit-mask of visible element categories.
#define IU_PER_MILS
Definition: plotter.cpp:134
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
Definition: class_module.h:100
std::vector< VIA_DIMENSION > m_ViasDimensionsList
#define FIRST_COPPER_LAYER
void SetKeywords(const wxString &aKeywords)
Definition: class_module.h:200
PCB_TARGET class definition.
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:166
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
DLIST< D_PAD > & PadsList()
Definition: class_module.h:163
void SetTextAngle(double aAngle)
Module description (excepted pads)
void SetComment3(const wxString &aComment)
Definition: title_block.h:119
const wxString & GetNetname() const
Function GetNetname.
Definition: netinfo.h:239
bool m_MicroViasAllowed
true to allow micro vias
int m_MicroViasMinDrill
micro vias (not vias) min drill diameter
int ReadDelimitedText(wxString *aDest, const char *aSource)
Function ReadDelimitedText copies bytes from aSource delimited string segment to aDest wxString...
Definition: string.cpp:120
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 loadPAD(MODULE *aModule)
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
#define SZ(x)
Get the length of a string constant, at compile time.
MODULE_MAP::iterator MODULE_ITER
class SEGZONE, a segment used to fill a zone area (segment on a
Definition: typeinfo.h:97
void ReadAndVerifyHeader(LINE_READER *aReader)
int getNetCode(int aNetCode)
Converts net code using the mapping table if available, otherwise returns unchanged net code ...
void SetPortrait(bool aIsPortrait)
Function SetPortrait will rotate the paper page 90 degrees.
Definition: page_info.cpp:182
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:469
const wxPoint GetPosition() const override
Definition: class_module.h:184
void SetFPID(const LIB_ID &aFPID)
Definition: class_module.h:194
#define TESTLINE(x)
C string compare test for a specific length of characters.
void loadTrackList(int aStructType)
Function loadTrackList reads a list of segments (Tracks and Vias, or Segzones)
Use thermal relief for pads.
Definition: zones.h:53
void SetEnabledLayers(LSET aLayerMask)
Function SetEnabledLayers is a proxy function that calls the correspondent function in m_BoardSetting...
wxPoint m_AuxOrigin
origin for plot exports
void SetPath(const wxString &aPath)
Definition: class_module.h:203
Class DIMENSION.
NETINFO_MAPPING * m_mapping
mapping for net codes, so only not empty nets are stored with consecutive integers as net codes ...
MODULE_MAP m_modules
LP_CACHE * m_cache
#define SOLDERPASTE_N_BACK
#define FIRST_NON_COPPER_LAYER
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:161
int m_SolderMaskMinWidth
Solder mask min width.
void SetAttributes(int aAttributes)
Definition: class_module.h:227
MODULE * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintLoad loads a footprint having aFootprintName from the aLibraryPath containing a lib...
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:206
const PROPERTIES * m_props
passed via Save() or Load(), no ownership, may be NULL.
pads are covered by copper
Definition: zones.h:54
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
virtual void SetText(const wxString &aText)
Definition: eda_text.h:154
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) ...
void SetDescription(const wxString &aDoc)
Definition: class_module.h:197