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 = LIB_ID( UTF8( fpName ) );
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_DrawSegmentWidth = tmp;
944  }
945 
946  else if( TESTLINE( "EdgeSegmWidth" ) )
947  {
948  BIU tmp = biuParse( line + SZ( "EdgeSegmWidth" ) );
949  bds.m_EdgeSegmentWidth = 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_PcbTextWidth = 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_PcbTextSize = wxSize( x, y );
1033  }
1034 
1035  else if( TESTLINE( "EdgeModWidth" ) )
1036  {
1037  BIU tmp = biuParse( line + SZ( "EdgeModWidth" ) );
1038  bds.m_ModuleSegmentWidth = tmp;
1039  }
1040 
1041  else if( TESTLINE( "TextModWidth" ) )
1042  {
1043  BIU tmp = biuParse( line + SZ( "TextModWidth" ) );
1044  bds.m_ModuleTextWidth = tmp;
1045  }
1046 
1047  else if( TESTLINE( "TextModSize" ) )
1048  {
1049  BIU x = biuParse( line + SZ( "TextModSize" ), &data );
1050  BIU y = biuParse( data );
1051 
1052  bds.m_ModuleTextSize = wxSize( x, y );
1053  }
1054 
1055  else if( TESTLINE( "PadSize" ) )
1056  {
1057  BIU x = biuParse( line + SZ( "PadSize" ), &data );
1058  BIU y = biuParse( data );
1059 
1060  bds.m_Pad_Master.SetSize( wxSize( x, y ) );
1061  }
1062 
1063  else if( TESTLINE( "PadDrill" ) )
1064  {
1065  BIU tmp = biuParse( line + SZ( "PadDrill" ) );
1066  bds.m_Pad_Master.SetDrillSize( wxSize( tmp, tmp ) );
1067  }
1068 
1069  else if( TESTLINE( "Pad2MaskClearance" ) )
1070  {
1071  BIU tmp = biuParse( line + SZ( "Pad2MaskClearance" ) );
1072  bds.m_SolderMaskMargin = tmp;
1073  }
1074 
1075  else if( TESTLINE( "SolderMaskMinWidth" ) )
1076  {
1077  BIU tmp = biuParse( line + SZ( "SolderMaskMinWidth" ) );
1078  bds.m_SolderMaskMinWidth = tmp;
1079  }
1080 
1081  else if( TESTLINE( "Pad2PasteClearance" ) )
1082  {
1083  BIU tmp = biuParse( line + SZ( "Pad2PasteClearance" ) );
1084  bds.m_SolderPasteMargin = tmp;
1085  }
1086 
1087  else if( TESTLINE( "Pad2PasteClearanceRatio" ) )
1088  {
1089  double ratio = atof( line + SZ( "Pad2PasteClearanceRatio" ) );
1090  bds.m_SolderPasteMarginRatio = ratio;
1091  }
1092 
1093  else if( TESTLINE( "GridOrigin" ) )
1094  {
1095  BIU x = biuParse( line + SZ( "GridOrigin" ), &data );
1096  BIU y = biuParse( data );
1097 
1098  // m_board->SetGridOrigin( wxPoint( x, y ) ); gets overwritten by SetDesignSettings() below
1099  bds.m_GridOrigin = wxPoint( x, y );
1100  }
1101 
1102  else if( TESTLINE( "VisibleElements" ) )
1103  {
1104  int visibleElements = hexParse( line + SZ( "VisibleElements" ) );
1105  bds.SetVisibleElements( visibleElements );
1106  }
1107 
1108  else if( TESTLINE( "$EndSETUP" ) )
1109  {
1110  m_board->SetDesignSettings( bds );
1111  m_board->SetZoneSettings( zs );
1112 
1113  // Very old *.brd file does not have NETCLASSes
1114  // "TrackWidth", "ViaSize", "ViaDrill", "ViaMinSize",
1115  // and "TrackClearence", were defined in SETUP
1116  // these values are put into the default NETCLASS until later board load
1117  // code should override them. *.brd files which have been
1118  // saved with knowledge of NETCLASSes will override these
1119  // defaults, very old boards (before 2009) will not and use the setup values.
1120  // However these values should be the same as default NETCLASS.
1121 
1122  return; // preferred exit
1123  }
1124  }
1125 
1126  // @todo: this code is currently unreachable, would need a goto, to get here.
1127  // that may be better handled with an #ifdef
1128 
1129  /* Ensure tracks and vias sizes lists are ok:
1130  * Sort lists by by increasing value and remove duplicates
1131  * (the first value is not tested, because it is the netclass value
1132  */
1133  BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1134  sort( designSettings.m_ViasDimensionsList.begin() + 1, designSettings.m_ViasDimensionsList.end() );
1135  sort( designSettings.m_TrackWidthList.begin() + 1, designSettings.m_TrackWidthList.end() );
1136 
1137  for( unsigned ii = 1; ii < designSettings.m_ViasDimensionsList.size() - 1; ii++ )
1138  {
1139  if( designSettings.m_ViasDimensionsList[ii] == designSettings.m_ViasDimensionsList[ii + 1] )
1140  {
1141  designSettings.m_ViasDimensionsList.erase( designSettings.m_ViasDimensionsList.begin() + ii );
1142  ii--;
1143  }
1144  }
1145 
1146  for( unsigned ii = 1; ii < designSettings.m_TrackWidthList.size() - 1; ii++ )
1147  {
1148  if( designSettings.m_TrackWidthList[ii] == designSettings.m_TrackWidthList[ii + 1] )
1149  {
1150  designSettings.m_TrackWidthList.erase( designSettings.m_TrackWidthList.begin() + ii );
1151  ii--;
1152  }
1153  }
1154 }
1155 
1156 
1158 {
1159  char* line;
1160  char* saveptr;
1161 
1162  while( ( line = READLINE( m_reader ) ) != NULL )
1163  {
1164  const char* data;
1165 
1166  // most frequently encountered ones at the top
1167 
1168  if( TESTSUBSTR( "D" ) && strchr( "SCAP", line[1] ) ) // read a drawing item, e.g. "DS"
1169  {
1170  loadMODULE_EDGE( aModule );
1171  }
1172 
1173  else if( TESTLINE( "$PAD" ) )
1174  {
1175  loadPAD( aModule );
1176  }
1177 
1178  // Read a footprint text description (ref, value, or drawing)
1179  else if( TESTSUBSTR( "T" ) )
1180  {
1181  // e.g. "T1 6940 -16220 350 300 900 60 M I 20 N "CFCARD"\r\n"
1182 
1183  int tnum = intParse( line + SZ( "T" ) );
1184 
1185  TEXTE_MODULE* textm = 0;
1186 
1187  switch( tnum )
1188  {
1190  textm = &aModule->Reference();
1191  break;
1192 
1194  textm = &aModule->Value();
1195  break;
1196 
1197  // All other fields greater than 1.
1198  default:
1199  textm = new TEXTE_MODULE( aModule );
1200  aModule->GraphicalItemsList().PushBack( textm );
1201  }
1202 
1203  loadMODULE_TEXT( textm );
1204  }
1205 
1206  else if( TESTLINE( "Po" ) )
1207  {
1208  // e.g. "Po 19120 39260 900 0 4E823D06 46EAAFA5 ~~\r\n"
1209 
1210  // 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 );
1211 
1212  BIU pos_x = biuParse( line + SZ( "Po" ), &data );
1213  BIU pos_y = biuParse( data, &data );
1214  int orient = intParse( data, &data );
1215 
1216  LAYER_NUM layer_num = layerParse( data, &data );
1217  PCB_LAYER_ID layer_id = leg_layer2new( m_cu_count, layer_num );
1218 
1219  long edittime = hexParse( data, &data );
1220  timestamp_t timestamp = hexParse( data, &data );
1221 
1222  data = strtok_r( (char*) data+1, delims, &saveptr );
1223 
1224  // data is now a two character long string
1225  // Note: some old files do not have this field
1226  if( data && data[0] == 'F' )
1227  aModule->SetLocked( true );
1228 
1229  if( data && data[1] == 'P' )
1230  aModule->SetIsPlaced( true );
1231 
1232  aModule->SetPosition( wxPoint( pos_x, pos_y ) );
1233  aModule->SetLayer( layer_id );
1234  aModule->SetOrientation( orient );
1235  aModule->SetTimeStamp( timestamp );
1236  aModule->SetLastEditTime( edittime );
1237  }
1238 
1239  /* footprint name set earlier, immediately after MODULE construction
1240  else if( TESTLINE( "Li" ) ) // Library name of footprint
1241  {
1242  // There can be whitespace in the footprint name on some old libraries.
1243  // Grab everything after "Li" up to end of line:
1244  //aModule->SetFPID( FROM_UTF8( StrPurge( line + SZ( "Li" ) ) ) );
1245  }
1246  */
1247 
1248  else if( TESTLINE( "Sc" ) ) // timestamp
1249  {
1250  timestamp_t timestamp = hexParse( line + SZ( "Sc" ) );
1251  aModule->SetTimeStamp( timestamp );
1252  }
1253 
1254  else if( TESTLINE( "Op" ) ) // (Op)tions for auto placement
1255  {
1256  int itmp1 = hexParse( line + SZ( "Op" ), &data );
1257  int itmp2 = hexParse( data );
1258 
1259  int cntRot180 = itmp2 & 0x0F;
1260  if( cntRot180 > 10 )
1261  cntRot180 = 10;
1262 
1263  aModule->SetPlacementCost180( cntRot180 );
1264 
1265  int cntRot90 = itmp1 & 0x0F;
1266  if( cntRot90 > 10 )
1267  cntRot90 = 0;
1268 
1269  itmp1 = (itmp1 >> 4) & 0x0F;
1270  if( itmp1 > 10 )
1271  itmp1 = 0;
1272 
1273  aModule->SetPlacementCost90( (itmp1 << 4) | cntRot90 );
1274  }
1275 
1276  else if( TESTLINE( "At" ) ) // (At)tributes of module
1277  {
1278  int attrs = MOD_DEFAULT;
1279 
1280  data = line + SZ( "At" );
1281 
1282  if( strstr( data, "SMD" ) )
1283  attrs |= MOD_CMS;
1284 
1285  if( strstr( data, "VIRTUAL" ) )
1286  attrs |= MOD_VIRTUAL;
1287 
1288  aModule->SetAttributes( attrs );
1289  }
1290 
1291  else if( TESTLINE( "AR" ) ) // Alternate Reference
1292  {
1293  // e.g. "AR /47BA2624/45525076"
1294  data = strtok_r( line + SZ( "AR" ), delims, &saveptr );
1295  if( data )
1296  aModule->SetPath( FROM_UTF8( data ) );
1297  }
1298 
1299  else if( TESTLINE( "$SHAPE3D" ) )
1300  {
1301  load3D( aModule );
1302  }
1303 
1304  else if( TESTLINE( "Cd" ) )
1305  {
1306  // e.g. "Cd Double rangee de contacts 2 x 4 pins\r\n"
1307  aModule->SetDescription( FROM_UTF8( StrPurge( line + SZ( "Cd" ) ) ) );
1308  }
1309 
1310  else if( TESTLINE( "Kw" ) ) // Key words
1311  {
1312  aModule->SetKeywords( FROM_UTF8( StrPurge( line + SZ( "Kw" ) ) ) );
1313  }
1314 
1315  else if( TESTLINE( ".SolderPasteRatio" ) )
1316  {
1317  double tmp = atof( line + SZ( ".SolderPasteRatio" ) );
1318  // Due to a bug in dialog editor in Modedit, fixed in BZR version 3565
1319  // this parameter can be broken.
1320  // It should be >= -50% (no solder paste) and <= 0% (full area of the pad)
1321 
1322  if( tmp < -0.50 )
1323  tmp = -0.50;
1324  if( tmp > 0.0 )
1325  tmp = 0.0;
1326  aModule->SetLocalSolderPasteMarginRatio( tmp );
1327  }
1328 
1329  else if( TESTLINE( ".SolderPaste" ) )
1330  {
1331  BIU tmp = biuParse( line + SZ( ".SolderPaste" ) );
1332  aModule->SetLocalSolderPasteMargin( tmp );
1333  }
1334 
1335  else if( TESTLINE( ".SolderMask" ) )
1336  {
1337  BIU tmp = biuParse( line + SZ( ".SolderMask" ) );
1338  aModule->SetLocalSolderMaskMargin( tmp );
1339  }
1340 
1341  else if( TESTLINE( ".LocalClearance" ) )
1342  {
1343  BIU tmp = biuParse( line + SZ( ".LocalClearance" ) );
1344  aModule->SetLocalClearance( tmp );
1345  }
1346 
1347  else if( TESTLINE( ".ZoneConnection" ) )
1348  {
1349  int tmp = intParse( line + SZ( ".ZoneConnection" ) );
1350  aModule->SetZoneConnection( (ZoneConnection)tmp );
1351  }
1352 
1353  else if( TESTLINE( ".ThermalWidth" ) )
1354  {
1355  BIU tmp = biuParse( line + SZ( ".ThermalWidth" ) );
1356  aModule->SetThermalWidth( tmp );
1357  }
1358 
1359  else if( TESTLINE( ".ThermalGap" ) )
1360  {
1361  BIU tmp = biuParse( line + SZ( ".ThermalGap" ) );
1362  aModule->SetThermalGap( tmp );
1363  }
1364 
1365  else if( TESTLINE( "$EndMODULE" ) )
1366  {
1367  aModule->CalculateBoundingBox();
1368 
1369  return; // preferred exit
1370  }
1371  }
1372 
1373  wxString msg = wxString::Format(
1374  _( "Missing '$EndMODULE' for MODULE \"%s\"" ),
1375  GetChars( aModule->GetFPID().GetLibItemName() ) );
1376 
1377  THROW_IO_ERROR( msg );
1378 }
1379 
1380 
1382 {
1383  unique_ptr<D_PAD> pad( new D_PAD( aModule ) );
1384  char* line;
1385  char* saveptr;
1386 
1387  while( ( line = READLINE( m_reader ) ) != NULL )
1388  {
1389  const char* data;
1390 
1391  if( TESTLINE( "Sh" ) ) // (Sh)ape and padname
1392  {
1393  // e.g. "Sh "A2" C 520 520 0 0 900"
1394  // or "Sh "1" R 157 1378 0 0 900"
1395 
1396  // mypadname is LATIN1/CRYLIC for BOARD_FORMAT_VERSION 1,
1397  // but for BOARD_FORMAT_VERSION 2, it is UTF8 from disk.
1398  // So we have to go through two code paths. Moving forward
1399  // padnames will be in UTF8 on disk, as are all KiCad strings on disk.
1400  char mypadname[50];
1401 
1402  data = line + SZ( "Sh" ) + 1; // +1 skips trailing whitespace
1403 
1404  data = data + ReadDelimitedText( mypadname, data, sizeof(mypadname) ) + 1; // +1 trailing whitespace
1405 
1406  // sscanf( PtLine, " %s %d %d %d %d %d", BufCar, &m_Size.x, &m_Size.y, &m_DeltaSize.x, &m_DeltaSize.y, &m_Orient );
1407  while( isSpace( *data ) )
1408  ++data;
1409 
1410  unsigned char padchar = (unsigned char) *data++;
1411  int padshape;
1412 
1413  BIU size_x = biuParse( data, &data );
1414  BIU size_y = biuParse( data, &data );
1415  BIU delta_x = biuParse( data, &data );
1416  BIU delta_y = biuParse( data, &data );
1417  double orient = degParse( data );
1418 
1419  switch( padchar )
1420  {
1421  case 'C': padshape = PAD_SHAPE_CIRCLE; break;
1422  case 'R': padshape = PAD_SHAPE_RECT; break;
1423  case 'O': padshape = PAD_SHAPE_OVAL; break;
1424  case 'T': padshape = PAD_SHAPE_TRAPEZOID; break;
1425  default:
1426  m_error.Printf( _( "Unknown padshape '%c=0x%02x' on line: %d of footprint: \"%s\"" ),
1427  padchar,
1428  padchar,
1429  m_reader->LineNumber(),
1430  GetChars( aModule->GetFPID().GetLibItemName() )
1431  );
1433  }
1434 
1435  // go through a wxString to establish a universal character set properly
1436  wxString padname;
1437 
1438  if( m_loading_format_version == 1 )
1439  {
1440  // add 8 bit bytes, file format 1 was KiCad font type byte,
1441  // simply promote those 8 bit bytes up into UNICODE. (subset of LATIN1)
1442  const unsigned char* cp = (unsigned char*) mypadname;
1443  while( *cp )
1444  {
1445  padname += *cp++; // unsigned, ls 8 bits only
1446  }
1447  }
1448  else
1449  {
1450  // version 2, which is UTF8.
1451  padname = FROM_UTF8( mypadname );
1452  }
1453  // chances are both were ASCII, but why take chances?
1454 
1455  pad->SetName( padname );
1456  pad->SetShape( PAD_SHAPE_T( padshape ) );
1457  pad->SetSize( wxSize( size_x, size_y ) );
1458  pad->SetDelta( wxSize( delta_x, delta_y ) );
1459  pad->SetOrientation( orient );
1460  }
1461 
1462  else if( TESTLINE( "Dr" ) ) // (Dr)ill
1463  {
1464  // e.g. "Dr 350 0 0" or "Dr 0 0 0 O 0 0"
1465  // sscanf( PtLine, "%d %d %d %s %d %d", &m_Drill.x, &m_Offset.x, &m_Offset.y, BufCar, &dx, &dy );
1466 
1467  BIU drill_x = biuParse( line + SZ( "Dr" ), &data );
1468  BIU drill_y = drill_x;
1469  BIU offs_x = biuParse( data, &data );
1470  BIU offs_y = biuParse( data, &data );
1471 
1473 
1474  data = strtok_r( (char*) data, delims, &saveptr );
1475  if( data ) // optional shape
1476  {
1477  if( data[0] == 'O' )
1478  {
1479  drShape = PAD_DRILL_SHAPE_OBLONG;
1480 
1481  data = strtok_r( NULL, delims, &saveptr );
1482  drill_x = biuParse( data );
1483 
1484  data = strtok_r( NULL, delims, &saveptr );
1485  drill_y = biuParse( data );
1486  }
1487  }
1488 
1489  pad->SetDrillShape( drShape );
1490  pad->SetOffset( wxPoint( offs_x, offs_y ) );
1491  pad->SetDrillSize( wxSize( drill_x, drill_y ) );
1492  }
1493 
1494  else if( TESTLINE( "At" ) ) // (At)tribute
1495  {
1496  // e.g. "At SMD N 00888000"
1497  // sscanf( PtLine, "%s %s %X", BufLine, BufCar, &m_layerMask );
1498 
1499  PAD_ATTR_T attribute;
1500 
1501  data = strtok_r( line + SZ( "At" ), delims, &saveptr );
1502 
1503  if( !strcmp( data, "SMD" ) )
1504  attribute = PAD_ATTRIB_SMD;
1505  else if( !strcmp( data, "CONN" ) )
1506  attribute = PAD_ATTRIB_CONN;
1507  else if( !strcmp( data, "HOLE" ) )
1508  attribute = PAD_ATTRIB_HOLE_NOT_PLATED;
1509  else
1510  attribute = PAD_ATTRIB_STANDARD;
1511 
1512  strtok_r( NULL, delims, &saveptr ); // skip BufCar
1513  data = strtok_r( NULL, delims, &saveptr );
1514 
1515  LEG_MASK layer_mask = hexParse( data );
1516 
1517  pad->SetLayerSet( leg_mask2new( m_cu_count, layer_mask ) );
1518  pad->SetAttribute( attribute );
1519  }
1520 
1521  else if( TESTLINE( "Ne" ) ) // (Ne)tname
1522  {
1523  // e.g. "Ne 461 "V5.0"
1524 
1525  char buf[1024]; // can be fairly long
1526  int netcode = intParse( line + SZ( "Ne" ), &data );
1527 
1528  // Store the new code mapping
1529  pad->SetNetCode( getNetCode( netcode ) );
1530 
1531  // read Netname
1532  ReadDelimitedText( buf, data, sizeof(buf) );
1533 #ifndef NDEBUG
1534  if( m_board )
1535  assert( m_board->FindNet( getNetCode( netcode ) )->GetNetname() ==
1536  FROM_UTF8( StrPurge( buf ) ) );
1537 #endif /* NDEBUG */
1538  }
1539 
1540  else if( TESTLINE( "Po" ) ) // (Po)sition
1541  {
1542  // e.g. "Po 500 -500"
1543  wxPoint pos;
1544 
1545  pos.x = biuParse( line + SZ( "Po" ), &data );
1546  pos.y = biuParse( data );
1547 
1548  pad->SetPos0( pos );
1549  // pad->SetPosition( pos ); set at function return
1550  }
1551 
1552  else if( TESTLINE( "Le" ) )
1553  {
1554  BIU tmp = biuParse( line + SZ( "Le" ) );
1555  pad->SetPadToDieLength( tmp );
1556  }
1557 
1558  else if( TESTLINE( ".SolderMask" ) )
1559  {
1560  BIU tmp = biuParse( line + SZ( ".SolderMask" ) );
1561  pad->SetLocalSolderMaskMargin( tmp );
1562  }
1563 
1564  else if( TESTLINE( ".SolderPasteRatio" ) )
1565  {
1566  double tmp = atof( line + SZ( ".SolderPasteRatio" ) );
1567  pad->SetLocalSolderPasteMarginRatio( tmp );
1568  }
1569 
1570  else if( TESTLINE( ".SolderPaste" ) )
1571  {
1572  BIU tmp = biuParse( line + SZ( ".SolderPaste" ) );
1573  pad->SetLocalSolderPasteMargin( tmp );
1574  }
1575 
1576  else if( TESTLINE( ".LocalClearance" ) )
1577  {
1578  BIU tmp = biuParse( line + SZ( ".LocalClearance" ) );
1579  pad->SetLocalClearance( tmp );
1580  }
1581 
1582  else if( TESTLINE( ".ZoneConnection" ) )
1583  {
1584  int tmp = intParse( line + SZ( ".ZoneConnection" ) );
1585  pad->SetZoneConnection( (ZoneConnection)tmp );
1586  }
1587 
1588  else if( TESTLINE( ".ThermalWidth" ) )
1589  {
1590  BIU tmp = biuParse( line + SZ( ".ThermalWidth" ) );
1591  pad->SetThermalWidth( tmp );
1592  }
1593 
1594  else if( TESTLINE( ".ThermalGap" ) )
1595  {
1596  BIU tmp = biuParse( line + SZ( ".ThermalGap" ) );
1597  pad->SetThermalGap( tmp );
1598  }
1599 
1600  else if( TESTLINE( "$EndPAD" ) )
1601  {
1602  // pad's "Position" is not relative to the module's,
1603  // whereas Pos0 is relative to the module's but is the unrotated coordinate.
1604 
1605  wxPoint padpos = pad->GetPos0();
1606 
1607  RotatePoint( &padpos, aModule->GetOrientation() );
1608 
1609  pad->SetPosition( padpos + aModule->GetPosition() );
1610 
1611  aModule->PadsList().PushBack( pad.release() );
1612  return; // preferred exit
1613  }
1614  }
1615 
1616  THROW_IO_ERROR( "Missing '$EndPAD'" );
1617 }
1618 
1619 
1621 {
1622  STROKE_T shape;
1623  char* line = m_reader->Line(); // obtain current (old) line
1624 
1625  switch( line[1] )
1626  {
1627  case 'S': shape = S_SEGMENT; break;
1628  case 'C': shape = S_CIRCLE; break;
1629  case 'A': shape = S_ARC; break;
1630  case 'P': shape = S_POLYGON; break;
1631  default:
1632  m_error.Printf( _( "Unknown EDGE_MODULE type:'%c=0x%02x' on line:%d of footprint:\"%s\"" ),
1633  (unsigned char) line[1],
1634  (unsigned char) line[1],
1635  m_reader->LineNumber(),
1636  GetChars( aModule->GetFPID().GetLibItemName() )
1637  );
1639  }
1640 
1641  unique_ptr<EDGE_MODULE> dwg( new EDGE_MODULE( aModule, shape ) ); // a drawing
1642 
1643  const char* data;
1644 
1645  // common to all cases, and we have to check their values uniformly at end
1646  BIU width = 1;
1648 
1649  switch( shape )
1650  {
1651  case S_ARC:
1652  {
1653  // 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 );
1654  BIU start0_x = biuParse( line + SZ( "DA" ), &data );
1655  BIU start0_y = biuParse( data, &data );
1656  BIU end0_x = biuParse( data, &data );
1657  BIU end0_y = biuParse( data, &data );
1658  double angle = degParse( data, &data );
1659 
1660  width = biuParse( data, &data );
1661  layer = layerParse( data );
1662 
1663  dwg->SetAngle( angle );
1664  dwg->m_Start0 = wxPoint( start0_x, start0_y );
1665  dwg->m_End0 = wxPoint( end0_x, end0_y );
1666  }
1667  break;
1668 
1669  case S_SEGMENT:
1670  case S_CIRCLE:
1671  {
1672  // e.g. "DS -7874 -10630 7874 -10630 50 20\r\n"
1673  // 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 );
1674 
1675  BIU start0_x = biuParse( line + SZ( "DS" ), &data );
1676  BIU start0_y = biuParse( data, &data );
1677  BIU end0_x = biuParse( data, &data );
1678  BIU end0_y = biuParse( data, &data );
1679 
1680  width = biuParse( data, &data );
1681  layer = layerParse( data );
1682 
1683  dwg->m_Start0 = wxPoint( start0_x, start0_y );
1684  dwg->m_End0 = wxPoint( end0_x, end0_y );
1685  }
1686  break;
1687 
1688  case S_POLYGON:
1689  {
1690  // e.g. "DP %d %d %d %d %d %d %d\n"
1691  // 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 );
1692 
1693  BIU start0_x = biuParse( line + SZ( "DP" ), &data );
1694  BIU start0_y = biuParse( data, &data );
1695  BIU end0_x = biuParse( data, &data );
1696  BIU end0_y = biuParse( data, &data );
1697  int ptCount = intParse( data, &data );
1698 
1699  width = biuParse( data, &data );
1700  layer = layerParse( data );
1701 
1702  dwg->m_Start0 = wxPoint( start0_x, start0_y );
1703  dwg->m_End0 = wxPoint( end0_x, end0_y );
1704 
1705  std::vector<wxPoint> pts;
1706  pts.reserve( ptCount );
1707 
1708  for( int ii = 0; ii<ptCount; ++ii )
1709  {
1710  if( ( line = READLINE( m_reader ) ) == NULL )
1711  {
1712  THROW_IO_ERROR( "S_POLGON point count mismatch." );
1713  }
1714 
1715  // e.g. "Dl 23 44\n"
1716 
1717  if( !TESTLINE( "Dl" ) )
1718  {
1719  THROW_IO_ERROR( "Missing Dl point def" );
1720  }
1721 
1722  BIU x = biuParse( line + SZ( "Dl" ), &data );
1723  BIU y = biuParse( data );
1724 
1725  pts.push_back( wxPoint( x, y ) );
1726  }
1727 
1728  dwg->SetPolyPoints( pts );
1729  }
1730  break;
1731 
1732  default:
1733  // first switch code above prevents us from getting here.
1734  break;
1735  }
1736 
1737  // Check for a reasonable width:
1738 
1739  /* @todo no MAX_WIDTH in out of reach header.
1740  if( width <= 1 )
1741  width = 1;
1742  else if( width > MAX_WIDTH )
1743  width = MAX_WIDTH;
1744  */
1745 
1746  // Check for a reasonable layer:
1747  // m_Layer must be >= FIRST_NON_COPPER_LAYER, but because microwave footprints
1748  // can use the copper layers m_Layer < FIRST_NON_COPPER_LAYER is allowed.
1749  // @todo: changes use of EDGE_MODULE these footprints and allows only
1750  // m_Layer >= FIRST_NON_COPPER_LAYER
1751  if( layer < FIRST_LAYER || layer > LAST_NON_COPPER_LAYER )
1752  layer = SILKSCREEN_N_FRONT;
1753 
1754  dwg->SetWidth( width );
1755  dwg->SetLayer( leg_layer2new( m_cu_count, layer ) );
1756 
1757  EDGE_MODULE* em = dwg.release();
1758 
1759  aModule->GraphicalItemsList().PushBack( em );
1760 
1761  // this had been done at the MODULE level before, presumably because the
1762  // EDGE_MODULE needs to be already added to a module before this function will work.
1763  em->SetDrawCoord();
1764 }
1765 
1766 
1768 {
1769  const char* data;
1770  const char* txt_end;
1771  const char* line = m_reader->Line(); // current (old) line
1772  char* saveptr;
1773 
1774  // sscanf( line + 1, "%d %d %d %d %d %d %d %s %s %d %s",
1775  // &type, &m_Pos0.x, &m_Pos0.y, &m_Size.y, &m_Size.x,
1776  // &m_Orient, &m_Thickness, BufCar1, BufCar2, &layer, BufCar3 ) >= 10 )
1777 
1778  // e.g. "T1 6940 -16220 350 300 900 60 M I 20 N "CFCARD"\r\n"
1779  // or T1 0 500 600 400 900 80 M V 20 N"74LS245"
1780  // ouch, the last example has no space between N and "74LS245" !
1781  // that is an older version.
1782 
1783  int type = intParse( line+1, &data );
1784  BIU pos0_x = biuParse( data, &data );
1785  BIU pos0_y = biuParse( data, &data );
1786  BIU size0_y = biuParse( data, &data );
1787  BIU size0_x = biuParse( data, &data );
1788  double orient = degParse( data, &data );
1789  BIU thickn = biuParse( data, &data );
1790 
1791  // read the quoted text before the first call to strtok() which introduces
1792  // NULs into the string and chops it into mutliple C strings, something
1793  // ReadDelimitedText() cannot traverse.
1794 
1795  // convert the "quoted, escaped, UTF8, text" to a wxString, find it by skipping
1796  // as far forward as needed until the first double quote.
1797  txt_end = data + ReadDelimitedText( &m_field, data );
1798 
1799  aText->SetText( m_field );
1800 
1801  // after switching to strtok, there's no easy coming back because of the
1802  // embedded nul(s?) placed to the right of the current field.
1803  // (that's the reason why strtok was deprecated...)
1804  char* mirror = strtok_r( (char*) data, delims, &saveptr );
1805  char* hide = strtok_r( NULL, delims, &saveptr );
1806  char* tmp = strtok_r( NULL, delims, &saveptr );
1807 
1808  LAYER_NUM layer_num = tmp ? layerParse( tmp ) : SILKSCREEN_N_FRONT;
1809 
1810  char* italic = strtok_r( NULL, delims, &saveptr );
1811 
1812  char* hjust = strtok_r( (char*) txt_end, delims, &saveptr );
1813  char* vjust = strtok_r( NULL, delims, &saveptr );
1814 
1816  && type != TEXTE_MODULE::TEXT_is_VALUE )
1818 
1819  aText->SetType( static_cast<TEXTE_MODULE::TEXT_TYPE>( type ) );
1820 
1821  aText->SetPos0( wxPoint( pos0_x, pos0_y ) );
1822  aText->SetTextSize( wxSize( size0_x, size0_y ) );
1823 
1824  orient -= ( static_cast<MODULE*>( aText->GetParent() ) )->GetOrientation();
1825 
1826  aText->SetTextAngle( orient );
1827 
1828  // @todo put in accessors?
1829  // Set a reasonable width:
1830  if( thickn < 1 )
1831  thickn = 1;
1832 
1833  /* this is better left to the dialogs UIs
1834  aText->SetThickness( Clamp_Text_PenSize( thickn, aText->GetSize() ) );
1835  */
1836 
1837  aText->SetThickness( thickn );
1838 
1839  aText->SetMirrored( mirror && *mirror == 'M' );
1840 
1841  aText->SetVisible( !(hide && *hide == 'I') );
1842 
1843  aText->SetItalic( italic && *italic == 'I' );
1844 
1845  if( hjust )
1846  aText->SetHorizJustify( horizJustify( hjust ) );
1847 
1848  if( vjust )
1849  aText->SetVertJustify( vertJustify( vjust ) );
1850 
1851  if( layer_num < FIRST_LAYER )
1852  layer_num = FIRST_LAYER;
1853  else if( layer_num > LAST_NON_COPPER_LAYER )
1854  layer_num = LAST_NON_COPPER_LAYER;
1855  else if( layer_num == LAYER_N_BACK )
1856  layer_num = SILKSCREEN_N_BACK;
1857  else if( layer_num == LAYER_N_FRONT )
1858  layer_num = SILKSCREEN_N_FRONT;
1859 
1860  aText->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
1861 
1862  // Calculate the actual position.
1863  aText->SetDrawCoord();
1864 }
1865 
1866 
1868 {
1869  MODULE_3D_SETTINGS t3D;
1870 
1871  char* line;
1872  while( ( line = READLINE( m_reader ) ) != NULL )
1873  {
1874  if( TESTLINE( "Na" ) ) // Shape File Name
1875  {
1876  char buf[512];
1877  ReadDelimitedText( buf, line + SZ( "Na" ), sizeof(buf) );
1878  t3D.m_Filename = buf;
1879  }
1880 
1881  else if( TESTLINE( "Sc" ) ) // Scale
1882  {
1883  sscanf( line + SZ( "Sc" ), "%lf %lf %lf\n",
1884  &t3D.m_Scale.x,
1885  &t3D.m_Scale.y,
1886  &t3D.m_Scale.z );
1887  }
1888 
1889  else if( TESTLINE( "Of" ) ) // Offset
1890  {
1891  sscanf( line + SZ( "Of" ), "%lf %lf %lf\n",
1892  &t3D.m_Offset.x,
1893  &t3D.m_Offset.y,
1894  &t3D.m_Offset.z );
1895  }
1896 
1897  else if( TESTLINE( "Ro" ) ) // Rotation
1898  {
1899  sscanf( line + SZ( "Ro" ), "%lf %lf %lf\n",
1900  &t3D.m_Rotation.x,
1901  &t3D.m_Rotation.y,
1902  &t3D.m_Rotation.z );
1903  }
1904 
1905  else if( TESTLINE( "$EndSHAPE3D" ) )
1906  {
1907  aModule->Models().push_back( t3D );
1908  return; // preferred exit
1909  }
1910  }
1911 
1912  THROW_IO_ERROR( "Missing '$EndSHAPE3D'" );
1913 }
1914 
1915 
1917 {
1918  /* example:
1919  $DRAWSEGMENT
1920  Po 0 57500 -1000 57500 0 150
1921  De 24 0 900 0 0
1922  $EndDRAWSEGMENT
1923  */
1924 
1925  unique_ptr<DRAWSEGMENT> dseg( new DRAWSEGMENT( m_board ) );
1926 
1927  char* line;
1928  char* saveptr;
1929 
1930  while( ( line = READLINE( m_reader ) ) != NULL )
1931  {
1932  const char* data;
1933 
1934  if( TESTLINE( "Po" ) )
1935  {
1936  // 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 );
1937  int shape = intParse( line + SZ( "Po" ), &data );
1938  BIU start_x = biuParse( data, &data );
1939  BIU start_y = biuParse( data, &data );
1940  BIU end_x = biuParse( data, &data );
1941  BIU end_y = biuParse( data, &data );
1942  BIU width = biuParse( data );
1943 
1944  if( width < 0 )
1945  width = 0;
1946 
1947  dseg->SetShape( STROKE_T( shape ) );
1948  dseg->SetWidth( width );
1949  dseg->SetStart( wxPoint( start_x, start_y ) );
1950  dseg->SetEnd( wxPoint( end_x, end_y ) );
1951  }
1952 
1953  else if( TESTLINE( "De" ) )
1954  {
1955  BIU x = 0;
1956  BIU y;
1957 
1958  data = strtok_r( line + SZ( "De" ), delims, &saveptr );
1959  for( int i = 0; data; ++i, data = strtok_r( NULL, delims, &saveptr ) )
1960  {
1961  switch( i )
1962  {
1963  case 0:
1964  LAYER_NUM layer;
1965  layer = layerParse( data );
1966 
1967  if( layer < FIRST_NON_COPPER_LAYER )
1968  layer = FIRST_NON_COPPER_LAYER;
1969 
1970  else if( layer > LAST_NON_COPPER_LAYER )
1971  layer = LAST_NON_COPPER_LAYER;
1972 
1973  dseg->SetLayer( leg_layer2new( m_cu_count, layer ) );
1974  break;
1975  case 1:
1976  int mtype;
1977  mtype = intParse( data );
1978  dseg->SetType( mtype ); // m_Type
1979  break;
1980  case 2:
1981  double angle;
1982  angle = degParse( data );
1983  dseg->SetAngle( angle ); // m_Angle
1984  break;
1985  case 3:
1986  timestamp_t timestamp;
1987  timestamp = hexParse( data );
1988  dseg->SetTimeStamp( timestamp );
1989  break;
1990  case 4:
1991  STATUS_FLAGS state;
1992  state = static_cast<STATUS_FLAGS>( hexParse( data ) );
1993  dseg->SetState( state, true );
1994  break;
1995 
1996  // Bezier Control Points
1997  case 5:
1998  x = biuParse( data );
1999  break;
2000  case 6:
2001  y = biuParse( data );
2002  dseg->SetBezControl1( wxPoint( x, y ) );
2003  break;
2004 
2005  case 7:
2006  x = biuParse( data );
2007  break;
2008  case 8:
2009  y = biuParse( data );
2010  dseg->SetBezControl2( wxPoint( x, y ) );
2011  break;
2012 
2013  default:
2014  break;
2015  }
2016  }
2017  }
2018 
2019  else if( TESTLINE( "$EndDRAWSEGMENT" ) )
2020  {
2021  m_board->Add( dseg.release(), ADD_APPEND );
2022  return; // preferred exit
2023  }
2024  }
2025 
2026  THROW_IO_ERROR( "Missing '$EndDRAWSEGMENT'" );
2027 }
2028 
2030 {
2031  /* a net description is something like
2032  * $EQUIPOT
2033  * Na 5 "/BIT1"
2034  * St ~
2035  * $EndEQUIPOT
2036  */
2037 
2038  char buf[1024];
2039 
2040  NETINFO_ITEM* net = NULL;
2041  char* line;
2042  int netCode = 0;
2043 
2044  while( ( line = READLINE( m_reader ) ) != NULL )
2045  {
2046  const char* data;
2047 
2048  if( TESTLINE( "Na" ) )
2049  {
2050  // e.g. "Na 58 "/cpu.sch/PAD7"\r\n"
2051 
2052  netCode = intParse( line + SZ( "Na" ), &data );
2053 
2054  ReadDelimitedText( buf, data, sizeof(buf) );
2055 
2056  if( net == NULL )
2057  net = new NETINFO_ITEM( m_board, FROM_UTF8( buf ), netCode );
2058  else
2059  {
2060  THROW_IO_ERROR( "Two net definitions in '$EQUIPOT' block" );
2061  }
2062  }
2063 
2064  else if( TESTLINE( "$EndEQUIPOT" ) )
2065  {
2066  // net 0 should be already in list, so store this net
2067  // if it is not the net 0, or if the net 0 does not exists.
2068  if( net && ( net->GetNet() > 0 || m_board->FindNet( 0 ) == NULL ) )
2069  {
2070  m_board->Add( net );
2071 
2072  // Be sure we have room to store the net in m_netCodes
2073  if( (int)m_netCodes.size() <= netCode )
2074  m_netCodes.resize( netCode+1 );
2075 
2076  m_netCodes[netCode] = net->GetNet();
2077  net = NULL;
2078  }
2079  else
2080  {
2081  delete net;
2082  net = NULL; // Avoid double deletion.
2083  }
2084 
2085  return; // preferred exit
2086  }
2087  }
2088 
2089  // If we are here, there is an error.
2090  delete net;
2091  THROW_IO_ERROR( "Missing '$EndEQUIPOT'" );
2092 }
2093 
2094 
2096 {
2097  /* examples:
2098  For a single line text:
2099  ----------------------
2100  $TEXTPCB
2101  Te "Text example"
2102  Po 66750 53450 600 800 150 0
2103  De 24 1 0 Italic
2104  $EndTEXTPCB
2105 
2106  For a multi line text:
2107  ---------------------
2108  $TEXTPCB
2109  Te "Text example"
2110  Nl "Line 2"
2111  Po 66750 53450 600 800 150 0
2112  De 24 1 0 Italic
2113  $EndTEXTPCB
2114  Nl "line nn" is a line added to the current text
2115  */
2116 
2117  char text[1024];
2118 
2119  // maybe someday a constructor that takes all this data in one call?
2120  TEXTE_PCB* pcbtxt = new TEXTE_PCB( m_board );
2121  m_board->Add( pcbtxt, ADD_APPEND );
2122 
2123  char* line;
2124  char* saveptr;
2125 
2126  while( ( line = READLINE( m_reader ) ) != NULL )
2127  {
2128  const char* data;
2129 
2130  if( TESTLINE( "Te" ) ) // Text line (or first line for multi line texts)
2131  {
2132  ReadDelimitedText( text, line + SZ( "Te" ), sizeof(text) );
2133  pcbtxt->SetText( FROM_UTF8( text ) );
2134  }
2135 
2136  else if( TESTLINE( "nl" ) ) // next line of the current text
2137  {
2138  ReadDelimitedText( text, line + SZ( "nl" ), sizeof(text) );
2139  pcbtxt->SetText( pcbtxt->GetText() + wxChar( '\n' ) + FROM_UTF8( text ) );
2140  }
2141 
2142  else if( TESTLINE( "Po" ) )
2143  {
2144  // 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 );
2145  wxSize size;
2146 
2147  BIU pos_x = biuParse( line + SZ( "Po" ), &data );
2148  BIU pos_y = biuParse( data, &data );
2149  size.x = biuParse( data, &data );
2150  size.y = biuParse( data, &data );
2151  BIU thickn = biuParse( data, &data );
2152  double angle = degParse( data );
2153 
2154  // Ensure the text has minimal size to see this text on screen:
2155 
2156  /* @todo wait until we are firmly in the nanometer world
2157  if( sz.x < 5 )
2158  sz.x = 5;
2159 
2160  if( sz.y < 5 )
2161  sz.y = 5;
2162  */
2163 
2164  pcbtxt->SetTextSize( size );
2165 
2166  /* @todo move into an accessor
2167  // Set a reasonable width:
2168  if( thickn < 1 )
2169  thickn = 1;
2170 
2171  thickn = Clamp_Text_PenSize( thickn, size );
2172  */
2173 
2174  pcbtxt->SetThickness( thickn );
2175  pcbtxt->SetTextAngle( angle );
2176 
2177  pcbtxt->SetTextPos( wxPoint( pos_x, pos_y ) );
2178  }
2179 
2180  else if( TESTLINE( "De" ) )
2181  {
2182  // e.g. "De 21 1 0 Normal C\r\n"
2183  // sscanf( line + 2, " %d %d %lX %s %c\n", &m_Layer, &normal_display, &m_TimeStamp, style, &hJustify );
2184 
2185  LAYER_NUM layer_num = layerParse( line + SZ( "De" ), &data );
2186  int notMirrored = intParse( data, &data );
2187  timestamp_t timestamp = hexParse( data, &data );
2188  char* style = strtok_r( (char*) data, delims, &saveptr );
2189  char* hJustify = strtok_r( NULL, delims, &saveptr );
2190  char* vJustify = strtok_r( NULL, delims, &saveptr );
2191 
2192  pcbtxt->SetMirrored( !notMirrored );
2193  pcbtxt->SetTimeStamp( timestamp );
2194  pcbtxt->SetItalic( !strcmp( style, "Italic" ) );
2195 
2196  if( hJustify )
2197  pcbtxt->SetHorizJustify( horizJustify( hJustify ) );
2198  else
2199  {
2200  // boom, somebody changed a constructor, I was relying on this:
2201  wxASSERT( pcbtxt->GetHorizJustify() == GR_TEXT_HJUSTIFY_CENTER );
2202  }
2203 
2204  if( vJustify )
2205  pcbtxt->SetVertJustify( vertJustify( vJustify ) );
2206 
2207  if( layer_num < FIRST_COPPER_LAYER )
2208  layer_num = FIRST_COPPER_LAYER;
2209  else if( layer_num > LAST_NON_COPPER_LAYER )
2210  layer_num = LAST_NON_COPPER_LAYER;
2211 
2212  if( layer_num >= FIRST_NON_COPPER_LAYER ||
2213  is_leg_copperlayer_valid( m_cu_count, layer_num ) )
2214  pcbtxt->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2215  else // not perfect, but putting this text on front layer is a workaround
2216  pcbtxt->SetLayer( F_Cu );
2217  }
2218 
2219  else if( TESTLINE( "$EndTEXTPCB" ) )
2220  {
2221  return; // preferred exit
2222  }
2223  }
2224 
2225  THROW_IO_ERROR( "Missing '$EndTEXTPCB'" );
2226 }
2227 
2228 
2229 void LEGACY_PLUGIN::loadTrackList( int aStructType )
2230 {
2231  char* line;
2232  char* saveptr;
2233 
2234  while( ( line = READLINE( m_reader ) ) != NULL )
2235  {
2236  // read two lines per loop iteration, each loop is one TRACK or VIA
2237  // example first line:
2238  // e.g. "Po 0 23994 28800 24400 28800 150 -1" for a track
2239  // e.g. "Po 3 21086 17586 21086 17586 180 -1" for a via (uses sames start and end)
2240 
2241  const char* data;
2242 
2243  if( line[0] == '$' ) // $EndTRACK
2244  return; // preferred exit
2245 
2246  // int arg_count = sscanf( line + 2, " %d %d %d %d %d %d %d", &shape, &tempStartX, &tempStartY, &tempEndX, &tempEndY, &width, &drill );
2247 
2248  assert( TESTLINE( "Po" ) );
2249 
2250  VIATYPE_T viatype = static_cast<VIATYPE_T>( intParse( line + SZ( "Po" ), &data ));
2251  BIU start_x = biuParse( data, &data );
2252  BIU start_y = biuParse( data, &data );
2253  BIU end_x = biuParse( data, &data );
2254  BIU end_y = biuParse( data, &data );
2255  BIU width = biuParse( data, &data );
2256 
2257  // optional 7th drill parameter (must be optional in an old format?)
2258  data = strtok_r( (char*) data, delims, &saveptr );
2259 
2260  BIU drill = data ? biuParse( data ) : -1; // SetDefault() if < 0
2261 
2262  // Read the 2nd line to determine the exact type, one of:
2263  // PCB_TRACE_T, PCB_VIA_T, or PCB_ZONE_T. The type field in 2nd line
2264  // differentiates between PCB_TRACE_T and PCB_VIA_T. With virtual
2265  // functions in use, it is critical to instantiate the PCB_VIA_T
2266  // exactly.
2267  READLINE( m_reader );
2268 
2269  line = m_reader->Line();
2270 
2271  // example second line:
2272  // "De 0 0 463 0 800000\r\n"
2273 
2274 #if 1
2275  assert( TESTLINE( "De" ) );
2276 #else
2277  if( !TESTLINE( "De" ) )
2278  {
2279  // mandatory 2nd line is missing
2280  THROW_IO_ERROR( "Missing 2nd line of a TRACK def" );
2281  }
2282 #endif
2283 
2284  int makeType;
2285  unsigned long timeStamp;
2286  LAYER_NUM layer_num;
2287  int type, net_code, flags_int;
2288 
2289  // parse the 2nd line to determine the type of object
2290  // e.g. "De 15 1 7 0 0" for a via
2291  sscanf( line + SZ( "De" ), " %d %d %d %lX %X", &layer_num, &type, &net_code,
2292  &timeStamp, &flags_int );
2293 
2294  STATUS_FLAGS flags;
2295 
2296  flags = static_cast<STATUS_FLAGS>( flags_int );
2297 
2298  if( aStructType==PCB_TRACE_T && type==1 )
2299  makeType = PCB_VIA_T;
2300  else
2301  makeType = aStructType;
2302 
2303  TRACK* newTrack;
2304 
2305  switch( makeType )
2306  {
2307  default:
2308  case PCB_TRACE_T:
2309  newTrack = new TRACK( m_board );
2310  break;
2311 
2312  case PCB_VIA_T:
2313  newTrack = new VIA( m_board );
2314  break;
2315 
2316  case PCB_ZONE_T: // this is now deprecated, but exist in old boards
2317  newTrack = new SEGZONE( m_board );
2318  break;
2319  }
2320 
2321  newTrack->SetTimeStamp( (timestamp_t)timeStamp );
2322  newTrack->SetPosition( wxPoint( start_x, start_y ) );
2323  newTrack->SetEnd( wxPoint( end_x, end_y ) );
2324 
2325  newTrack->SetWidth( width );
2326 
2327  if( makeType == PCB_VIA_T ) // Ensure layers are OK when possible:
2328  {
2329  VIA *via = static_cast<VIA*>( newTrack );
2330  via->SetViaType( viatype );
2331 
2332  if( drill < 0 )
2333  via->SetDrillDefault();
2334  else
2335  via->SetDrill( drill );
2336 
2337  if( via->GetViaType() == VIA_THROUGH )
2338  via->SetLayerPair( F_Cu, B_Cu );
2339  else
2340  {
2341  PCB_LAYER_ID back = leg_layer2new( m_cu_count, (layer_num >> 4) & 0xf );
2342  PCB_LAYER_ID front = leg_layer2new( m_cu_count, layer_num & 0xf );
2343 
2344  if( is_leg_copperlayer_valid( m_cu_count, back ) &&
2346  via->SetLayerPair( front, back );
2347  else
2348  {
2349  delete via;
2350  newTrack = NULL;
2351  }
2352  }
2353  }
2354  else
2355  {
2356  // A few legacy boards can have tracks on non existent layers, because
2357  // reducing the number of layers does not remove tracks on removed layers
2358  // If happens, skip them
2359  if( is_leg_copperlayer_valid( m_cu_count, layer_num ) )
2360  newTrack->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2361  else
2362  {
2363  delete newTrack;
2364  newTrack = NULL;
2365  }
2366  }
2367 
2368  if( newTrack )
2369  {
2370  newTrack->SetNetCode( getNetCode( net_code ) );
2371  newTrack->SetState( flags, true );
2372 
2373  m_board->Add( newTrack );
2374  }
2375  }
2376 
2377  THROW_IO_ERROR( "Missing '$EndTRACK'" );
2378 }
2379 
2380 
2382 {
2383  char buf[1024];
2384  wxString netname;
2385  char* line;
2386 
2387  // create an empty NETCLASS without a name, but do not add it to the BOARD
2388  // yet since that would bypass duplicate netclass name checking within the BOARD.
2389  // store it temporarily in an unique_ptr until successfully inserted into the BOARD
2390  // just before returning.
2391  NETCLASSPTR nc = std::make_shared<NETCLASS>( wxEmptyString );
2392 
2393  while( ( line = READLINE( m_reader ) ) != NULL )
2394  {
2395  if( TESTLINE( "AddNet" ) ) // most frequent type of line
2396  {
2397  // e.g. "AddNet "V3.3D"\n"
2398  ReadDelimitedText( buf, line + SZ( "AddNet" ), sizeof(buf) );
2399  netname = FROM_UTF8( buf );
2400  nc->Add( netname );
2401  }
2402 
2403  else if( TESTLINE( "Clearance" ) )
2404  {
2405  BIU tmp = biuParse( line + SZ( "Clearance" ) );
2406  nc->SetClearance( tmp );
2407  }
2408 
2409  else if( TESTLINE( "TrackWidth" ) )
2410  {
2411  BIU tmp = biuParse( line + SZ( "TrackWidth" ) );
2412  nc->SetTrackWidth( tmp );
2413  }
2414 
2415  else if( TESTLINE( "ViaDia" ) )
2416  {
2417  BIU tmp = biuParse( line + SZ( "ViaDia" ) );
2418  nc->SetViaDiameter( tmp );
2419  }
2420 
2421  else if( TESTLINE( "ViaDrill" ) )
2422  {
2423  BIU tmp = biuParse( line + SZ( "ViaDrill" ) );
2424  nc->SetViaDrill( tmp );
2425  }
2426 
2427  else if( TESTLINE( "uViaDia" ) )
2428  {
2429  BIU tmp = biuParse( line + SZ( "uViaDia" ) );
2430  nc->SetuViaDiameter( tmp );
2431  }
2432 
2433  else if( TESTLINE( "uViaDrill" ) )
2434  {
2435  BIU tmp = biuParse( line + SZ( "uViaDrill" ) );
2436  nc->SetuViaDrill( tmp );
2437  }
2438 
2439  else if( TESTLINE( "Name" ) )
2440  {
2441  ReadDelimitedText( buf, line + SZ( "Name" ), sizeof(buf) );
2442  nc->SetName( FROM_UTF8( buf ) );
2443  }
2444 
2445  else if( TESTLINE( "Desc" ) )
2446  {
2447  ReadDelimitedText( buf, line + SZ( "Desc" ), sizeof(buf) );
2448  nc->SetDescription( FROM_UTF8( buf ) );
2449  }
2450 
2451  else if( TESTLINE( "$EndNCLASS" ) )
2452  {
2453  if( !m_board->GetDesignSettings().m_NetClasses.Add( nc ) )
2454  {
2455  // Must have been a name conflict, this is a bad board file.
2456  // User may have done a hand edit to the file.
2457 
2458  // unique_ptr will delete nc on this code path
2459 
2460  m_error.Printf( _( "duplicate NETCLASS name \"%s\"" ), nc->GetName().GetData() );
2462  }
2463 
2464  return; // preferred exit
2465  }
2466  }
2467 
2468  THROW_IO_ERROR( "Missing '$EndNCLASS'" );
2469 }
2470 
2471 
2473 {
2474  unique_ptr<ZONE_CONTAINER> zc( new ZONE_CONTAINER( m_board ) );
2475 
2477  bool endContour = false;
2478  int holeIndex = -1; // -1 is the main outline; holeIndex >= 0 = hole index
2479  char buf[1024];
2480  char* line;
2481  char* saveptr;
2482 
2483  while( ( line = READLINE( m_reader ) ) != NULL )
2484  {
2485  const char* data;
2486 
2487  if( TESTLINE( "ZCorner" ) ) // new corner of the zone outlines found
2488  {
2489  // e.g. "ZCorner 25650 49500 0"
2490  BIU x = biuParse( line + SZ( "ZCorner" ), &data );
2491  BIU y = biuParse( data, &data );
2492 
2493  if( endContour )
2494  {
2495  // the previous corner was the last corner of a contour.
2496  // so this corner is the first of a new hole
2497  endContour = false;
2498  zc->NewHole();
2499  holeIndex++;
2500  }
2501 
2502  zc->AppendCorner( wxPoint( x, y ), holeIndex );
2503 
2504  // Is this corner the end of current contour?
2505  // the next corner (if any) will be stored in a new contour (a hole)
2506  // intParse( data )returns 0 = usual corner, 1 = last corner of the current contour:
2507  endContour = intParse( data );
2508  }
2509 
2510  else if( TESTLINE( "ZInfo" ) ) // general info found
2511  {
2512  // e.g. 'ZInfo 479194B1 310 "COMMON"'
2513  timestamp_t timestamp = hexParse( line + SZ( "ZInfo" ), &data );
2514  int netcode = intParse( data, &data );
2515 
2516  if( ReadDelimitedText( buf, data, sizeof(buf) ) > (int) sizeof(buf) )
2517  {
2518  THROW_IO_ERROR( "ZInfo netname too long" );
2519  }
2520 
2521  zc->SetTimeStamp( timestamp );
2522  // Init the net code only, not the netname, to be sure
2523  // the zone net name is the name read in file.
2524  // (When mismatch, the user will be prompted in DRC, to fix the actual name)
2525  zc->BOARD_CONNECTED_ITEM::SetNetCode( getNetCode( netcode ) );
2526  }
2527 
2528  else if( TESTLINE( "ZLayer" ) ) // layer found
2529  {
2530  LAYER_NUM layer_num = layerParse( line + SZ( "ZLayer" ) );
2531  zc->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2532  }
2533 
2534  else if( TESTLINE( "ZAux" ) ) // aux info found
2535  {
2536  // e.g. "ZAux 7 E"
2537  int ignore = intParse( line + SZ( "ZAux" ), &data );
2538  char* hopt = strtok_r( (char*) data, delims, &saveptr );
2539 
2540  if( !hopt )
2541  {
2542  m_error.Printf( _( "Bad ZAux for CZONE_CONTAINER \"%s\"" ), zc->GetNetname().GetData() );
2544  }
2545 
2546  switch( *hopt ) // upper case required
2547  {
2548  case 'N': outline_hatch = ZONE_CONTAINER::NO_HATCH; break;
2549  case 'E': outline_hatch = ZONE_CONTAINER::DIAGONAL_EDGE; break;
2550  case 'F': outline_hatch = ZONE_CONTAINER::DIAGONAL_FULL; break;
2551 
2552  default:
2553  m_error.Printf( _( "Bad ZAux for CZONE_CONTAINER \"%s\"" ), zc->GetNetname().GetData() );
2555  }
2556 
2557  (void) ignore;
2558 
2559  // Set hatch mode later, after reading corner outline data
2560  }
2561 
2562  else if( TESTLINE( "ZSmoothing" ) )
2563  {
2564  // e.g. "ZSmoothing 0 0"
2565  int smoothing = intParse( line + SZ( "ZSmoothing" ), &data );
2566  BIU cornerRadius = biuParse( data );
2567 
2568  if( smoothing >= ZONE_SETTINGS::SMOOTHING_LAST || smoothing < 0 )
2569  {
2570  m_error.Printf( _( "Bad ZSmoothing for CZONE_CONTAINER \"%s\"" ), zc->GetNetname().GetData() );
2572  }
2573 
2574  zc->SetCornerSmoothingType( smoothing );
2575  zc->SetCornerRadius( cornerRadius );
2576  }
2577 
2578  else if( TESTLINE( "ZKeepout" ) )
2579  {
2580  zc->SetIsKeepout( true );
2581  // e.g. "ZKeepout tracks N vias N pads Y"
2582  data = strtok_r( line + SZ( "ZKeepout" ), delims, &saveptr );
2583 
2584  while( data )
2585  {
2586  if( !strcmp( data, "tracks" ) )
2587  {
2588  data = strtok_r( NULL, delims, &saveptr );
2589  zc->SetDoNotAllowTracks( data && *data == 'N' );
2590  }
2591  else if( !strcmp( data, "vias" ) )
2592  {
2593  data = strtok_r( NULL, delims, &saveptr );
2594  zc->SetDoNotAllowVias( data && *data == 'N' );
2595  }
2596  else if( !strcmp( data, "copperpour" ) )
2597  {
2598  data = strtok_r( NULL, delims, &saveptr );
2599  zc->SetDoNotAllowCopperPour( data && *data == 'N' );
2600  }
2601 
2602  data = strtok_r( NULL, delims, &saveptr );
2603  }
2604  }
2605 
2606  else if( TESTLINE( "ZOptions" ) )
2607  {
2608  // e.g. "ZOptions 0 32 F 200 200"
2609  int fillmode = intParse( line + SZ( "ZOptions" ), &data );
2610  int arcsegcount = intParse( data, &data );
2611  char fillstate = data[1]; // here e.g. " F"
2612  BIU thermalReliefGap = biuParse( data += 2 , &data ); // +=2 for " F"
2613  BIU thermalReliefCopperBridge = biuParse( data );
2614 
2615  zc->SetFillMode( fillmode ? ZFM_SEGMENTS : ZFM_POLYGONS );
2616 
2617  // @todo ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF: don't really want pcbnew.h
2618  // in here, after all, its a PLUGIN and global data is evil.
2619  // put in accessor
2620  if( arcsegcount >= 32 )
2621  arcsegcount = 32;
2622 
2623  zc->SetArcSegmentCount( arcsegcount );
2624  zc->SetIsFilled( fillstate == 'S' );
2625  zc->SetThermalReliefGap( thermalReliefGap );
2626  zc->SetThermalReliefCopperBridge( thermalReliefCopperBridge );
2627  }
2628 
2629  else if( TESTLINE( "ZClearance" ) ) // Clearance and pad options info found
2630  {
2631  // e.g. "ZClearance 40 I"
2632  BIU clearance = biuParse( line + SZ( "ZClearance" ), &data );
2633  char* padoption = strtok_r( (char*) data, delims, &saveptr ); // data: " I"
2634 
2635  ZoneConnection popt;
2636  switch( *padoption )
2637  {
2638  case 'I': popt = PAD_ZONE_CONN_FULL; break;
2639  case 'T': popt = PAD_ZONE_CONN_THERMAL; break;
2640  case 'H': popt = PAD_ZONE_CONN_THT_THERMAL; break;
2641  case 'X': popt = PAD_ZONE_CONN_NONE; break;
2642 
2643  default:
2644  m_error.Printf( _( "Bad ZClearance padoption for CZONE_CONTAINER \"%s\"" ),
2645  zc->GetNetname().GetData() );
2647  }
2648 
2649  zc->SetZoneClearance( clearance );
2650  zc->SetPadConnection( popt );
2651  }
2652 
2653  else if( TESTLINE( "ZMinThickness" ) )
2654  {
2655  BIU thickness = biuParse( line + SZ( "ZMinThickness" ) );
2656  zc->SetMinThickness( thickness );
2657  }
2658 
2659  else if( TESTLINE( "ZPriority" ) )
2660  {
2661  int priority = intParse( line + SZ( "ZPriority" ) );
2662  zc->SetPriority( priority );
2663  }
2664 
2665  else if( TESTLINE( "$POLYSCORNERS" ) )
2666  {
2667  // Read the PolysList (polygons that are the solid areas in the filled zone)
2668  SHAPE_POLY_SET polysList;
2669 
2670  bool makeNewOutline = true;
2671 
2672  while( ( line = READLINE( m_reader ) ) != NULL )
2673  {
2674  if( TESTLINE( "$endPOLYSCORNERS" ) )
2675  break;
2676 
2677  // e.g. "39610 43440 0 0"
2678  BIU x = biuParse( line, &data );
2679  BIU y = biuParse( data, &data );
2680 
2681  if( makeNewOutline )
2682  polysList.NewOutline();
2683 
2684  polysList.Append( x, y );
2685 
2686  bool end_contour = intParse( data, &data ); // end_countour was a bool when file saved, so '0' or '1' here
2687  intParse( data ); // skip corner utility flag
2688 
2689  makeNewOutline = end_contour;
2690  }
2691 
2692  zc->SetFilledPolysList( polysList );
2693  }
2694 
2695  else if( TESTLINE( "$FILLSEGMENTS" ) )
2696  {
2697  while( ( line = READLINE( m_reader ) ) != NULL )
2698  {
2699  if( TESTLINE( "$endFILLSEGMENTS" ) )
2700  break;
2701 
2702  // e.g. ""%d %d %d %d\n"
2703  BIU sx = biuParse( line, &data );
2704  BIU sy = biuParse( data, &data );
2705  BIU ex = biuParse( data, &data );
2706  BIU ey = biuParse( data );
2707 
2708  zc->FillSegments().push_back( SEG( VECTOR2I( sx, sy ), VECTOR2I( ex, ey ) ) );
2709  }
2710  }
2711 
2712  else if( TESTLINE( "$endCZONE_OUTLINE" ) )
2713  {
2714  // Ensure keepout does not have a net
2715  // (which have no sense for a keepout zone)
2716  if( zc->GetIsKeepout() )
2717  zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2718 
2719  // should always occur, but who knows, a zone without two corners
2720  // is no zone at all, it's a spot?
2721 
2722  if( zc->GetNumCorners() > 2 )
2723  {
2724  if( !zc->IsOnCopperLayer() )
2725  {
2726  zc->SetFillMode( ZFM_POLYGONS );
2727  zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2728  }
2729 
2730  // Hatch here, after outlines corners are read
2731  // Set hatch here, after outlines corners are read
2732  zc->SetHatch( outline_hatch, ZONE_CONTAINER::GetDefaultHatchPitch(),
2733  true );
2734 
2735  m_board->Add( zc.release() );
2736  }
2737 
2738  return; // preferred exit
2739  }
2740  }
2741 
2742  THROW_IO_ERROR( "Missing '$endCZONE_OUTLINE'" );
2743 }
2744 
2745 
2747 {
2748  unique_ptr<DIMENSION> dim( new DIMENSION( m_board ) );
2749 
2750  char* line;
2751  char* saveptr;
2752 
2753  while( ( line = READLINE( m_reader ) ) != NULL )
2754  {
2755  const char* data;
2756 
2757  if( TESTLINE( "$endCOTATION" ) )
2758  {
2759  m_board->Add( dim.release(), ADD_APPEND );
2760  return; // preferred exit
2761  }
2762 
2763  else if( TESTLINE( "Va" ) )
2764  {
2765  BIU value = biuParse( line + SZ( "Va" ) );
2766  dim->SetValue( value );
2767  }
2768 
2769  else if( TESTLINE( "Ge" ) )
2770  {
2771  LAYER_NUM layer_num;
2772  unsigned long timestamp;
2773  int shape;
2774  int ilayer;
2775 
2776  sscanf( line + SZ( "Ge" ), " %d %d %lX", &shape, &ilayer, &timestamp );
2777 
2778  if( ilayer < FIRST_NON_COPPER_LAYER )
2779  layer_num = FIRST_NON_COPPER_LAYER;
2780  else if( ilayer > LAST_NON_COPPER_LAYER )
2781  layer_num = LAST_NON_COPPER_LAYER;
2782  else
2783  layer_num = ilayer;
2784 
2785  dim->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2786  dim->SetTimeStamp( (timestamp_t) timestamp );
2787  dim->SetShape( shape );
2788  }
2789 
2790  else if( TESTLINE( "Te" ) )
2791  {
2792  char buf[2048];
2793 
2794  ReadDelimitedText( buf, line + SZ( "Te" ), sizeof(buf) );
2795  dim->SetText( FROM_UTF8( buf ) );
2796  }
2797 
2798  else if( TESTLINE( "Po" ) )
2799  {
2800  // sscanf( Line + 2, " %d %d %d %d %d %d %d", &m_Text->m_Pos.x, &m_Text->m_Pos.y,
2801  // &m_Text->m_Size.x, &m_Text->m_Size.y, &thickness, &orientation, &normal_display );
2802 
2803  BIU pos_x = biuParse( line + SZ( "Po" ), &data );
2804  BIU pos_y = biuParse( data, &data );
2805  BIU width = biuParse( data, &data );
2806  BIU height = biuParse( data, &data );
2807  BIU thickn = biuParse( data, &data );
2808  double orient = degParse( data, &data );
2809  char* mirror = strtok_r( (char*) data, delims, &saveptr );
2810 
2811  // This sets both DIMENSION's position and internal m_Text's.
2812  // @todo: But why do we even know about internal m_Text?
2813  dim->SetPosition( wxPoint( pos_x, pos_y ) );
2814  dim->SetTextSize( wxSize( width, height ) );
2815 
2816  dim->Text().SetMirrored( mirror && *mirror == '0' );
2817  dim->Text().SetThickness( thickn );
2818  dim->Text().SetTextAngle( orient );
2819  }
2820 
2821  else if( TESTLINE( "Sb" ) )
2822  {
2823  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_crossBarOx, &m_crossBarOy, &m_crossBarFx, &m_crossBarFy, &m_Width );
2824 
2825  int ignore = biuParse( line + SZ( "Sb" ), &data );
2826  BIU crossBarOx = biuParse( data, &data );
2827  BIU crossBarOy = biuParse( data, &data );
2828  BIU crossBarFx = biuParse( data, &data );
2829  BIU crossBarFy = biuParse( data, &data );
2830  BIU width = biuParse( data );
2831 
2832  dim->m_crossBarO.x = crossBarOx;
2833  dim->m_crossBarO.y = crossBarOy;
2834  dim->m_crossBarF.x = crossBarFx;
2835  dim->m_crossBarF.y = crossBarFy;
2836  dim->SetWidth( width );
2837  (void) ignore;
2838  }
2839 
2840  else if( TESTLINE( "Sd" ) )
2841  {
2842  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_featureLineDOx, &m_featureLineDOy, &m_featureLineDFx, &m_featureLineDFy, &Dummy );
2843 
2844  int ignore = intParse( line + SZ( "Sd" ), &data );
2845  BIU featureLineDOx = biuParse( data, &data );
2846  BIU featureLineDOy = biuParse( data, &data );
2847  BIU featureLineDFx = biuParse( data, &data );
2848  BIU featureLineDFy = biuParse( data );
2849 
2850  dim->m_featureLineDO.x = featureLineDOx;
2851  dim->m_featureLineDO.y = featureLineDOy;
2852  dim->m_featureLineDF.x = featureLineDFx;
2853  dim->m_featureLineDF.y = featureLineDFy;
2854  (void) ignore;
2855  }
2856 
2857  else if( TESTLINE( "Sg" ) )
2858  {
2859  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_featureLineGOx, &m_featureLineGOy, &m_featureLineGFx, &m_featureLineGFy, &Dummy );
2860 
2861  int ignore = intParse( line + SZ( "Sg" ), &data );
2862  BIU featureLineGOx = biuParse( data, &data );
2863  BIU featureLineGOy = biuParse( data, &data );
2864  BIU featureLineGFx = biuParse( data, &data );
2865  BIU featureLineGFy = biuParse( data );
2866 
2867  dim->m_featureLineGO.x = featureLineGOx;
2868  dim->m_featureLineGO.y = featureLineGOy;
2869  dim->m_featureLineGF.x = featureLineGFx;
2870  dim->m_featureLineGF.y = featureLineGFy;
2871  (void) ignore;
2872  }
2873 
2874  else if( TESTLINE( "S1" ) )
2875  {
2876  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowD1Ox, &m_arrowD1Oy, &m_arrowD1Fx, &m_arrowD1Fy, &Dummy );
2877 
2878  int ignore = intParse( line + SZ( "S1" ), &data );
2879  biuParse( data, &data ); // skipping excessive data
2880  biuParse( data, &data ); // skipping excessive data
2881  BIU arrowD1Fx = biuParse( data, &data );
2882  BIU arrowD1Fy = biuParse( data );
2883 
2884  dim->m_arrowD1F.x = arrowD1Fx;
2885  dim->m_arrowD1F.y = arrowD1Fy;
2886  (void) ignore;
2887  }
2888 
2889  else if( TESTLINE( "S2" ) )
2890  {
2891  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowD2Ox, &m_arrowD2Oy, &m_arrowD2Fx, &m_arrowD2Fy, &Dummy );
2892 
2893  int ignore = intParse( line + SZ( "S2" ), &data );
2894  biuParse( data, &data ); // skipping excessive data
2895  biuParse( data, &data ); // skipping excessive data
2896  BIU arrowD2Fx = biuParse( data, &data );
2897  BIU arrowD2Fy = biuParse( data, &data );
2898 
2899  dim->m_arrowD2F.x = arrowD2Fx;
2900  dim->m_arrowD2F.y = arrowD2Fy;
2901  (void) ignore;
2902  }
2903 
2904  else if( TESTLINE( "S3" ) )
2905  {
2906  // sscanf( Line + 2, " %d %d %d %d %d %d\n", &Dummy, &m_arrowG1Ox, &m_arrowG1Oy, &m_arrowG1Fx, &m_arrowG1Fy, &Dummy );
2907  int ignore = intParse( line + SZ( "S3" ), &data );
2908  biuParse( data, &data ); // skipping excessive data
2909  biuParse( data, &data ); // skipping excessive data
2910  BIU arrowG1Fx = biuParse( data, &data );
2911  BIU arrowG1Fy = biuParse( data, &data );
2912 
2913  dim->m_arrowG1F.x = arrowG1Fx;
2914  dim->m_arrowG1F.y = arrowG1Fy;
2915  (void) ignore;
2916  }
2917 
2918  else if( TESTLINE( "S4" ) )
2919  {
2920  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowG2Ox, &m_arrowG2Oy, &m_arrowG2Fx, &m_arrowG2Fy, &Dummy );
2921  int ignore = intParse( line + SZ( "S4" ), &data );
2922  biuParse( data, &data ); // skipping excessive data
2923  biuParse( data, &data ); // skipping excessive data
2924  BIU arrowG2Fx = biuParse( data, &data );
2925  BIU arrowG2Fy = biuParse( data, &data );
2926 
2927  dim->m_arrowG2F.x = arrowG2Fx;
2928  dim->m_arrowG2F.y = arrowG2Fy;
2929  (void) ignore;
2930  }
2931  }
2932 
2933  THROW_IO_ERROR( "Missing '$endCOTATION'" );
2934 }
2935 
2936 
2938 {
2939  char* line;
2940 
2941  while( ( line = READLINE( m_reader ) ) != NULL )
2942  {
2943  const char* data;
2944 
2945  if( TESTLINE( "$EndPCB_TARGET" ) || TESTLINE( "$EndMIREPCB" ) )
2946  {
2947  return; // preferred exit
2948  }
2949 
2950  else if( TESTLINE( "Po" ) )
2951  {
2952  // 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 );
2953 
2954  int shape = intParse( line + SZ( "Po" ), &data );
2955 
2956  LAYER_NUM layer_num = layerParse( data, &data );
2957 
2958  BIU pos_x = biuParse( data, &data );
2959  BIU pos_y = biuParse( data, &data );
2960  BIU size = biuParse( data, &data );
2961  BIU width = biuParse( data, &data );
2962  timestamp_t timestamp = hexParse( data );
2963 
2964  if( layer_num < FIRST_NON_COPPER_LAYER )
2965  layer_num = FIRST_NON_COPPER_LAYER;
2966 
2967  else if( layer_num > LAST_NON_COPPER_LAYER )
2968  layer_num = LAST_NON_COPPER_LAYER;
2969 
2970  PCB_TARGET* t = new PCB_TARGET( m_board, shape, leg_layer2new( m_cu_count, layer_num ),
2971  wxPoint( pos_x, pos_y ), size, width );
2972  m_board->Add( t, ADD_APPEND );
2973 
2974  t->SetTimeStamp( timestamp );
2975  }
2976  }
2977 
2978  THROW_IO_ERROR( "Missing '$EndDIMENSION'" );
2979 }
2980 
2981 
2982 BIU LEGACY_PLUGIN::biuParse( const char* aValue, const char** nptrptr )
2983 {
2984  char* nptr;
2985 
2986  errno = 0;
2987 
2988  double fval = strtod( aValue, &nptr );
2989 
2990  if( errno )
2991  {
2992  m_error.Printf( _( "invalid float number in file: \"%s\"\nline: %d, offset: %d" ),
2993  m_reader->GetSource().GetData(),
2994  m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
2995 
2997  }
2998 
2999  if( aValue == nptr )
3000  {
3001  m_error.Printf( _( "missing float number in file: \"%s\"\nline: %d, offset: %d" ),
3002  m_reader->GetSource().GetData(),
3003  m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
3004 
3006  }
3007 
3008  if( nptrptr )
3009  *nptrptr = nptr;
3010 
3011  fval *= diskToBiu;
3012 
3013  // fval is up into the whole number realm here, and should be bounded
3014  // within INT_MIN to INT_MAX since BIU's are nanometers.
3015  return KiROUND( fval );
3016 }
3017 
3018 
3019 double LEGACY_PLUGIN::degParse( const char* aValue, const char** nptrptr )
3020 {
3021  char* nptr;
3022 
3023  errno = 0;
3024 
3025  double fval = strtod( aValue, &nptr );
3026 
3027  if( errno )
3028  {
3029  m_error.Printf( _( "invalid float number in file: \"%s\"\nline: %d, offset: %d" ),
3030  m_reader->GetSource().GetData(), m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
3031 
3033  }
3034 
3035  if( aValue == nptr )
3036  {
3037  m_error.Printf( _( "missing float number in file: \"%s\"\nline: %d, offset: %d" ),
3038  m_reader->GetSource().GetData(), m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
3039 
3041  }
3042 
3043  if( nptrptr )
3044  *nptrptr = nptr;
3045 
3046  return fval;
3047 }
3048 
3049 
3050 void LEGACY_PLUGIN::init( const PROPERTIES* aProperties )
3051 {
3053  m_cu_count = 16;
3054  m_board = NULL;
3055  m_props = aProperties;
3056 
3057  // conversion factor for saving RAM BIUs to KICAD legacy file format.
3058  biuToDisk = 1.0/IU_PER_MM; // BIUs are nanometers & file is mm
3059 
3060  // Conversion factor for loading KICAD legacy file format into BIUs in RAM
3061  // Start by assuming the *.brd file is in deci-mils.
3062  // If we see "Units mm" in the $GENERAL section, set diskToBiu to 1000000.0
3063  // then, during the file loading process, to start a conversion from
3064  // mm to nanometers. The deci-mil legacy files have no such "Units" marker
3065  // so we must assume the file is in deci-mils until told otherwise.
3066 
3067  diskToBiu = IU_PER_MILS / 10; // BIUs are nanometers
3068 }
3069 
3070 
3071 void LEGACY_PLUGIN::SaveModule3D( const MODULE* me ) const
3072 {
3073  auto sM = me->Models().begin();
3074  auto eM = me->Models().end();
3075 
3076  while( sM != eM )
3077  {
3078  if( sM->m_Filename.empty() )
3079  {
3080  ++sM;
3081  continue;
3082  }
3083 
3084  fprintf( m_fp, "$SHAPE3D\n" );
3085 
3086  fprintf( m_fp, "Na %s\n", EscapedUTF8( sM->m_Filename ).c_str() );
3087 
3088  fprintf(m_fp,
3089 #if defined(DEBUG)
3090  // use old formats for testing, just to verify compatibility
3091  // using "diff", then switch to more concise form for release builds.
3092  "Sc %lf %lf %lf\n",
3093 #else
3094  "Sc %.10g %.10g %.10g\n",
3095 #endif
3096  sM->m_Scale.x,
3097  sM->m_Scale.y,
3098  sM->m_Scale.z );
3099 
3100  fprintf(m_fp,
3101 #if defined(DEBUG)
3102  "Of %lf %lf %lf\n",
3103 #else
3104  "Of %.10g %.10g %.10g\n",
3105 #endif
3106  sM->m_Offset.x,
3107  sM->m_Offset.y,
3108  sM->m_Offset.z );
3109 
3110  fprintf(m_fp,
3111 #if defined(DEBUG)
3112  "Ro %lf %lf %lf\n",
3113 #else
3114  "Ro %.10g %.10g %.10g\n",
3115 #endif
3116  sM->m_Rotation.x,
3117  sM->m_Rotation.y,
3118  sM->m_Rotation.z );
3119 
3120  fprintf( m_fp, "$EndSHAPE3D\n" );
3121 
3122  ++sM;
3123  }
3124 
3125  return;
3126 }
3127 
3128 
3129 //-----<FOOTPRINT LIBRARY FUNCTIONS>--------------------------------------------
3130 
3131 /*
3132 
3133  The legacy file format is being obsoleted and this code will have a short
3134  lifetime, so it only needs to be good enough for a short duration of time.
3135  Caching all the MODULEs is a bit memory intensive, but it is a considerably
3136  faster way of fulfilling the API contract. Otherwise, without the cache, you
3137  would have to re-read the file when searching for any MODULE, and this would
3138  be very problematic filling a FOOTPRINT_LIST via this PLUGIN API. If memory
3139  becomes a concern, consider the cache lifetime policy, which determines the
3140  time that a LP_CACHE is in RAM. Note PLUGIN lifetime also plays a role in
3141  cache lifetime.
3142 
3143 */
3144 
3145 
3146 #include <boost/ptr_container/ptr_map.hpp>
3147 #include <wx/filename.h>
3148 
3149 typedef boost::ptr_map< std::string, MODULE > MODULE_MAP;
3150 typedef MODULE_MAP::iterator MODULE_ITER;
3151 typedef MODULE_MAP::const_iterator MODULE_CITER;
3152 
3153 
3160 struct LP_CACHE
3161 {
3162  LEGACY_PLUGIN* m_owner; // my owner, I need its LEGACY_PLUGIN::loadMODULE()
3163  wxString m_lib_path;
3164  wxDateTime m_mod_time;
3165  MODULE_MAP m_modules; // map or tuple of footprint_name vs. MODULE*
3167 
3168  LP_CACHE( LEGACY_PLUGIN* aOwner, const wxString& aLibraryPath );
3169 
3170  // Most all functions in this class throw IO_ERROR exceptions. There are no
3171  // error codes nor user interface calls from here, nor in any PLUGIN.
3172  // Catch these exceptions higher up please.
3173 
3175  void Save();
3176 
3177  void SaveHeader( FILE* aFile );
3178 
3179  void SaveIndex( FILE* aFile );
3180 
3181  void SaveModules( FILE* aFile );
3182 
3183  void SaveEndOfFile( FILE* aFile )
3184  {
3185  fprintf( aFile, "$EndLIBRARY\n" );
3186  }
3187 
3188  void Load();
3189 
3190  void ReadAndVerifyHeader( LINE_READER* aReader );
3191 
3192  void SkipIndex( LINE_READER* aReader );
3193 
3194  void LoadModules( LINE_READER* aReader );
3195 
3196  wxDateTime GetLibModificationTime();
3197 };
3198 
3199 
3200 LP_CACHE::LP_CACHE( LEGACY_PLUGIN* aOwner, const wxString& aLibraryPath ) :
3201  m_owner( aOwner ),
3202  m_lib_path( aLibraryPath ),
3203  m_writable( true )
3204 {
3205 }
3206 
3207 
3209 {
3210  wxFileName fn( m_lib_path );
3211 
3212  // update the writable flag while we have a wxFileName, in a network this
3213  // is possibly quite dynamic anyway.
3214  m_writable = fn.IsFileWritable();
3215 
3216  return fn.GetModificationTime();
3217 }
3218 
3219 
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( UTF8( 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( UTF8( 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  // If we have no cache, return a number which won't match any stored timestamps
3389  if( !m_cache || m_cache->m_lib_path != aLibraryPath )
3390  return wxDateTime::Now().GetValue().GetValue();
3391 
3392  return m_cache->GetLibModificationTime().GetValue().GetValue();
3393 }
3394 
3395 
3396 void LEGACY_PLUGIN::cacheLib( const wxString& aLibraryPath )
3397 {
3398  if( !m_cache || m_cache->m_lib_path != aLibraryPath ||
3399  // somebody else on a network touched the library:
3400  m_cache->m_mod_time != m_cache->GetLibModificationTime() )
3401  {
3402  // a spectacular episode in memory management:
3403  delete m_cache;
3404  m_cache = new LP_CACHE( this, aLibraryPath );
3405  m_cache->Load();
3406  }
3407 }
3408 
3409 
3410 void LEGACY_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames,
3411  const wxString& aLibraryPath,
3412  const PROPERTIES* aProperties )
3413 {
3414  LOCALE_IO toggle; // toggles on, then off, the C locale.
3415 
3416  init( aProperties );
3417 
3418  cacheLib( aLibraryPath );
3419 
3420  const MODULE_MAP& mods = m_cache->m_modules;
3421 
3422  for( MODULE_CITER it = mods.begin(); it != mods.end(); ++it )
3423  {
3424  aFootprintNames.Add( FROM_UTF8( it->first.c_str() ) );
3425  }
3426 }
3427 
3428 
3429 MODULE* LEGACY_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
3430  const wxString& aFootprintName, const PROPERTIES* aProperties )
3431 {
3432  LOCALE_IO toggle; // toggles on, then off, the C locale.
3433 
3434  init( aProperties );
3435 
3436  cacheLib( aLibraryPath );
3437 
3438  const MODULE_MAP& mods = m_cache->m_modules;
3439 
3440  MODULE_CITER it = mods.find( TO_UTF8( aFootprintName ) );
3441 
3442  if( it == mods.end() )
3443  {
3444  /*
3445  THROW_IO_ERROR( wxString::Format( _( "No \"%s\" footprint in library \"%s\"" ),
3446  aFootprintName.GetData(), aLibraryPath.GetData() ) );
3447  */
3448 
3449  return NULL;
3450  }
3451 
3452  // copy constructor to clone the already loaded MODULE
3453  return new MODULE( *it->second );
3454 }
3455 
3456 
3457 bool LEGACY_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
3458 {
3459  wxFileName fn = aLibraryPath;
3460 
3461  if( !fn.FileExists() )
3462  return false;
3463 
3464  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
3465  // we don't want that. we want bare metal portability with no UI here.
3466  if( wxRemove( aLibraryPath ) )
3467  {
3469  _( "library \"%s\" cannot be deleted" ),
3470  aLibraryPath.GetData() ) );
3471  }
3472 
3473  if( m_cache && m_cache->m_lib_path == aLibraryPath )
3474  {
3475  delete m_cache;
3476  m_cache = 0;
3477  }
3478 
3479  return true;
3480 }
3481 
3482 
3483 bool LEGACY_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
3484 {
3485 #if 0 // no support for 32 Cu layers in legacy format
3486  return false;
3487 #else
3488  LOCALE_IO toggle;
3489 
3490  init( NULL );
3491 
3492  cacheLib( aLibraryPath );
3493 
3494  return m_cache->m_writable;
3495 #endif
3496 }
3497 
3498 
3500  m_cu_count( 16 ), // for FootprintLoad()
3501  m_board( 0 ),
3502  m_props( 0 ),
3503  m_reader( 0 ),
3504  m_fp( 0 ),
3505  m_cache( 0 ),
3506  m_mapping( new NETINFO_MAPPING() )
3507 {
3508  init( NULL );
3509 }
3510 
3511 
3513 {
3514  delete m_cache;
3515  delete m_mapping;
3516 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:176
void SetComment1(const wxString &aComment)
Definition: title_block.h:116
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
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
void SetPlacementCost90(int aCost)
Definition: class_module.h:573
int m_SolderMaskMargin
Solder mask margin.
void SetFileFormatVersionAtLoad(int aVersion)
Definition: class_board.h:277
BOARD_ITEM_CONTAINER * GetParent() const
Struct VIA_DIMENSION is a small helper container to handle a stock of specific vias each with unique ...
long timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: base_struct.h:155
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:558
#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:502
void SetThermalGap(int aGap)
Definition: class_module.h:221
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:47
const ZONE_SETTINGS & GetZoneSettings() const
Definition: class_board.h:557
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
virtual void Save(const wxString &aFileName, BOARD *aBoard, const PROPERTIES *aProperties=NULL)
Function Save will write aBoard to a storage file in a format that this PLUGIN implementation knows a...
Definition: plugin.cpp:54
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:194
void SetViaType(VIATYPE_T aViaType)
Definition: class_track.h:459
void SetLocalClearance(int aClearance)
Definition: class_module.h:207
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:106
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:167
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:570
Class PCB_PLOT_PARAMS_PARSER is the parser class for PCB_PLOT_PARAMS.
int m_ModuleTextWidth
Default footprint texts thickness.
void SetEnd(const wxPoint &aEnd)
Definition: class_track.h:118
std::vector< int > m_TrackWidthList
Track width list.
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:83
int m_ModuleSegmentWidth
Default width for all graphic lines.
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: class_board.h:555
#define LAYER_N_BACK
void CalculateBoundingBox()
Function CalculateBoundingBox calculates the bounding box in board coordinates.
int m_PcbTextWidth
current Pcb (not module) Text width
wxDateTime m_mod_time
Class BOARD to handle a board.
LEGACY_PLUGIN * m_owner
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: class_board.h:549
void SetItalic(bool isItalic)
Definition: eda_text.h:167
ZoneConnection
How pads are covered by copper in zone.
Definition: zones.h:55
polygon (not yet used for tracks, but could be in microwave apps)
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:221
static const char delims[]
void SetVisible(bool aVisible)
Definition: eda_text.h:173
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:570
void SetDate(const wxString &aDate)
Function SetDate sets the date field, and defaults to the current time and date.
Definition: title_block.h:73
Classes to handle copper zones.
void SetZoneConnection(ZoneConnection aType)
Definition: class_module.h:215
usual segment : line with rounded ends
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:73
#define READLINE(rdr)
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:274
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:212
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
wxSize m_ModuleTextSize
Default footprint texts size.
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:589
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:39
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:188
void SetLocalSolderPasteMarginRatio(double aRatio)
Definition: class_module.h:213
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:119
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:101
#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
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:57
#define SILKSCREEN_N_FRONT
void SaveEndOfFile(FILE *aFile)
const LIB_ID & GetFPID() const
Definition: class_module.h:191
#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
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:137
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
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:458
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:187
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:501
void SetVisibleLayers(LSET aLayerMask)
Function SetVisibleLayers is a proxy function that calls the correspondent function in m_BoardSetting...
wxSize m_PcbTextSize
current Pcb (not module) Text size
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:118
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
Definition: page_info.h:49
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:128
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:192
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:71
void LoadModules(LINE_READER *aReader)
void SetLastEditTime(timestamp_t aTime)
Definition: class_module.h:309
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_DrawSegmentWidth
current graphic line width (not EDGE layer)
int m_ViasMinDrill
vias (not micro vias) min drill diameter
void SetCompany(const wxString &aCompany)
Definition: title_block.h:93
unsigned STATUS_FLAGS
Definition: base_struct.h:142
void SetThermalWidth(int aWidth)
Definition: class_module.h:218
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:533
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:543
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
class SEGZONE, a segment used to fill a zone area (segment on a copper layer)
Definition: typeinfo.h:97
unsigned LEG_MASK
std::map< wxString, MODULE * > MODULE_MAP
Definition: eagle_plugin.h:36
void SetIsPlaced(bool isPlaced)
Definition: class_module.h:282
LEGACY_PLUGIN::BIU BIU
HATCH_STYLE
Zone hatch styles.
Definition: class_zone.h:67
void SetFileName(const wxString &aFileName)
Definition: class_board.h:232
void SetPosition(const wxPoint &aPos) override
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: class_board.h:552
double diskToBiu
convert from disk engineering units to BIUs with this scale factor
int GetNet() const
Function GetNet.
Definition: netinfo.h:227
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:59
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)
#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:60
void SetLocalSolderMaskMargin(int aMargin)
Definition: class_module.h:204
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:487
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:102
default
Definition: class_module.h:76
static bool isSpace(int c)
Class ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:49
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:54
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:102
#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:210
MODULE_MAP::const_iterator MODULE_CITER
wxDateTime GetLibModificationTime()
std::list< MODULE_3D_SETTINGS > & Models()
Definition: class_module.h:177
void SetComment2(const wxString &aComment)
Definition: title_block.h:117
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:253
void SetLocked(bool isLocked) override
Function SetLocked sets the MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition: class_module.h:273
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:100
#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:169
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:191
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:466
Usual pad.
Definition: pad_shapes.h:60
void SetVisibleElements(int aMask)
Function SetVisibleElements changes the bit-mask of visible element categories.
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:99
std::vector< VIA_DIMENSION > m_ViasDimensionsList
Vias size and drill list.
#define FIRST_COPPER_LAYER
void SetKeywords(const wxString &aKeywords)
Definition: class_module.h:198
PCB_TARGET class definition.
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:164
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
DLIST< D_PAD > & PadsList()
Definition: class_module.h:161
void SetTextAngle(double aAngle)
Module description (excepted pads)
void SetComment3(const wxString &aComment)
Definition: title_block.h:118
const wxString & GetNetname() const
Function GetNetname.
Definition: netinfo.h:235
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:43
int m_EdgeSegmentWidth
current graphic line width (EDGE layer only)
double m_SolderPasteMarginRatio
Solder pask margin ratio value of pad size The final margin is the sum of these 2 values...
EDGE_MODULE class definition.
void 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
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:461
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
const wxPoint GetPosition() const override
Definition: class_module.h:182
void SetFPID(const LIB_ID &aFPID)
Definition: class_module.h:192
#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:58
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:201
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
NETCLASSES m_NetClasses
List of current netclasses. There is always the default netclass.
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:146
int m_SolderMaskMinWidth
Solder mask min width.
void SetAttributes(int aAttributes)
Definition: class_module.h:225
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:214
const PROPERTIES * m_props
passed via Save() or Load(), no ownership, may be NULL.
pads are covered by copper
Definition: zones.h:59
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
virtual void SetText(const wxString &aText)
Definition: eda_text.h:139
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:195