You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1177 lines
36 KiB

// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2007-2016 Jean-Pierre Charras jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /**
  25. * @file rs274x.cpp
  26. */
  27. #include <fctsys.h>
  28. #include <common.h>
  29. #include <macros.h>
  30. #include <base_units.h>
  31. #include <gerbview.h>
  32. #include <class_gerber_file_image.h>
  33. #include <class_X2_gerber_attributes.h>
  34. extern int ReadInt( char*& text, bool aSkipSeparator = true );
  35. extern double ReadDouble( char*& text, bool aSkipSeparator = true );
  36. extern bool GetEndOfBlock( char* buff, char*& text, FILE* gerber_file );
  37. #define CODE( x, y ) ( ( (x) << 8 ) + (y) )
  38. // See rs274xrevd_e.pdf, table 1: RS-274X parameters order of entry
  39. // in gerber files, when a coordinate is given (like X78Y600 or I0J80):
  40. // Y and Y are logical coordinates
  41. // A and B are plotter coordiantes
  42. // Usually A = X, B = Y
  43. // But we can have A = Y, B = X and/or offset, mirror, scale;
  44. // Also:
  45. // Image is what you must plot (the entire data of the file).
  46. // Layer is just a set of data blocks with their parameters. An image can have more than one
  47. // layer so a gerber layer is not like a board layer or the graphic layers used in GerbView
  48. // to show a file.
  49. enum RS274X_PARAMETERS {
  50. // Directive parameters: single usage recommended
  51. // Must be at the beginning of the file
  52. AXIS_SELECT = CODE( 'A', 'S' ), // Default: A=X, B=Y
  53. FORMAT_STATEMENT = CODE( 'F', 'S' ), // no default: this command must exists
  54. MIRROR_IMAGE = CODE( 'M', 'I' ), // Default: mo mirror
  55. MODE_OF_UNITS = CODE( 'M', 'O' ), // Default: inch
  56. INCH = CODE( 'I', 'N' ),
  57. MILLIMETER = CODE( 'M', 'M' ),
  58. OFFSET = CODE( 'O', 'F' ), // Default: A = 0, B = 0
  59. SCALE_FACTOR = CODE( 'S', 'F' ), // Default: A = 1.0, B = 1.0
  60. // Image parameters:
  61. // commands used only once at the beginning of the file
  62. IMAGE_JUSTIFY = CODE( 'I', 'J' ), // Default: no justification
  63. IMAGE_NAME = CODE( 'I', 'N' ), // Default: void
  64. IMAGE_OFFSET = CODE( 'I', 'O' ), // Default: A = 0, B = 0
  65. IMAGE_POLARITY = CODE( 'I', 'P' ), // Default: Positive
  66. IMAGE_ROTATION = CODE( 'I', 'R' ), // Default: 0
  67. PLOTTER_FILM = CODE( 'P', 'M' ),
  68. // Aperture parameters:
  69. // Usually for the whole file
  70. AP_DEFINITION = CODE( 'A', 'D' ),
  71. AP_MACRO = CODE( 'A', 'M' ),
  72. // X2 extention attribute commands
  73. // Mainly are found standard attributes and user attributes
  74. // standard attributes commands are:
  75. // TF (file attribute) TO (net attribute)
  76. // TA (aperture attribute) and TD (delete aperture attribute)
  77. FILE_ATTRIBUTE = CODE( 'T', 'F' ),
  78. // X2 extention Net attribute info
  79. // Net attribute options are:
  80. // TO (net attribute data): TO.CN or TO.P TO.N or TO.C
  81. NET_ATTRIBUTE = CODE( 'T', 'O' ),
  82. // X2 extention Aperture attribute TA
  83. APERTURE_ATTRIBUTE = CODE( 'T', 'A' ),
  84. // TD (delete aperture/object attribute):
  85. // Delete aperture attribute added by %TA or Oblect attribute added b %TO
  86. // TD (delete all) or %TD<attr name> to delete <attr name>.
  87. // eg: TD.P or TD.N or TD.C ...
  88. REMOVE_APERTURE_ATTRIBUTE = CODE( 'T', 'D' ),
  89. // Layer specific parameters
  90. // May be used singly or may be layer specfic
  91. // theses parameters are at the beginning of the file or layer
  92. // and reset some layer parameters (like interpolation)
  93. LAYER_NAME = CODE( 'L', 'N' ), // Default: Positive
  94. LAYER_POLARITY = CODE( 'L', 'P' ),
  95. KNOCKOUT = CODE( 'K', 'O' ), // Default: off
  96. STEP_AND_REPEAT = CODE( 'S', 'R' ), // Default: A = 1, B = 1
  97. ROTATE = CODE( 'R', 'O' ), // Default: 0
  98. // Miscellaneous parameters:
  99. INCLUDE_FILE = CODE( 'I', 'F' )
  100. };
  101. /**
  102. * Function ReadXCommand
  103. * reads in two bytes of data and assembles them into an int with the first
  104. * byte in the sequence put into the most significant part of a 16 bit value
  105. * and the second byte put into the least significant part of the 16 bit value.
  106. * @param text A reference to a pointer to read bytes from and to advance as
  107. * they are read.
  108. * @return int - with 16 bits of data in the ls bits, upper bits zeroed.
  109. */
  110. static int ReadXCommand( char*& text )
  111. {
  112. int result;
  113. int currbyte;
  114. if( text && *text )
  115. {
  116. currbyte = *text++;
  117. result = ( currbyte & 0xFF ) << 8;
  118. }
  119. else
  120. return -1;
  121. if( text && *text )
  122. {
  123. currbyte = *text++;
  124. result += currbyte & 0xFF;
  125. }
  126. else
  127. return -1;
  128. return result;
  129. }
  130. /**
  131. * convert a string read from a gerber file to an unicode string
  132. * usual chars are just copied. \hhhh values are converted to
  133. * the unicoade char value
  134. */
  135. static const wxString fromGerberString( const wxString& aGbrString )
  136. {
  137. wxString text;
  138. for( unsigned ii = 0; ii < aGbrString.size(); ++ii )
  139. {
  140. if( aGbrString[ii] == '\\' )
  141. {
  142. unsigned value = 0;
  143. for( int jj = 0; jj < 4; jj++ )
  144. { // Convert 4 hexa digits to binary value:
  145. ii++;
  146. value <<= 4;
  147. int digit = aGbrString[ii];
  148. if( digit >= '0' && digit <= '9' )
  149. digit -= '0';
  150. else if( digit >= 'A' && digit <= 'F' )
  151. digit -= 'A' - 10;
  152. else if( digit >= 'a' && digit <= 'f' )
  153. digit -= 'a' - 10;
  154. else digit = 0;
  155. value += digit & 0xF;
  156. }
  157. text.Append( wxUniChar( value ) );
  158. }
  159. else
  160. text.Append( aGbrString[ii] );
  161. }
  162. return text;
  163. }
  164. bool GERBER_FILE_IMAGE::ReadRS274XCommand( char* buff, char*& text )
  165. {
  166. bool ok = true;
  167. int code_command;
  168. text++;
  169. for( ; ; )
  170. {
  171. while( *text )
  172. {
  173. switch( *text )
  174. {
  175. case '%': // end of command
  176. text++;
  177. m_CommandState = CMD_IDLE;
  178. goto exit; // success completion
  179. case ' ':
  180. case '\r':
  181. case '\n':
  182. text++;
  183. break;
  184. case '*':
  185. text++;
  186. break;
  187. default:
  188. code_command = ReadXCommand( text );
  189. ok = ExecuteRS274XCommand( code_command, buff, text );
  190. if( !ok )
  191. goto exit;
  192. break;
  193. }
  194. }
  195. // end of current line, read another one.
  196. if( fgets( buff, GERBER_BUFZ, m_Current_File ) == NULL )
  197. {
  198. // end of file
  199. ok = false;
  200. break;
  201. }
  202. text = buff;
  203. }
  204. exit:
  205. return ok;
  206. }
  207. bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int command, char* buff, char*& text )
  208. {
  209. int code;
  210. int seq_len; // not used, just provided
  211. int seq_char;
  212. bool ok = true;
  213. char line[GERBER_BUFZ];
  214. wxString msg;
  215. double fcoord;
  216. bool x_fmt_known = false;
  217. bool y_fmt_known = false;
  218. // conv_scale = scaling factor from inch to Internal Unit
  219. double conv_scale = IU_PER_MILS * 1000;
  220. if( m_GerbMetric )
  221. conv_scale /= 25.4;
  222. // DBG( printf( "%22s: Command <%c%c>\n", __func__, (command >> 8) & 0xFF, command & 0xFF ); )
  223. switch( command )
  224. {
  225. case FORMAT_STATEMENT:
  226. seq_len = 2;
  227. while( *text != '*' )
  228. {
  229. switch( *text )
  230. {
  231. case ' ':
  232. text++;
  233. break;
  234. case 'L': // No Leading 0
  235. m_DecimalFormat = false;
  236. m_NoTrailingZeros = false;
  237. text++;
  238. break;
  239. case 'T': // No trailing 0
  240. m_DecimalFormat = false;
  241. m_NoTrailingZeros = true;
  242. text++;
  243. break;
  244. case 'A': // Absolute coord
  245. m_Relative = false;
  246. text++;
  247. break;
  248. case 'I': // Relative coord
  249. m_Relative = true;
  250. text++;
  251. break;
  252. case 'G':
  253. case 'N': // Sequence code (followed by one digit: the sequence len)
  254. // (sometimes found before the X,Y sequence)
  255. // Obscure option
  256. text++;
  257. seq_char = *text++;
  258. if( (seq_char >= '0') && (seq_char <= '9') )
  259. seq_len = seq_char - '0';
  260. break;
  261. case 'D':
  262. case 'M': // Sequence code (followed by one digit: the sequence len)
  263. // (sometimes found after the X,Y sequence)
  264. // Obscure option
  265. code = *text++;
  266. if( ( *text >= '0' ) && ( *text<= '9' ) )
  267. text++; // skip the digit
  268. else if( code == 'D' )
  269. // Decimal format: sometimes found, but not really documented
  270. m_DecimalFormat = true;
  271. break;
  272. case 'X':
  273. case 'Y':
  274. {
  275. code = *(text++);
  276. char ctmp = *(text++) - '0';
  277. if( code == 'X' )
  278. {
  279. x_fmt_known = true;
  280. // number of digits after the decimal point (0 to 7 allowed)
  281. m_FmtScale.x = *text - '0';
  282. m_FmtLen.x = ctmp + m_FmtScale.x;
  283. // m_FmtScale is 0 to 7
  284. // (Old Gerber specification was 0 to 6)
  285. if( m_FmtScale.x < 0 )
  286. m_FmtScale.x = 0;
  287. if( m_FmtScale.x > 7 )
  288. m_FmtScale.x = 7;
  289. }
  290. else
  291. {
  292. y_fmt_known = true;
  293. m_FmtScale.y = *text - '0';
  294. m_FmtLen.y = ctmp + m_FmtScale.y;
  295. if( m_FmtScale.y < 0 )
  296. m_FmtScale.y = 0;
  297. if( m_FmtScale.y > 7 )
  298. m_FmtScale.y = 7;
  299. }
  300. text++;
  301. }
  302. break;
  303. case '*':
  304. break;
  305. default:
  306. msg.Printf( wxT( "Unknown id (%c) in FS command" ),
  307. *text );
  308. AddMessageToList( msg );
  309. GetEndOfBlock( buff, text, m_Current_File );
  310. ok = false;
  311. break;
  312. }
  313. }
  314. if( !x_fmt_known || !y_fmt_known )
  315. AddMessageToList( wxT( "RS274X: Format Statement (FS) without X or Y format" ) );
  316. break;
  317. case AXIS_SELECT: // command ASAXBY*% or %ASAYBX*%
  318. m_SwapAxis = false;
  319. if( strnicmp( text, "AYBX", 4 ) == 0 )
  320. m_SwapAxis = true;
  321. break;
  322. case MIRROR_IMAGE: // command %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*%
  323. m_MirrorA = m_MirrorB = 0;
  324. while( *text && *text != '*' )
  325. {
  326. switch( *text )
  327. {
  328. case 'A': // Mirror A axis ?
  329. text++;
  330. if( *text == '1' )
  331. m_MirrorA = true;
  332. break;
  333. case 'B': // Mirror B axis ?
  334. text++;
  335. if( *text == '1' )
  336. m_MirrorB = true;
  337. break;
  338. default:
  339. text++;
  340. break;
  341. }
  342. }
  343. break;
  344. case MODE_OF_UNITS:
  345. code = ReadXCommand( text );
  346. if( code == INCH )
  347. m_GerbMetric = false;
  348. else if( code == MILLIMETER )
  349. m_GerbMetric = true;
  350. conv_scale = m_GerbMetric ? IU_PER_MILS / 25.4 : IU_PER_MILS;
  351. break;
  352. case FILE_ATTRIBUTE: // Command %TF ...
  353. m_IsX2_file = true;
  354. {
  355. X2_ATTRIBUTE dummy;
  356. dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
  357. if( dummy.IsFileFunction() )
  358. {
  359. delete m_FileFunction;
  360. m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy );
  361. }
  362. else if( dummy.IsFileMD5() )
  363. {
  364. m_MD5_value = dummy.GetPrm( 1 );
  365. }
  366. else if( dummy.IsFilePart() )
  367. {
  368. m_PartString = dummy.GetPrm( 1 );
  369. }
  370. }
  371. break;
  372. case APERTURE_ATTRIBUTE: // Command %TA ... Not yet supported
  373. {
  374. X2_ATTRIBUTE dummy;
  375. dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
  376. if( dummy.GetAttribute() == ".AperFunction" )
  377. {
  378. m_AperFunction = dummy.GetPrm( 1 );
  379. // A few function values can have other parameters. Add them
  380. for( int ii = 2; ii < dummy.GetPrmCount(); ii++ )
  381. m_AperFunction << "," << dummy.GetPrm( ii );
  382. }
  383. }
  384. break;
  385. case NET_ATTRIBUTE: // Command %TO currently %TO.P %TO.N and %TO.C
  386. {
  387. X2_ATTRIBUTE dummy;
  388. dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
  389. if( dummy.GetAttribute() == ".N" )
  390. {
  391. m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_NET;
  392. m_NetAttributeDict.m_Netname = fromGerberString( dummy.GetPrm( 1 ) );
  393. }
  394. else if( dummy.GetAttribute() == ".C" )
  395. {
  396. m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_CMP;
  397. m_NetAttributeDict.m_Cmpref = fromGerberString( dummy.GetPrm( 1 ) );
  398. }
  399. else if( dummy.GetAttribute() == ".P" )
  400. {
  401. m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_PAD;
  402. m_NetAttributeDict.m_Cmpref = fromGerberString( dummy.GetPrm( 1 ) );
  403. m_NetAttributeDict.m_Padname = fromGerberString( dummy.GetPrm( 2 ) );
  404. }
  405. }
  406. break;
  407. case REMOVE_APERTURE_ATTRIBUTE: // Command %TD ...
  408. {
  409. X2_ATTRIBUTE dummy;
  410. dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
  411. RemoveAttribute( dummy );
  412. }
  413. break;
  414. case OFFSET: // command: OFAnnBnn (nn = float number) = layer Offset
  415. m_Offset.x = m_Offset.y = 0;
  416. while( *text != '*' )
  417. {
  418. switch( *text )
  419. {
  420. case 'A': // A axis offset in current unit (inch or mm)
  421. text++;
  422. fcoord = ReadDouble( text );
  423. m_Offset.x = KiROUND( fcoord * conv_scale );
  424. break;
  425. case 'B': // B axis offset in current unit (inch or mm)
  426. text++;
  427. fcoord = ReadDouble( text );
  428. m_Offset.y = KiROUND( fcoord * conv_scale );
  429. break;
  430. }
  431. }
  432. break;
  433. case SCALE_FACTOR:
  434. m_Scale.x = m_Scale.y = 1.0;
  435. while( *text != '*' )
  436. {
  437. switch( *text )
  438. {
  439. case 'A': // A axis scale
  440. text++;
  441. m_Scale.x = ReadDouble( text );
  442. break;
  443. case 'B': // B axis scale
  444. text++;
  445. m_Scale.y = ReadDouble( text );
  446. break;
  447. }
  448. }
  449. break;
  450. case IMAGE_OFFSET: // command: IOAnnBnn (nn = float number) = Image Offset
  451. m_ImageOffset.x = m_ImageOffset.y = 0;
  452. while( *text != '*' )
  453. {
  454. switch( *text )
  455. {
  456. case 'A': // A axis offset in current unit (inch or mm)
  457. text++;
  458. fcoord = ReadDouble( text );
  459. m_ImageOffset.x = KiROUND( fcoord * conv_scale );
  460. break;
  461. case 'B': // B axis offset in current unit (inch or mm)
  462. text++;
  463. fcoord = ReadDouble( text );
  464. m_ImageOffset.y = KiROUND( fcoord * conv_scale );
  465. break;
  466. }
  467. }
  468. break;
  469. case IMAGE_ROTATION: // command IR0* or IR90* or IR180* or IR270*
  470. if( strnicmp( text, "0*", 2 ) == 0 )
  471. m_ImageRotation = 0;
  472. else if( strnicmp( text, "90*", 3 ) == 0 )
  473. m_ImageRotation = 90;
  474. else if( strnicmp( text, "180*", 4 ) == 0 )
  475. m_ImageRotation = 180;
  476. else if( strnicmp( text, "270*", 4 ) == 0 )
  477. m_ImageRotation = 270;
  478. else
  479. AddMessageToList( _( "RS274X: Command \"IR\" rotation value not allowed" ) );
  480. break;
  481. case STEP_AND_REPEAT: // command SR, like %SRX3Y2I5.0J2*%
  482. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
  483. GetLayerParams().m_StepForRepeat.x = 0.0;
  484. GetLayerParams().m_StepForRepeat.x = 0.0; // offset for Step and Repeat command
  485. GetLayerParams().m_XRepeatCount = 1;
  486. GetLayerParams().m_YRepeatCount = 1; // The repeat count
  487. GetLayerParams().m_StepForRepeatMetric = m_GerbMetric; // the step units
  488. while( *text && *text != '*' )
  489. {
  490. switch( *text )
  491. {
  492. case 'I': // X axis offset
  493. text++;
  494. GetLayerParams().m_StepForRepeat.x = ReadDouble( text );
  495. break;
  496. case 'J': // Y axis offset
  497. text++;
  498. GetLayerParams().m_StepForRepeat.y = ReadDouble( text );
  499. break;
  500. case 'X': // X axis repeat count
  501. text++;
  502. GetLayerParams().m_XRepeatCount = ReadInt( text );
  503. break;
  504. case 'Y': // Y axis offset
  505. text++;
  506. GetLayerParams().m_YRepeatCount = ReadInt( text );
  507. break;
  508. default:
  509. text++;
  510. break;
  511. }
  512. }
  513. break;
  514. case IMAGE_JUSTIFY: // Command IJAnBn*
  515. m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false)
  516. m_ImageJustifyYCenter = false; // Image Justify Center on Y axis (default = false)
  517. m_ImageJustifyOffset = wxPoint(0,0); // Image Justify Offset on XY axis (default = 0,0)
  518. while( *text && *text != '*' )
  519. {
  520. // IJ command is (for A or B axis) AC or AL or A<coordinate>
  521. switch( *text )
  522. {
  523. case 'A': // A axis justify
  524. text++;
  525. if( *text == 'C' )
  526. {
  527. m_ImageJustifyXCenter = true;
  528. text++;
  529. }
  530. else if( *text == 'L' )
  531. {
  532. m_ImageJustifyXCenter = true;
  533. text++;
  534. }
  535. else m_ImageJustifyOffset.x = KiROUND( ReadDouble( text ) * conv_scale);
  536. break;
  537. case 'B': // B axis justify
  538. text++;
  539. if( *text == 'C' )
  540. {
  541. m_ImageJustifyYCenter = true;
  542. text++;
  543. }
  544. else if( *text == 'L' )
  545. {
  546. m_ImageJustifyYCenter = true;
  547. text++;
  548. }
  549. else m_ImageJustifyOffset.y = KiROUND( ReadDouble( text ) * conv_scale);
  550. break;
  551. default:
  552. text++;
  553. break;
  554. }
  555. }
  556. if( m_ImageJustifyXCenter )
  557. m_ImageJustifyOffset.x = 0;
  558. if( m_ImageJustifyYCenter )
  559. m_ImageJustifyOffset.y = 0;
  560. break;
  561. case KNOCKOUT:
  562. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
  563. msg = _( "RS274X: Command KNOCKOUT ignored by GerbView" ) ;
  564. AddMessageToList( msg );
  565. break;
  566. case PLOTTER_FILM: // Command PF <string>
  567. // This is an info about film that must be used to plot this file
  568. // Has no meaning here. We just display this string
  569. msg = wxT( "Plotter Film info:<br>" );
  570. while( *text != '*' )
  571. {
  572. msg.Append( *text++ );
  573. }
  574. AddMessageToList( msg );
  575. break;
  576. case ROTATE: // Layer rotation: command like %RO45*%
  577. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
  578. m_LocalRotation =ReadDouble( text ); // Store layer rotation in degrees
  579. break;
  580. case IMAGE_NAME:
  581. m_ImageName.Empty();
  582. while( *text != '*' )
  583. {
  584. m_ImageName.Append( *text++ );
  585. }
  586. break;
  587. case LAYER_NAME:
  588. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
  589. GetLayerParams( ).m_LayerName.Empty();
  590. while( *text != '*' )
  591. {
  592. GetLayerParams( ).m_LayerName.Append( *text++ );
  593. }
  594. break;
  595. case IMAGE_POLARITY:
  596. if( strnicmp( text, "NEG", 3 ) == 0 )
  597. m_ImageNegative = true;
  598. else
  599. m_ImageNegative = false;
  600. DBG( printf( "%22s: IMAGE_POLARITY m_ImageNegative=%s\n", __func__,
  601. m_ImageNegative ? "true" : "false" ); )
  602. break;
  603. case LAYER_POLARITY:
  604. if( *text == 'C' )
  605. GetLayerParams().m_LayerNegative = true;
  606. else
  607. GetLayerParams().m_LayerNegative = false;
  608. // DBG( printf( "%22s: LAYER_POLARITY m_LayerNegative=%s\n", __func__,
  609. // GetLayerParams().m_LayerNegative ? "true" : "false" ); )
  610. break;
  611. case INCLUDE_FILE:
  612. if( m_FilesPtr >= INCLUDE_FILES_CNT_MAX )
  613. {
  614. ok = false;
  615. AddMessageToList( _( "Too many include files!!" ) );
  616. break;
  617. }
  618. strncpy( line, text, sizeof(line)-1 );
  619. line[sizeof(line)-1] = '\0';
  620. strtok( line, "*%%\n\r" );
  621. m_FilesList[m_FilesPtr] = m_Current_File;
  622. m_Current_File = fopen( line, "rt" );
  623. if( m_Current_File == 0 )
  624. {
  625. msg.Printf( wxT( "include file <%s> not found." ), line );
  626. AddMessageToList( msg );
  627. ok = false;
  628. m_Current_File = m_FilesList[m_FilesPtr];
  629. break;
  630. }
  631. m_FilesPtr++;
  632. break;
  633. case AP_MACRO: // lines like %AMMYMACRO*
  634. // 5,1,8,0,0,1.08239X$1,22.5*
  635. // %
  636. /*ok = */ReadApertureMacro( buff, text, m_Current_File );
  637. break;
  638. case AP_DEFINITION:
  639. /* input example: %ADD30R,0.081800X0.101500*%
  640. * Aperture definition has 4 options: C, R, O, P
  641. * (Circle, Rect, Oval, regular Polygon)
  642. * and shapes can have a hole (round or rectangular).
  643. * All optional parameters values start by X
  644. * at this point, text points to 2nd 'D'
  645. */
  646. if( *text++ != 'D' )
  647. {
  648. ok = false;
  649. break;
  650. }
  651. m_Has_DCode = true;
  652. code = ReadInt( text );
  653. D_CODE* dcode;
  654. dcode = GetDCODE( code );
  655. if( dcode == NULL )
  656. break;
  657. dcode->m_AperFunction = m_AperFunction;
  658. // at this point, text points to character after the ADD<num>,
  659. // i.e. R in example above. If text[0] is one of the usual
  660. // apertures: (C,R,O,P), there is a comma after it.
  661. if( text[1] == ',' )
  662. {
  663. char stdAperture = *text;
  664. text += 2; // skip "C," for example
  665. dcode->m_Size.x = KiROUND( ReadDouble( text ) * conv_scale );
  666. dcode->m_Size.y = dcode->m_Size.x;
  667. switch( stdAperture ) // Aperture desceiption has optional parameters. Read them
  668. {
  669. case 'C': // Circle
  670. dcode->m_Shape = APT_CIRCLE;
  671. while( *text == ' ' )
  672. text++;
  673. if( *text == 'X' )
  674. {
  675. text++;
  676. dcode->m_Drill.x = dcode->m_Drill.y =
  677. KiROUND( ReadDouble( text ) * conv_scale );
  678. dcode->m_DrillShape = APT_DEF_ROUND_HOLE;
  679. }
  680. while( *text == ' ' )
  681. text++;
  682. if( *text == 'X' )
  683. {
  684. text++;
  685. dcode->m_Drill.y =
  686. KiROUND( ReadDouble( text ) * conv_scale );
  687. dcode->m_DrillShape = APT_DEF_RECT_HOLE;
  688. }
  689. dcode->m_Defined = true;
  690. break;
  691. case 'O': // oval
  692. case 'R': // rect
  693. dcode->m_Shape = (stdAperture == 'O') ? APT_OVAL : APT_RECT;
  694. while( *text == ' ' )
  695. text++;
  696. if( *text == 'X' )
  697. {
  698. text++;
  699. dcode->m_Size.y =
  700. KiROUND( ReadDouble( text ) * conv_scale );
  701. }
  702. while( *text == ' ' )
  703. text++;
  704. if( *text == 'X' )
  705. {
  706. text++;
  707. dcode->m_Drill.x = KiROUND( ReadDouble( text ) * conv_scale );
  708. dcode->m_Drill.y = dcode->m_Drill.x;
  709. dcode->m_DrillShape = APT_DEF_ROUND_HOLE;
  710. }
  711. while( *text == ' ' )
  712. text++;
  713. if( *text == 'X' )
  714. {
  715. text++;
  716. dcode->m_Drill.y =
  717. KiROUND( ReadDouble( text ) * conv_scale );
  718. dcode->m_DrillShape = APT_DEF_RECT_HOLE;
  719. }
  720. dcode->m_Defined = true;
  721. break;
  722. case 'P':
  723. /* Regular polygon: a command line like %ADD12P,0.040X10X25X0.025X0.025X0.0150*%
  724. * params are: <diameter>, X<edge count>, X<Rotation>, X<X hole dim>, X<Y hole dim>
  725. */
  726. dcode->m_Shape = APT_POLYGON;
  727. while( *text == ' ' )
  728. text++;
  729. if( *text == 'X' )
  730. {
  731. text++;
  732. dcode->m_EdgesCount = ReadInt( text );
  733. }
  734. while( *text == ' ' )
  735. text++;
  736. if( *text == 'X' )
  737. {
  738. text++;
  739. dcode->m_Rotation = ReadDouble( text );
  740. }
  741. while( *text == ' ' )
  742. text++;
  743. if( *text == 'X' )
  744. {
  745. text++;
  746. dcode->m_Drill.x = KiROUND( ReadDouble( text ) * conv_scale );
  747. dcode->m_Drill.y = dcode->m_Drill.x =
  748. dcode->m_DrillShape = APT_DEF_ROUND_HOLE;
  749. }
  750. while( *text == ' ' )
  751. text++;
  752. if( *text == 'X' )
  753. {
  754. text++;
  755. dcode->m_Drill.y = KiROUND( ReadDouble( text ) * conv_scale );
  756. dcode->m_DrillShape = APT_DEF_RECT_HOLE;
  757. }
  758. dcode->m_Defined = true;
  759. break;
  760. }
  761. }
  762. else // text[0] starts an aperture macro name
  763. {
  764. APERTURE_MACRO am_lookup;
  765. while( *text && *text != '*' && *text != ',' )
  766. am_lookup.name.Append( *text++ );
  767. // When an aperture definition is like %AMLINE2* 22,1,$1,$2,0,0,-45*
  768. // the ADDxx<MACRO_NAME> command has parameters, like %ADD14LINE2,0.8X0.5*%
  769. if( *text == ',' )
  770. { // Read aperture macro parameters and store them
  771. text++; // text points the first parameter
  772. while( *text && *text != '*' )
  773. {
  774. double param = ReadDouble( text );
  775. dcode->AppendParam( param );
  776. while( isspace( *text ) ) text++;
  777. if( *text == 'X' )
  778. ++text;
  779. }
  780. }
  781. // lookup the aperture macro here.
  782. APERTURE_MACRO* pam = FindApertureMacro( am_lookup );
  783. if( !pam )
  784. {
  785. msg.Printf( wxT( "RS274X: aperture macro %s not found\n" ),
  786. TO_UTF8( am_lookup.name ) );
  787. AddMessageToList( msg );
  788. ok = false;
  789. break;
  790. }
  791. dcode->m_Shape = APT_MACRO;
  792. dcode->SetMacro( pam );
  793. }
  794. break;
  795. default:
  796. ok = false;
  797. break;
  798. }
  799. (void) seq_len; // quiet g++, or delete the unused variable.
  800. ok = GetEndOfBlock( buff, text, m_Current_File );
  801. return ok;
  802. }
  803. bool GetEndOfBlock( char* buff, char*& text, FILE* gerber_file )
  804. {
  805. for( ; ; )
  806. {
  807. while( (text < buff + GERBER_BUFZ) && *text )
  808. {
  809. if( *text == '*' )
  810. return true;
  811. if( *text == '%' )
  812. return true;
  813. text++;
  814. }
  815. if( fgets( buff, GERBER_BUFZ, gerber_file ) == NULL )
  816. break;
  817. text = buff;
  818. }
  819. return false;
  820. }
  821. /**
  822. * Function GetNextLine
  823. * test for an end of line
  824. * if an end of line is found:
  825. * read a new line
  826. * @param aBuff = buffer (size = GERBER_BUFZ) to fill with a new line
  827. * @param aText = pointer to the last useful char in aBuff
  828. * on return: points the beginning of the next line.
  829. * @param aFile = the opened GERBER file to read
  830. * @return a pointer to the beginning of the next line or NULL if end of file
  831. */
  832. static char* GetNextLine( char *aBuff, char* aText, FILE* aFile )
  833. {
  834. for( ; ; )
  835. {
  836. switch (*aText )
  837. {
  838. case ' ': // skip blanks
  839. case '\n':
  840. case '\r': // Skip line terminators
  841. ++aText;
  842. break;
  843. case 0: // End of text found in aBuff: Read a new string
  844. if( fgets( aBuff, GERBER_BUFZ, aFile ) == NULL )
  845. return NULL;
  846. aText = aBuff;
  847. return aText;
  848. default:
  849. return aText;
  850. }
  851. }
  852. return aText;
  853. }
  854. bool GERBER_FILE_IMAGE::ReadApertureMacro( char *buff,
  855. char*& text,
  856. FILE* gerber_file )
  857. {
  858. wxString msg;
  859. APERTURE_MACRO am;
  860. // read macro name
  861. while( *text )
  862. {
  863. if( *text == '*' )
  864. {
  865. ++text;
  866. break;
  867. }
  868. am.name.Append( *text++ );
  869. }
  870. // Read aperture macro parameters
  871. for( ; ; )
  872. {
  873. if( *text == '*' )
  874. ++text;
  875. text = GetNextLine( buff, text, gerber_file ); // Get next line
  876. if( text == NULL ) // End of File
  877. return false;
  878. // text points the beginning of a new line.
  879. // Test for the last line in aperture macro lis:
  880. // last line is % or *% sometime found.
  881. if( *text == '*' )
  882. ++text;
  883. if( *text == '%' )
  884. break; // exit with text still pointing at %
  885. int paramCount = 0;
  886. int primitive_type = AMP_UNKNOWN;
  887. // Test for a valid symbol at the beginning of a description:
  888. // it can be: a parameter declaration like $1=$2/4
  889. // or a digit (macro primitive selection)
  890. // all other symbols are illegal.
  891. if( *text == '$' ) // local parameter declaration, inside the aperture macro
  892. {
  893. am.m_localparamStack.push_back( AM_PARAM() );
  894. AM_PARAM& param = am.m_localparamStack.back();
  895. text = GetNextLine( buff, text, gerber_file );
  896. if( text == NULL) // End of File
  897. return false;
  898. param.ReadParam( text );
  899. continue;
  900. }
  901. else if( !isdigit(*text) ) // Ill. symbol
  902. {
  903. msg.Printf( wxT( "RS274X: Aperture Macro \"%s\": ill. symbol, line: \"%s\"" ),
  904. GetChars( am.name ), GetChars( FROM_UTF8( buff ) ) );
  905. AddMessageToList( msg );
  906. primitive_type = AMP_COMMENT;
  907. }
  908. else
  909. primitive_type = ReadInt( text );
  910. switch( primitive_type )
  911. {
  912. case AMP_COMMENT: // lines starting by 0 are a comment
  913. paramCount = 0;
  914. // Skip comment
  915. while( *text && (*text != '*') )
  916. text++;
  917. break;
  918. case AMP_CIRCLE:
  919. paramCount = 4;
  920. break;
  921. case AMP_LINE2:
  922. case AMP_LINE20:
  923. paramCount = 7;
  924. break;
  925. case AMP_LINE_CENTER:
  926. case AMP_LINE_LOWER_LEFT:
  927. paramCount = 6;
  928. break;
  929. case AMP_EOF:
  930. paramCount = 0;
  931. break;
  932. case AMP_OUTLINE:
  933. paramCount = 4;
  934. break;
  935. case AMP_POLYGON:
  936. paramCount = 6;
  937. break;
  938. case AMP_MOIRE:
  939. paramCount = 9;
  940. break;
  941. case AMP_THERMAL:
  942. paramCount = 6;
  943. break;
  944. default:
  945. // @todo, there needs to be a way of reporting the line number
  946. msg.Printf( wxT( "RS274X: Aperture Macro \"%s\": Invalid primitive id code %d, line: \"%s\"" ),
  947. GetChars( am.name ), primitive_type, GetChars( FROM_UTF8( buff ) ) );
  948. AddMessageToList( msg );
  949. return false;
  950. }
  951. AM_PRIMITIVE prim( m_GerbMetric );
  952. prim.primitive_id = (AM_PRIMITIVE_ID) primitive_type;
  953. int ii;
  954. for( ii = 0; ii < paramCount && *text && *text != '*'; ++ii )
  955. {
  956. prim.params.push_back( AM_PARAM() );
  957. AM_PARAM& param = prim.params.back();
  958. text = GetNextLine( buff, text, gerber_file );
  959. if( text == NULL) // End of File
  960. return false;
  961. param.ReadParam( text );
  962. }
  963. if( ii < paramCount )
  964. {
  965. // maybe some day we can throw an exception and track a line number
  966. msg.Printf( wxT( "RS274X: read macro descr type %d: read %d parameters, insufficient parameters\n" ),
  967. prim.primitive_id, ii );
  968. AddMessageToList( msg );
  969. }
  970. // there are more parameters to read if this is an AMP_OUTLINE
  971. if( prim.primitive_id == AMP_OUTLINE )
  972. {
  973. // so far we have read [0]:exposure, [1]:#points, [2]:X start, [3]: Y start
  974. // Now read all the points, plus trailing rotation in degrees.
  975. // params[1] is a count of polygon points, so it must be given
  976. // in advance, i.e. be immediate.
  977. wxASSERT( prim.params[1].IsImmediate() );
  978. paramCount = (int) prim.params[1].GetValue( 0 ) * 2 + 1;
  979. for( int jj = 0; jj < paramCount && *text != '*'; ++jj )
  980. {
  981. prim.params.push_back( AM_PARAM() );
  982. AM_PARAM& param = prim.params.back();
  983. text = GetNextLine( buff, text, gerber_file );
  984. if( text == NULL ) // End of File
  985. return false;
  986. param.ReadParam( text );
  987. }
  988. }
  989. am.primitives.push_back( prim );
  990. }
  991. m_aperture_macros.insert( am );
  992. return true;
  993. }