KiCad PCB EDA Suite
page_layout_reader.cpp
Go to the documentation of this file.
1 
7 /*
8  * This program source code file is part of KiCad, a free EDA CAD application.
9  *
10  * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
11  * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors.
12  *
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, you may find one here:
26  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
27  * or you may search the http://www.gnu.org website for the version 2 license,
28  * or you may write to the Free Software Foundation, Inc.,
29  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
30  */
31 
32 #include <fctsys.h>
33 #include <base_struct.h>
34 #include <worksheet.h>
38 
39 
40 using namespace TB_READER_T;
41 
48 {
49 public:
50  PAGE_LAYOUT_READER_PARSER( const char* aLine, const wxString& aSource );
51  void Parse( WORKSHEET_LAYOUT* aLayout )
52  throw( PARSE_ERROR, IO_ERROR );
53 
54 private:
55 
63  int parseInt( int aMin, int aMax );
64 
70  double parseDouble();
71 
72  void parseSetup( WORKSHEET_LAYOUT* aLayout ) throw( IO_ERROR, PARSE_ERROR );
73 
77  void parseGraphic( WORKSHEET_DATAITEM * aItem ) throw( IO_ERROR, PARSE_ERROR );
78 
82  void parseText( WORKSHEET_DATAITEM_TEXT * aItem ) throw( IO_ERROR, PARSE_ERROR );
83 
88  void parsePolygon( WORKSHEET_DATAITEM_POLYPOLYGON * aItem )
89  throw( IO_ERROR, PARSE_ERROR );
90 
94  void parsePolyOutline( WORKSHEET_DATAITEM_POLYPOLYGON * aItem )
95  throw( IO_ERROR, PARSE_ERROR );
96 
97 
101  void parseBitmap( WORKSHEET_DATAITEM_BITMAP * aItem )
102  throw( IO_ERROR, PARSE_ERROR );
103 
104  void parseCoordinate( POINT_COORD& aCoord) throw( IO_ERROR, PARSE_ERROR );
105  void readOption( WORKSHEET_DATAITEM * aItem ) throw( IO_ERROR, PARSE_ERROR );
106  void readPngdata( WORKSHEET_DATAITEM_BITMAP * aItem ) throw( IO_ERROR, PARSE_ERROR );
107 };
108 
109 // PCB_PLOT_PARAMS_PARSER
110 
111 PAGE_LAYOUT_READER_PARSER::PAGE_LAYOUT_READER_PARSER( const char* aLine, const wxString& aSource ) :
112  PAGE_LAYOUT_READER_LEXER( aLine, aSource )
113 {
114 }
115 
116 
118  throw( PARSE_ERROR, IO_ERROR )
119 {
120  T token;
121  WORKSHEET_DATAITEM * item;
122 
123  LOCALE_IO toggle;
124 
125  while( ( token = NextTok() ) != T_RIGHT )
126  {
127  if( token == T_EOF)
128  break;
129 
130  if( token == T_LEFT )
131  token = NextTok();
132 
133  if( token == T_page_layout )
134  continue;
135 
136  switch( token )
137  {
138  case T_setup: // Defines default values for graphic items
139  parseSetup( aLayout );
140  break;
141 
142  case T_line:
144  parseGraphic( item );
145  aLayout->Append( item );
146  break;
147 
148  case T_rect:
150  parseGraphic( item );
151  aLayout->Append( item );
152  break;
153 
154  case T_polygon:
155  item = new WORKSHEET_DATAITEM_POLYPOLYGON();
156  parsePolygon( (WORKSHEET_DATAITEM_POLYPOLYGON*) item );
157  aLayout->Append( item );
158  break;
159 
160  case T_bitmap:
161  item = new WORKSHEET_DATAITEM_BITMAP( NULL );
162  parseBitmap( (WORKSHEET_DATAITEM_BITMAP*) item );
163  aLayout->Append( item );
164  break;
165 
166  case T_tbtext:
167  NeedSYMBOLorNUMBER();
168  item = new WORKSHEET_DATAITEM_TEXT( FromUTF8() );
169  parseText( (WORKSHEET_DATAITEM_TEXT*) item );
170  aLayout->Append( item );
171  break;
172 
173  default:
174  Unexpected( CurText() );
175  break;
176  }
177  }
178 }
179 
181  throw( IO_ERROR, PARSE_ERROR )
182 {
183  T token;
184  while( ( token = NextTok() ) != T_RIGHT )
185  {
186  if( token == T_EOF)
187  break;
188 
189  switch( token )
190  {
191  case T_LEFT:
192  break;
193 
194  case T_linewidth:
196  NeedRIGHT();
197  break;
198 
199  case T_textsize:
202  NeedRIGHT();
203  break;
204 
205  case T_textlinewidth:
207  NeedRIGHT();
208  break;
209 
210  case T_left_margin:
211  aLayout->SetLeftMargin( parseDouble() );
212  NeedRIGHT();
213  break;
214 
215  case T_right_margin:
216  aLayout->SetRightMargin( parseDouble() );
217  NeedRIGHT();
218  break;
219 
220  case T_top_margin:
221  aLayout->SetTopMargin( parseDouble() );
222  NeedRIGHT();
223  break;
224 
225  case T_bottom_margin:
226  aLayout->SetBottomMargin( parseDouble() );
227  NeedRIGHT();
228  break;
229 
230  default:
231  Unexpected( CurText() );
232  break;
233  }
234  }
235 }
236 
238  throw( IO_ERROR, PARSE_ERROR )
239 {
240  T token;
241 
242  while( ( token = NextTok() ) != T_RIGHT )
243  {
244  if( token == T_EOF)
245  break;
246 
247  if( token == T_LEFT )
248  token = NextTok();
249 
250  switch( token )
251  {
252  case T_comment:
253  NeedSYMBOLorNUMBER();
254  aItem->m_Info = FromUTF8();
255  NeedRIGHT();
256  break;
257 
258  case T_pos:
259  parseCoordinate( aItem->m_Pos );
260  break;
261 
262  case T_name:
263  NeedSYMBOLorNUMBER();
264  aItem->m_Name = FromUTF8();
265  NeedRIGHT();
266  break;
267 
268  case T_option:
269  readOption( aItem );
270  break;
271 
272  case T_pts:
273  parsePolyOutline( aItem );
274  aItem->CloseContour();
275  break;
276 
277  case T_rotate:
278  aItem->m_Orient = parseDouble();
279  NeedRIGHT();
280  break;
281 
282  case T_repeat:
283  aItem->m_RepeatCount = parseInt( -1, 100 );
284  NeedRIGHT();
285  break;
286 
287  case T_incrx:
288  aItem->m_IncrementVector.x = parseDouble();
289  NeedRIGHT();
290  break;
291 
292  case T_incry:
293  aItem->m_IncrementVector.y = parseDouble();
294  NeedRIGHT();
295  break;
296 
297  case T_linewidth:
298  aItem->m_LineWidth = parseDouble();
299  NeedRIGHT();
300  break;
301 
302  default:
303  Unexpected( CurText() );
304  break;
305  }
306  }
307 
308  aItem->SetBoundingBox();
309 }
310 
312  throw( IO_ERROR, PARSE_ERROR )
313 {
314  DPOINT corner;
315  T token;
316 
317  while( ( token = NextTok() ) != T_RIGHT )
318  {
319  if( token == T_EOF)
320  break;
321 
322  if( token == T_LEFT )
323  token = NextTok();
324 
325  switch( token )
326  {
327  case T_xy:
328  corner.x = parseDouble();
329  corner.y = parseDouble();
330  aItem->AppendCorner( corner );
331  NeedRIGHT();
332  break;
333 
334  default:
335  Unexpected( CurText() );
336  break;
337  }
338  }
339 }
340 
341 #include <wx/mstream.h>
343  throw( IO_ERROR, PARSE_ERROR )
344 {
345  T token;
346  BITMAP_BASE* image = new BITMAP_BASE;
347  aItem->m_ImageBitmap = image;
348 
349  while( ( token = NextTok() ) != T_RIGHT )
350  {
351  if( token == T_EOF)
352  break;
353 
354  if( token == T_LEFT )
355  token = NextTok();
356 
357  switch( token )
358  {
359  case T_name:
360  NeedSYMBOLorNUMBER();
361  aItem->m_Name = FromUTF8();
362  NeedRIGHT();
363  break;
364 
365  case T_pos:
366  parseCoordinate( aItem->m_Pos );
367  break;
368 
369  case T_repeat:
370  aItem->m_RepeatCount = parseInt( -1, 100 );
371  NeedRIGHT();
372  break;
373 
374  case T_incrx:
375  aItem->m_IncrementVector.x = parseDouble();
376  NeedRIGHT();
377  break;
378 
379  case T_incry:
380  aItem->m_IncrementVector.y = parseDouble();
381  NeedRIGHT();
382  break;
383 
384  case T_linewidth:
385  aItem->m_LineWidth = parseDouble();
386  NeedRIGHT();
387  break;
388 
389  case T_scale:
390  aItem->m_ImageBitmap->SetScale( parseDouble() );
391  NeedRIGHT();
392  break;
393 
394  case T_pngdata:
395  readPngdata( aItem );
396  break;
397 
398  case T_option:
399  readOption( aItem );
400  break;
401 
402  default:
403  Unexpected( CurText() );
404  break;
405  }
406  }
407 }
408 
410  throw( IO_ERROR, PARSE_ERROR )
411 {
412  std::string tmp;
413  T token;
414 
415  while( ( token = NextTok() ) != T_RIGHT )
416  {
417  if( token == T_EOF)
418  break;
419 
420  if( token == T_LEFT )
421  token = NextTok();
422 
423  switch( token )
424  {
425  case T_data:
426  NeedSYMBOLorNUMBER();
427  tmp += CurStr();
428  tmp += "\n";
429  NeedRIGHT();
430  break;
431 
432  default:
433  Unexpected( CurText() );
434  break;
435  }
436  }
437 
438  tmp += "EndData";
439 
440  wxString msg;
441  STRING_LINE_READER str_reader( tmp, wxT("Png kicad_wks data") );
442 
443  if( ! aItem->m_ImageBitmap->LoadData( str_reader, msg ) )
444  {
445  wxLogMessage(msg);
446  }
447 }
448 
449 
451  throw( IO_ERROR, PARSE_ERROR )
452 {
453  T token;
454 
455  while( ( token = NextTok() ) != T_RIGHT )
456  {
457  if( token == T_EOF)
458  break;
459 
460  switch( token )
461  {
462  case T_page1only:
463  aItem->SetPage1Option( 1 );
464  break;
465 
466  case T_notonpage1:
467  aItem->SetPage1Option( -1 );
468  break;
469 
470  default:
471  Unexpected( CurText() );
472  break;
473  }
474  }
475 }
476 
477 
479  throw( IO_ERROR, PARSE_ERROR )
480 {
481  T token;
482 
483  while( ( token = NextTok() ) != T_RIGHT )
484  {
485  if( token == T_EOF)
486  break;
487 
488  if( token == T_LEFT )
489  token = NextTok();
490  else
491  {
492  // If an other token than T_LEFT is read here, this is an error
493  // however, due to a old bug in kicad, the token T_end can be found
494  // without T_LEFT in a very few .wks files (perhaps only one in a demo).
495  // So this ugly hack disables the error detection.
496  if( token != T_end )
497  Unexpected( CurText() );
498  }
499 
500  switch( token )
501  {
502  case T_comment:
503  NeedSYMBOLorNUMBER();
504  aItem->m_Info = FromUTF8();
505  NeedRIGHT();
506  break;
507 
508  case T_option:
509  readOption( aItem );
510  break;
511 
512  case T_name:
513  NeedSYMBOLorNUMBER();
514  aItem->m_Name = FromUTF8();
515  NeedRIGHT();
516  break;
517 
518  case T_start:
519  parseCoordinate( aItem->m_Pos );
520  break;
521 
522  case T_end:
523  parseCoordinate( aItem->m_End );
524  break;
525 
526  case T_repeat:
527  aItem->m_RepeatCount = parseInt( -1, 100 );
528  NeedRIGHT();
529  break;
530 
531  case T_incrx:
532  aItem->m_IncrementVector.x = parseDouble();
533  NeedRIGHT();
534  break;
535 
536  case T_incry:
537  aItem->m_IncrementVector.y = parseDouble();
538  NeedRIGHT();
539  break;
540 
541  case T_linewidth:
542  aItem->m_LineWidth = parseDouble();
543  NeedRIGHT();
544  break;
545 
546  default:
547  Unexpected( CurText() );
548  break;
549  }
550  }
551 }
552 
553 
555  throw( IO_ERROR, PARSE_ERROR )
556 {
557  T token;
558 
559  while( ( token = NextTok() ) != T_RIGHT )
560  {
561  if( token == T_EOF)
562  break;
563 
564  if( token == T_LEFT )
565  token = NextTok();
566 
567  switch( token )
568  {
569  case T_comment:
570  NeedSYMBOLorNUMBER();
571  aItem->m_Info = FromUTF8();
572  NeedRIGHT();
573  break;
574 
575  case T_option:
576  readOption( aItem );
577  break;
578 
579  case T_name:
580  NeedSYMBOLorNUMBER();
581  aItem->m_Name = FromUTF8();
582  NeedRIGHT();
583  break;
584 
585  case T_pos:
586  parseCoordinate( aItem->m_Pos );
587  break;
588 
589  case T_repeat:
590  aItem->m_RepeatCount = parseInt( -1, 100 );
591  NeedRIGHT();
592  break;
593 
594  case T_incrx:
595  aItem->m_IncrementVector.x = parseDouble();
596  NeedRIGHT();
597  break;
598 
599  case T_incry:
600  aItem->m_IncrementVector.y = parseDouble();
601  NeedRIGHT();
602  break;
603 
604  case T_incrlabel:
605  aItem->m_IncrementLabel = parseInt(INT_MIN, INT_MAX);
606  NeedRIGHT();
607  break;
608 
609  case T_maxlen:
610  aItem->m_BoundingBoxSize.x = parseDouble();
611  NeedRIGHT();
612  break;
613 
614  case T_maxheight:
615  aItem->m_BoundingBoxSize.y = parseDouble();
616  NeedRIGHT();
617  break;
618 
619  case T_font:
620  while( ( token = NextTok() ) != T_RIGHT )
621  {
622  if( token == T_EOF)
623  break;
624 
625  switch( token )
626  {
627  case T_LEFT:
628  break;
629 
630  case T_bold:
631  aItem->SetBold( true );
632  break;
633 
634  case T_italic:
635  aItem->SetItalic( true );
636  break;
637 
638  case T_size:
639  aItem->m_TextSize.x = parseDouble();
640  aItem->m_TextSize.y = parseDouble();
641  NeedRIGHT();
642  break;
643 
644  case T_linewidth:
645  aItem->m_LineWidth = parseDouble();
646  NeedRIGHT();
647  break;
648 
649  default:
650  Unexpected( CurText() );
651  break;
652  }
653  }
654  break;
655 
656  case T_justify:
657  while( ( token = NextTok() ) != T_RIGHT )
658  {
659  if( token == T_EOF)
660  break;
661 
662  switch( token )
663  {
664  case T_center:
665  aItem->m_Hjustify = GR_TEXT_HJUSTIFY_CENTER;
666  aItem->m_Vjustify = GR_TEXT_VJUSTIFY_CENTER;
667  break;
668 
669  case T_left:
670  aItem->m_Hjustify = GR_TEXT_HJUSTIFY_LEFT;
671  break;
672 
673  case T_right:
674  aItem->m_Hjustify = GR_TEXT_HJUSTIFY_RIGHT;
675  break;
676 
677  case T_top:
678  aItem->m_Vjustify = GR_TEXT_VJUSTIFY_TOP;
679  break;
680 
681  case T_bottom:
682  aItem->m_Vjustify = GR_TEXT_VJUSTIFY_BOTTOM;
683  break;
684 
685  default:
686  Unexpected( CurText() );
687  break;
688  }
689  }
690  break;
691 
692  case T_rotate:
693  aItem->m_Orient = parseDouble();
694  NeedRIGHT();
695  break;
696 
697  default:
698  Unexpected( CurText() );
699  break;
700  }
701  }
702 }
703 
704 // parse an expression like " 25 1 ltcorner)"
706  throw( IO_ERROR, PARSE_ERROR )
707 {
708  T token;
709 
710  aCoord.m_Pos.x = parseDouble();
711  aCoord.m_Pos.y = parseDouble();
712 
713  while( ( token = NextTok() ) != T_RIGHT )
714  {
715  switch( token )
716  {
717  case T_ltcorner:
718  aCoord.m_Anchor = LT_CORNER; // left top corner
719  break;
720 
721  case T_lbcorner:
722  aCoord.m_Anchor = LB_CORNER; // left bottom corner
723  break;
724 
725  case T_rbcorner:
726  aCoord.m_Anchor = RB_CORNER; // right bottom corner
727  break;
728 
729  case T_rtcorner:
730  aCoord.m_Anchor = RT_CORNER; // right top corner
731  break;
732 
733  default:
734  Unexpected( CurText() );
735  break;
736  }
737  }
738 }
739 
740 int PAGE_LAYOUT_READER_PARSER::parseInt( int aMin, int aMax )
741 {
742  T token = NextTok();
743 
744  if( token != T_NUMBER )
745  Expecting( T_NUMBER );
746 
747  int val = atoi( CurText() );
748 
749  if( val < aMin )
750  val = aMin;
751  else if( val > aMax )
752  val = aMax;
753 
754  return val;
755 }
756 
757 
759 {
760  T token = NextTok();
761 
762  if( token != T_NUMBER )
763  Expecting( T_NUMBER );
764 
765  double val = strtod( CurText(), NULL );
766 
767  return val;
768 }
769 
770 // defaultPageLayout is the default page layout description
771 // using the S expr.
772 // see page_layout_default_shape.cpp
773 extern const char defaultPageLayout[];
774 
776 {
777  ClearList();
778  PAGE_LAYOUT_READER_PARSER lp_parser( defaultPageLayout, wxT( "default page" ) );
779 
780  try
781  {
782  lp_parser.Parse( this );
783  }
784  catch( const IO_ERROR& ioe )
785  {
786  wxLogMessage( ioe.What() );
787  }
788 }
789 
794 void WORKSHEET_LAYOUT::SetPageLayout( const char* aPageLayout, bool Append )
795 {
796  if( ! Append )
797  ClearList();
798 
799  PAGE_LAYOUT_READER_PARSER lp_parser( aPageLayout, wxT( "Sexpr_string" ) );
800 
801  try
802  {
803  lp_parser.Parse( this );
804  }
805  catch( const IO_ERROR& ioe )
806  {
807  wxLogMessage( ioe.What() );
808  }
809 }
810 
811 #include <wx/file.h>
812 
813 // SetLayout() try to load the aFullFileName custom layout file,
814 // if aFullFileName is empty, try the filename defined by the
815 // environment variable KICAD_WKSFILE (a *.kicad_wks filename).
816 // if does not exists, loads the default page layout.
817 void WORKSHEET_LAYOUT::SetPageLayout( const wxString& aFullFileName, bool Append )
818 {
819  wxString fullFileName = aFullFileName;
820 
821  if( !Append )
822  {
823  if( fullFileName.IsEmpty() )
824  wxGetEnv( wxT( "KICAD_WKSFILE" ), &fullFileName );
825 
826  if( fullFileName.IsEmpty() || !wxFileExists( fullFileName ) )
827  {
828  #if 0
829  if( !fullFileName.IsEmpty() )
830  {
831  wxLogMessage( wxT("Page layout file <%s> not found"),
832  fullFileName.GetData() );
833  }
834  #endif
836  return;
837  }
838  }
839 
840  wxFile wksFile( fullFileName );
841 
842  if( ! wksFile.IsOpened() )
843  {
844  if( !Append )
846  return;
847  }
848 
849  int filelen = wksFile.Length();
850  char * buffer = new char[filelen+10];
851 
852  if( wksFile.Read( buffer, filelen ) != filelen )
853  wxLogMessage( _("The file <%s> was not fully read"),
854  fullFileName.GetData() );
855  else
856  {
857  buffer[filelen]=0;
858 
859  if( ! Append )
860  ClearList();
861 
862  PAGE_LAYOUT_READER_PARSER pl_parser( buffer, fullFileName );
863 
864  try
865  {
866  pl_parser.Parse( this );
867  }
868  catch( const IO_ERROR& ioe )
869  {
870  wxLogMessage( ioe.What() );
871  }
872  }
873 
874  delete[] buffer;
875 }
876 
void parseCoordinate(POINT_COORD &aCoord)
int parseInt(int aMin, int aMax)
Function parseInt parses an integer and constrains it between two values.
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
void parseText(WORKSHEET_DATAITEM_TEXT *aItem)
parse a text item starting by "(tbtext" and read parameters.
description of graphic items and texts to build a title block
void readPngdata(WORKSHEET_DATAITEM_BITMAP *aItem)
double parseDouble()
Function parseDouble parses a double.
void SetDefaultLayout()
Fills the list with the default layout shape.
PAGE_LAYOUT_READER_PARSER(const char *aLine, const wxString &aSource)
This class handle bitmap images in KiCad.
static double parseDouble(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseDouble.
const char defaultPageLayout[]
void parseBitmap(WORKSHEET_DATAITEM_BITMAP *aItem)
parse a bitmap item starting by "( bitmap" and read parameters.
C++ does not put enum values in separate namespaces unless the enum itself is in a separate namespace...
void ClearList()
erase the list of items
TB_READER_T::T NextTok()
Function NextTok returns the next token found in the input file or T_EOF when reaching the end of fil...
Class PAGE_LAYOUT_READER_PARSER holds data and functions pertinent to parsing a S-expression file for...
void Expecting(int aTok)
Function Expecting throws an IO_ERROR exception with an input file specific error message...
Definition: dsnlexer.cpp:353
void parsePolyOutline(WORKSHEET_DATAITEM_POLYPOLYGON *aItem)
parse a list of corners starting by "( pts" and read coordinates.
WORKSHEET_LAYOUT handles the graphic items list to draw/plot the title block and other items (page re...
Class PAGE_LAYOUT_READER_LEXER is an automatically generated class using the TokenList2DnsLexer.cmake technology, based on keywords provided by file: /home/kicad/workspace/kicad-doxygen/common/page_layout/page_layout_reader.keywords.
static double m_DefaultTextThickness
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller's report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:94
void parseGraphic(WORKSHEET_DATAITEM *aItem)
parse a graphic item starting by "(line" or "(rect" and read parameters.
T
enum T contains all this lexer's tokens.
classes and function to generate graphics to plt or draw titles blocks and frame references ...
void Parse(WORKSHEET_LAYOUT *aLayout)
Basic classes for most KiCad items.
Class STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
const char * CurText()
Function CurText returns a pointer to the current token's text.
Definition: dsnlexer.h:479
void parsePolygon(WORKSHEET_DATAITEM_POLYPOLYGON *aItem)
parse a polygon item starting by "( polygon" and read parameters.
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
void parseSetup(WORKSHEET_LAYOUT *aLayout)
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:73
void SetPageLayout(const wxString &aFullFileName=wxEmptyString, bool Append=false)
Populates the list with a custom layout, or the default layout, if no custom layout available...
void readOption(WORKSHEET_DATAITEM *aItem)