Commit df29e89c authored by dickelbeck's avatar dickelbeck

beginnings of aperture macro support

parent a2a02496
This diff is collapsed.
...@@ -85,7 +85,7 @@ void WinEDA_GerberFrame::Process_Special_Functions( wxCommandEvent& event ) ...@@ -85,7 +85,7 @@ void WinEDA_GerberFrame::Process_Special_Functions( wxCommandEvent& event )
{ {
int id = event.GetId(); int id = event.GetId();
int layer = GetScreen()->m_Active_Layer; int layer = GetScreen()->m_Active_Layer;
GERBER_Descr* gerber_layer = g_GERBER_Descr_List[layer]; GERBER* gerber_layer = g_GERBER_List[layer];
wxPoint pos; wxPoint pos;
wxClientDC dc( DrawPanel ); wxClientDC dc( DrawPanel );
......
...@@ -31,7 +31,7 @@ void WinEDA_GerberFrame::ExportDataInPcbnewFormat( wxCommandEvent& event ) ...@@ -31,7 +31,7 @@ void WinEDA_GerberFrame::ExportDataInPcbnewFormat( wxCommandEvent& event )
// Check whether any of the Gerber layers are actually currently used // Check whether any of the Gerber layers are actually currently used
while( no_used_layers && ii < 32 ) while( no_used_layers && ii < 32 )
{ {
if( g_GERBER_Descr_List[ii] != NULL ) if( g_GERBER_List[ii] != NULL )
no_used_layers = false; no_used_layers = false;
ii++; ii++;
} }
...@@ -152,7 +152,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile, ...@@ -152,7 +152,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile,
int pcb_layer_number = LayerLookUpTable[layer]; int pcb_layer_number = LayerLookUpTable[layer];
if( pcb_layer_number < 0 || pcb_layer_number > LAST_NO_COPPER_LAYER ) if( pcb_layer_number < 0 || pcb_layer_number > LAST_NO_COPPER_LAYER )
continue; continue;
if( pcb_layer_number > LAST_COPPER_LAYER ) if( pcb_layer_number > LAST_COPPER_LAYER )
{ {
DRAWSEGMENT* drawitem = new DRAWSEGMENT( pcb, TYPEDRAWSEGMENT ); DRAWSEGMENT* drawitem = new DRAWSEGMENT( pcb, TYPEDRAWSEGMENT );
...@@ -167,7 +167,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile, ...@@ -167,7 +167,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile,
else else
{ {
TRACK* newtrack; TRACK* newtrack;
// replace spots with vias when possible // replace spots with vias when possible
if( track->m_Shape == S_SPOT_CIRCLE if( track->m_Shape == S_SPOT_CIRCLE
|| track->m_Shape == S_SPOT_RECT || track->m_Shape == S_SPOT_RECT
...@@ -178,13 +178,13 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile, ...@@ -178,13 +178,13 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile,
// A spot is found, and can be a via: change it to via, and delete other // A spot is found, and can be a via: change it to via, and delete other
// spots at same location // spots at same location
newtrack->m_Shape = VIA_THROUGH; newtrack->m_Shape = VIA_THROUGH;
newtrack->SetLayer( 0x0F ); // Layers are 0 to 15 (Cu/Cmp) newtrack->SetLayer( 0x0F ); // Layers are 0 to 15 (Cu/Cmp)
newtrack->SetDrillDefault(); newtrack->SetDrillDefault();
// Compute the via position from track position ( Via position is the // Compute the via position from track position ( Via position is the
// position of the middle of the track segment ) // position of the middle of the track segment )
newtrack->m_Start.x = (newtrack->m_Start.x + newtrack->m_End.x) / 2; newtrack->m_Start.x = (newtrack->m_Start.x + newtrack->m_End.x) / 2;
newtrack->m_Start.y = (newtrack->m_Start.y + newtrack->m_End.y) / 2; newtrack->m_Start.y = (newtrack->m_Start.y + newtrack->m_End.y) / 2;
newtrack->m_End = newtrack->m_Start; newtrack->m_End = newtrack->m_Start;
...@@ -194,7 +194,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile, ...@@ -194,7 +194,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile,
newtrack = track->Copy(); newtrack = track->Copy();
newtrack->SetLayer( pcb_layer_number ); newtrack->SetLayer( pcb_layer_number );
} }
newtrack->Insert( pcb, NULL ); newtrack->Insert( pcb, NULL );
} }
} }
...@@ -204,7 +204,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile, ...@@ -204,7 +204,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile,
{ {
if( track->m_Shape != VIA_THROUGH ) if( track->m_Shape != VIA_THROUGH )
continue; continue;
// Search and delete others vias // Search and delete others vias
TRACK* next_track; TRACK* next_track;
TRACK* alt_track = track->Next(); TRACK* alt_track = track->Next();
...@@ -225,7 +225,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile, ...@@ -225,7 +225,7 @@ static int SavePcbFormatAscii( WinEDA_GerberFrame* frame, FILE* aFile,
// Switch the locale to standard C (needed to print floating point numbers like 1.3) // Switch the locale to standard C (needed to print floating point numbers like 1.3)
SetLocaleTo_C_standard( ); SetLocaleTo_C_standard( );
// write the PCB heading // write the PCB heading
fprintf( aFile, "PCBNEW-BOARD Version %d date %s\n\n", g_CurrentVersionPCB, fprintf( aFile, "PCBNEW-BOARD Version %d date %s\n\n", g_CurrentVersionPCB,
DateAndTime( line ) ); DateAndTime( line ) );
......
...@@ -209,7 +209,7 @@ void WinEDA_GerberFrame::SetToolbars() ...@@ -209,7 +209,7 @@ void WinEDA_GerberFrame::SetToolbars()
*/ */
{ {
int layer = ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer; int layer = ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer;
GERBER_Descr* Gerber_layer_descr = g_GERBER_Descr_List[layer]; GERBER* gerber = g_GERBER_List[layer];
if( m_HToolBar == NULL ) if( m_HToolBar == NULL )
return; return;
...@@ -242,14 +242,14 @@ void WinEDA_GerberFrame::SetToolbars() ...@@ -242,14 +242,14 @@ void WinEDA_GerberFrame::SetToolbars()
m_SelLayerBox->SetSelection( ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer ); m_SelLayerBox->SetSelection( ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer );
} }
if( Gerber_layer_descr ) if( gerber )
{ {
int sel_index; int sel_index;
m_SelLayerTool->Enable( TRUE ); m_SelLayerTool->Enable( TRUE );
if( Gerber_layer_descr->m_Selected_Tool < FIRST_DCODE ) // No tool selected if( gerber->m_Selected_Tool < FIRST_DCODE ) // No tool selected
sel_index = 0; sel_index = 0;
else else
sel_index = Gerber_layer_descr->m_Selected_Tool - FIRST_DCODE + 1; sel_index = gerber->m_Selected_Tool - FIRST_DCODE + 1;
if( sel_index != m_SelLayerTool->GetSelection() ) if( sel_index != m_SelLayerTool->GetSelection() )
{ {
......
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
#ifndef GERBVIEW_H #ifndef GERBVIEW_H
#define GERBVIEW_H #define GERBVIEW_H
#include <vector>
#include <set>
#ifndef eda_global #ifndef eda_global
#define eda_global extern #define eda_global extern
#endif #endif
...@@ -21,6 +25,7 @@ typedef enum { ...@@ -21,6 +25,7 @@ typedef enum {
FORMAT_POST FORMAT_POST
} PlotFormat; } PlotFormat;
//eda_global wxString g_Plot_FileName; //eda_global wxString g_Plot_FileName;
eda_global wxString g_PhotoFilenameExt; eda_global wxString g_PhotoFilenameExt;
eda_global wxString g_DrillFilenameExt; eda_global wxString g_DrillFilenameExt;
...@@ -38,7 +43,22 @@ eda_global int g_Plot_Spot_Mini; /* Diametre mini de l'ouverture pour ...@@ -38,7 +43,22 @@ eda_global int g_Plot_Spot_Mini; /* Diametre mini de l'ouverture pour
/* Constantes utiles en trace GERBER */ /* Constantes utiles en trace GERBER */
/*************************************/ /*************************************/
/* codes de type de forme d'outils */ /**
* Enum APERTURE_T
* is the set of all gerber aperture types allowed, according to page 16 of
* http://gerbv.sourceforge.net/docs/rs274xrevd_e.pdf
*/
enum APERTURE_T
{
APT_CIRCLE = 'C',
APT_LINE = 'L',
APT_RECT = 'R',
APT_OVAL = '0',
APT_POLYGON = 'P',
APT_MACRO = 'M'
};
/* replaced by APERTURE_T
enum Gerb_StandardShape { enum Gerb_StandardShape {
GERB_CIRCLE = 1, GERB_CIRCLE = 1,
GERB_RECT, GERB_RECT,
...@@ -46,6 +66,8 @@ enum Gerb_StandardShape { ...@@ -46,6 +66,8 @@ enum Gerb_StandardShape {
GERB_OVALE, GERB_OVALE,
GERB_SPECIAL_SHAPE GERB_SPECIAL_SHAPE
}; };
*/
// Interpolation type // Interpolation type
enum Gerb_Interpolation { enum Gerb_Interpolation {
...@@ -90,18 +112,132 @@ enum Gerb_Analyse_Cmd { ...@@ -90,18 +112,132 @@ enum Gerb_Analyse_Cmd {
}; };
class D_CODE; /**
* Struct DCODE_PARAM
* holds a parameter for a DCODE or an "aperture macro" as defined within standard RS274X.
* The \a value field can be either a constant or a place holder for a DCODE
* parameter.
*/
struct DCODE_PARAM
{
DCODE_PARAM() :
isImmediate(true),
value(0.0)
{}
bool isImmediate; ///< the \a value field is an actual value, not a parameter place holder.
double value; ///< if immediate then the value, else an integer index into D_CODE.m_am_params.
};
/**
* Enum AM_PRIMITIVE_ID
* is the set of all "aperture macro primitives" (primitive numbers). See
* Table 3 in http://gerbv.sourceforge.net/docs/rs274xrevd_e.pdf
*/
enum AM_PRIMITIVE_ID
{
AMP_CIRCLE = 1,
AMP_LINE2 = 2,
AMP_LINE20 = 20,
AMP_LINE_CENTER = 21,
AMP_LINE_LOWER_LEFT = 22,
AMP_EOF = 3,
AMP_OUTLINE = 4,
AMP_POLYGON = 5,
AMP_MOIRE = 6,
AMP_THERMAL = 7,
};
typedef std::vector<DCODE_PARAM> DCODE_PARAMS;
/** /**
* Class GERBER_Descr * Struct AM_PRIMITIVE
* holds an aperture macro primitive as given in Table 3 of
* http://gerbv.sourceforge.net/docs/rs274xrevd_e.pdf
*/
struct AM_PRIMITIVE
{
AM_PRIMITIVE_ID primitive_id;
DCODE_PARAMS params;
};
typedef std::vector<AM_PRIMITIVE> AM_PRIMITIVES;
/**
* Struct APERTURE_MACRO
* helps support the "aperture macro" defined within standard RS274X.
*/
struct APERTURE_MACRO
{
wxString name;
AM_PRIMITIVES primitives;
};
/**
* Struct APERTURE_MACRO_less_than
* is used by std:set<APERTURE_MACRO> instantiation which uses APERTURE_MACRO.name as its key.
*/
struct APERTURE_MACRO_less_than
{
// a "less than" test on two wxStrings
bool operator()( const APERTURE_MACRO& am1, const APERTURE_MACRO& am2) const
{
return am1.name.Cmp( am2.name ) < 0; // case specific wxString compare
}
};
/**
* Type APERTURE_MACRO_SET
* is a sorted collection of APERTURE_MACROS whose key is the name field in
* the APERTURE_MACRO.
*/
typedef std::set<APERTURE_MACRO, APERTURE_MACRO_less_than> APERTURE_MACRO_SET;
typedef std::pair<APERTURE_MACRO_SET::iterator, bool> APERTURE_MACRO_SET_PAIR;
/**
* Class D_CODE
* holds a gerber DCODE definition.
*/
class D_CODE
{
public:
wxSize m_Size; /* Dimensions horiz et Vert */
APERTURE_T m_Shape; /* shape ( Line, rect , circulaire , ovale .. ) */
int m_Num_Dcode; /* numero de code ( >= 10 ) */
wxSize m_Drill; /* dimension du trou central (s'il existe) */
int m_DrillShape; /* forme du trou central ( rond = 1, rect = 2 ) */
bool m_InUse; /* FALSE si non utilis */
bool m_Defined; /* FALSE si non defini */
wxString m_SpecialDescr;
APERTURE_MACRO* m_Macro; ///< no ownership, points to GERBER.m_aperture_macros element
/**
* parameters used only when this D_CODE holds a reference to an aperture
* macro, and these parameters would customize the macro.
*/
DCODE_PARAMS m_am_params;
public:
D_CODE( int num_dcode );
~D_CODE();
void Clear_D_CODE_Data();
};
/**
* Class GERBER
* holds the data for one gerber file or layer * holds the data for one gerber file or layer
*/ */
class GERBER_Descr class GERBER
{ {
public: public:
GERBER_Descr* m_Parent; // Pointeur sur la racine pour layers imbriques
GERBER_Descr* m_Pback; // Pointeur de chainage arriere pour layers imbriques
GERBER_Descr* m_Pnext; // Pointeur de chainage avant pour layers imbriques
wxString m_FileName; // Full File Name for this layer wxString m_FileName; // Full File Name for this layer
wxString m_Name; // Layer name wxString m_Name; // Layer name
int m_Layer; // Layer Number int m_Layer; // Layer Number
...@@ -139,10 +275,12 @@ public: ...@@ -139,10 +275,12 @@ public:
bool m_PolygonFillMode; // Enbl polygon mode (read coord as a polygone descr) bool m_PolygonFillMode; // Enbl polygon mode (read coord as a polygone descr)
int m_PolygonFillModeState; // In polygon mode: 0 = first segm, 1 = next segm int m_PolygonFillModeState; // In polygon mode: 0 = first segm, 1 = next segm
APERTURE_MACRO_SET m_aperture_macros;
public: public:
GERBER_Descr( int layer ); GERBER( int layer );
~GERBER_Descr(); ~GERBER();
void Clear_GERBER_Descr(); void Clear_GERBER();
int ReturnUsedDcodeNumber(); int ReturnUsedDcodeNumber();
void ResetDefaultValues(); void ResetDefaultValues();
void InitToolTable(); void InitToolTable();
...@@ -174,29 +312,18 @@ public: ...@@ -174,29 +312,18 @@ public:
* executes 1 commande * executes 1 commande
*/ */
bool ExecuteRS274XCommand( int command, char aBuff[GERBER_BUFZ], char*& text ); bool ExecuteRS274XCommand( int command, char aBuff[GERBER_BUFZ], char*& text );
};
/** /**
* Class D_CODE * Function ReadApertureMacro
* holds a gerber DCODE definition. * reads in an aperture macro and saves it in m_aperture_macros.
*/ * @param aBuff a character buffer at least GERBER_BUFZ long that can be
class D_CODE * used to read successive lines from the gerber file.
{ * @param text A reference to a character pointer which gives the initial text to read from.
public: * @param gerber_file Which file to read from for continuation.
wxSize m_Size; /* Dimensions horiz et Vert */ * @return bool - true if a macro was read in successfully, else false.
int m_Shape; /* shape ( Line, rect , circulaire , ovale .. ) */ */
int m_Num_Dcode; /* numero de code ( >= 10 ) */ bool ReadApertureMacro( char aBuff[GERBER_BUFZ], char*& text, FILE* gerber_file );
wxSize m_Drill; /* dimension du trou central (s'il existe) */
int m_DrillShape; /* forme du trou central ( rond = 1, rect = 2 ) */
bool m_InUse; /* FALSE si non utilis */
bool m_Defined; /* FALSE si non defini */
wxString m_SpecialDescr;
public:
D_CODE( int num_dcode );
~D_CODE();
void Clear_D_CODE_Data();
}; };
...@@ -206,9 +333,15 @@ public: ...@@ -206,9 +333,15 @@ public:
/**************/ /**************/
bool GetEndOfBlock( char buff[GERBER_BUFZ], char*& text, FILE* gerber_file ); bool GetEndOfBlock( char buff[GERBER_BUFZ], char*& text, FILE* gerber_file );
/*************/
/* dcode.cpp */ /**
/*************/ * Function ReturnToolDescr
* returns a D_CODE given a global layer index and Dcode value.
* @param aLayer The index into the global array of GERBER called g_GERBER_List[].
* @param aDcode The dcode value to look up.
* @param aIndex If not null, where to put a one basedindex into the GERBER's m_Aperture_List[] array.
* @return D_CODE* - the looked up D_CODE or NULL if none was encountered in the gerber file for given \a aDcode.
*/
D_CODE * ReturnToolDescr( int layer, int Dcode, int * index = NULL ); D_CODE * ReturnToolDescr( int layer, int Dcode, int * index = NULL );
...@@ -222,11 +355,15 @@ eda_global const wxChar* g_GERBER_Tool_Type[6] ...@@ -222,11 +355,15 @@ eda_global const wxChar* g_GERBER_Tool_Type[6]
#endif #endif
; ;
eda_global GERBER_Descr* g_GERBER_Descr_List[32]; eda_global GERBER* g_GERBER_List[32];
eda_global int g_DisplayPolygonsModeSketch; /* How to show filled polygons :
* 0 = filled
* 1 = Sketch mode /**
*/ * How to show filled polygons :
* 0 = filled
* 1 = Sketch mode
*/
eda_global int g_DisplayPolygonsModeSketch;
#include "pcbnew.h" #include "pcbnew.h"
......
...@@ -56,8 +56,8 @@ bool WinEDA_GerberFrame::Clear_Pcb( bool query ) ...@@ -56,8 +56,8 @@ bool WinEDA_GerberFrame::Clear_Pcb( bool query )
/* init pointeurs et variables */ /* init pointeurs et variables */
for( layer = 0; layer < 32; layer++ ) for( layer = 0; layer < 32; layer++ )
{ {
if( g_GERBER_Descr_List[layer] ) if( g_GERBER_List[layer] )
g_GERBER_Descr_List[layer]->InitToolTable(); g_GERBER_List[layer]->InitToolTable();
} }
/* remise a 0 ou a une valeur initiale des variables de la structure */ /* remise a 0 ou a une valeur initiale des variables de la structure */
......
...@@ -117,37 +117,37 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC, ...@@ -117,37 +117,37 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC,
int G_commande = 0, int G_commande = 0,
D_commande = 0; /* command number for G et D commands (like G04 or D02) */ D_commande = 0; /* command number for G et D commands (like G04 or D02) */
char Line[GERBER_BUFZ]; char line[GERBER_BUFZ];
wxString msg; wxString msg;
char* text; char* text;
int layer; /* current layer used in gerbview */ int layer; /* current layer used in gerbview */
GERBER_Descr* gerber_layer; GERBER* gerber;
wxPoint pos; wxPoint pos;
int error = 0; int error = 0;
layer = GetScreen()->m_Active_Layer; layer = GetScreen()->m_Active_Layer;
if( g_GERBER_Descr_List[layer] == NULL ) if( g_GERBER_List[layer] == NULL )
{ {
g_GERBER_Descr_List[layer] = new GERBER_Descr( layer ); g_GERBER_List[layer] = new GERBER( layer );
} }
gerber_layer = g_GERBER_Descr_List[layer]; gerber = g_GERBER_List[layer];
/* Set the gerber scale: */ /* Set the gerber scale: */
gerber_layer->ResetDefaultValues(); gerber->ResetDefaultValues();
/* Read the gerber file */ /* Read the gerber file */
gerber_layer->m_Current_File = wxFopen( GERBER_FullFileName, wxT( "rt" ) ); gerber->m_Current_File = wxFopen( GERBER_FullFileName, wxT( "rt" ) );
if( gerber_layer->m_Current_File == 0 ) if( gerber->m_Current_File == 0 )
{ {
msg = _( "File " ) + GERBER_FullFileName + _( " not found" ); msg = _( "File " ) + GERBER_FullFileName + _( " not found" );
DisplayError( this, msg, 10 ); DisplayError( this, msg, 10 );
return FALSE; return FALSE;
} }
gerber_layer->m_FileName = GERBER_FullFileName; gerber->m_FileName = GERBER_FullFileName;
wxString path = wxPathOnly( GERBER_FullFileName ); wxString path = wxPathOnly( GERBER_FullFileName );
if( path != wxEmptyString ) if( path != wxEmptyString )
...@@ -158,21 +158,21 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC, ...@@ -158,21 +158,21 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC,
while( TRUE ) while( TRUE )
{ {
if( fgets( Line, sizeof(Line), gerber_layer->m_Current_File ) == NULL ) // E.O.F if( fgets( line, sizeof(line), gerber->m_Current_File ) == NULL ) // E.O.F
{ {
if( gerber_layer->m_FilesPtr == 0 ) if( gerber->m_FilesPtr == 0 )
break; break;
fclose( gerber_layer->m_Current_File ); fclose( gerber->m_Current_File );
gerber_layer->m_FilesPtr--; gerber->m_FilesPtr--;
gerber_layer->m_Current_File = gerber->m_Current_File =
gerber_layer->m_FilesList[gerber_layer->m_FilesPtr]; gerber->m_FilesList[gerber->m_FilesPtr];
continue; continue;
} }
text = StrPurge( Line ); text = StrPurge( line );
while( text && *text ) while( text && *text )
{ {
...@@ -185,49 +185,49 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC, ...@@ -185,49 +185,49 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC,
break; break;
case '*': // End commande case '*': // End commande
gerber_layer->m_CommandState = END_BLOCK; gerber->m_CommandState = END_BLOCK;
text++; text++;
break; break;
case 'M': // End file case 'M': // End file
gerber_layer->m_CommandState = CMD_IDLE; gerber->m_CommandState = CMD_IDLE;
while( *text ) while( *text )
text++; text++;
break; break;
case 'G': /* Line type Gxx : command */ case 'G': /* Line type Gxx : command */
G_commande = gerber_layer->ReturnGCodeNumber( text ); G_commande = gerber->ReturnGCodeNumber( text );
gerber_layer->Execute_G_Command( text, G_commande ); gerber->Execute_G_Command( text, G_commande );
break; break;
case 'D': /* Line type Dxx : Tool selection (xx > 0) or command if xx = 0..9*/ case 'D': /* Line type Dxx : Tool selection (xx > 0) or command if xx = 0..9*/
D_commande = gerber_layer->ReturnDCodeNumber( text ); D_commande = gerber->ReturnDCodeNumber( text );
gerber_layer->Execute_DCODE_Command( this, DC, gerber->Execute_DCODE_Command( this, DC,
text, D_commande ); text, D_commande );
break; break;
case 'X': case 'X':
case 'Y': /* Move or draw command */ case 'Y': /* Move or draw command */
pos = gerber_layer->ReadXYCoord( text ); pos = gerber->ReadXYCoord( text );
if( *text == '*' ) // command like X12550Y19250* if( *text == '*' ) // command like X12550Y19250*
{ {
gerber_layer->Execute_DCODE_Command( this, DC, text, gerber->Execute_DCODE_Command( this, DC, text,
gerber_layer->m_Last_Pen_Command ); gerber->m_Last_Pen_Command );
} }
break; break;
case 'I': case 'I':
case 'J': /* Auxiliary Move command */ case 'J': /* Auxiliary Move command */
pos = gerber_layer->ReadIJCoord( text ); pos = gerber->ReadIJCoord( text );
break; break;
case '%': case '%':
if( gerber_layer->m_CommandState != ENTER_RS274X_CMD ) if( gerber->m_CommandState != ENTER_RS274X_CMD )
{ {
gerber_layer->m_CommandState = ENTER_RS274X_CMD; gerber->m_CommandState = ENTER_RS274X_CMD;
if( !gerber_layer->ReadRS274XCommand( this, DC, Line, text ) ) if( !gerber->ReadRS274XCommand( this, DC, line, text ) )
{ {
error++; error++;
} }
...@@ -235,7 +235,7 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC, ...@@ -235,7 +235,7 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC,
else //Error else //Error
{ {
error++; error++;
gerber_layer->m_CommandState = CMD_IDLE; gerber->m_CommandState = CMD_IDLE;
text++; text++;
} }
break; break;
...@@ -254,14 +254,14 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC, ...@@ -254,14 +254,14 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC,
error, GERBER_FullFileName.GetData() ); error, GERBER_FullFileName.GetData() );
DisplayError( this, msg ); DisplayError( this, msg );
} }
fclose( gerber_layer->m_Current_File ); fclose( gerber->m_Current_File );
SetLocaleTo_Default( ); SetLocaleTo_Default( );
/* Init DCodes list and perhaps read a DCODES file, /* Init DCodes list and perhaps read a DCODES file,
* if the gerber file is only a RS274D file (without any aperture information) * if the gerber file is only a RS274D file (without any aperture information)
*/ */
if( !gerber_layer->m_As_DCode ) if( !gerber->m_As_DCode )
{ {
wxString DCodeFileName; wxString DCodeFileName;
if( D_Code_FullFileName.IsEmpty() ) if( D_Code_FullFileName.IsEmpty() )
......
...@@ -302,7 +302,7 @@ static void Append_1_SEG_ARC_GERBER( int Dcode_index, ...@@ -302,7 +302,7 @@ static void Append_1_SEG_ARC_GERBER( int Dcode_index,
*/ */
/***********************************************/ /***********************************************/
wxPoint GERBER_Descr::ReadXYCoord( char*& Text ) wxPoint GERBER::ReadXYCoord( char*& Text )
/***********************************************/ /***********************************************/
/* Retourne la coord courante pointee par Text (XnnnnYmmmm) /* Retourne la coord courante pointee par Text (XnnnnYmmmm)
...@@ -432,7 +432,7 @@ wxPoint GERBER_Descr::ReadXYCoord( char*& Text ) ...@@ -432,7 +432,7 @@ wxPoint GERBER_Descr::ReadXYCoord( char*& Text )
/************************************************/ /************************************************/
wxPoint GERBER_Descr::ReadIJCoord( char*& Text ) wxPoint GERBER::ReadIJCoord( char*& Text )
/************************************************/ /************************************************/
/* Retourne la coord type InnJnn courante pointee par Text (InnnnJmmmm) /* Retourne la coord type InnJnn courante pointee par Text (InnnnJmmmm)
...@@ -553,7 +553,7 @@ wxPoint GERBER_Descr::ReadIJCoord( char*& Text ) ...@@ -553,7 +553,7 @@ wxPoint GERBER_Descr::ReadIJCoord( char*& Text )
/*****************************************************/ /*****************************************************/
int GERBER_Descr::ReturnGCodeNumber( char*& Text ) int GERBER::ReturnGCodeNumber( char*& Text )
/*****************************************************/ /*****************************************************/
/* Lit la sequence Gnn et retourne la valeur nn /* Lit la sequence Gnn et retourne la valeur nn
...@@ -579,7 +579,7 @@ int GERBER_Descr::ReturnGCodeNumber( char*& Text ) ...@@ -579,7 +579,7 @@ int GERBER_Descr::ReturnGCodeNumber( char*& Text )
/**************************************************/ /**************************************************/
int GERBER_Descr::ReturnDCodeNumber( char*& Text ) int GERBER::ReturnDCodeNumber( char*& Text )
/**************************************************/ /**************************************************/
/* Lit la sequence Dnn et retourne la valeur nn /* Lit la sequence Dnn et retourne la valeur nn
...@@ -603,7 +603,7 @@ int GERBER_Descr::ReturnDCodeNumber( char*& Text ) ...@@ -603,7 +603,7 @@ int GERBER_Descr::ReturnDCodeNumber( char*& Text )
/******************************************************************/ /******************************************************************/
bool GERBER_Descr::Execute_G_Command( char*& text, int G_commande ) bool GERBER::Execute_G_Command( char*& text, int G_commande )
/******************************************************************/ /******************************************************************/
{ {
...@@ -699,15 +699,17 @@ bool GERBER_Descr::Execute_G_Command( char*& text, int G_commande ) ...@@ -699,15 +699,17 @@ bool GERBER_Descr::Execute_G_Command( char*& text, int G_commande )
/*****************************************************************************/ /*****************************************************************************/
bool GERBER_Descr::Execute_DCODE_Command( WinEDA_GerberFrame* frame, wxDC* DC, bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, wxDC* DC,
char*& text, int D_commande ) char*& text, int D_commande )
/*****************************************************************************/ /*****************************************************************************/
{ {
wxSize size( 15, 15 ); wxSize size( 15, 15 );
int shape = 1, dcode = 0; APERTURE_T aperture = APT_CIRCLE;
D_CODE* pt_Tool = NULL;
wxString msg; int dcode = 0;
D_CODE* pt_Tool = NULL;
wxString msg;
if( D_commande >= FIRST_DCODE ) // This is a "Set tool" command if( D_commande >= FIRST_DCODE ) // This is a "Set tool" command
{ {
...@@ -769,9 +771,9 @@ bool GERBER_Descr::Execute_DCODE_Command( WinEDA_GerberFrame* frame, wxDC* DC, ...@@ -769,9 +771,9 @@ bool GERBER_Descr::Execute_DCODE_Command( WinEDA_GerberFrame* frame, wxDC* DC,
pt_Tool = ReturnToolDescr( m_Layer, m_Current_Tool ); pt_Tool = ReturnToolDescr( m_Layer, m_Current_Tool );
if( pt_Tool ) if( pt_Tool )
{ {
size = pt_Tool->m_Size; size = pt_Tool->m_Size;
dcode = pt_Tool->m_Num_Dcode; dcode = pt_Tool->m_Num_Dcode;
shape = pt_Tool->m_Shape; aperture = pt_Tool->m_Shape;
} }
switch( m_Iterpolation ) switch( m_Iterpolation )
...@@ -821,29 +823,29 @@ bool GERBER_Descr::Execute_DCODE_Command( WinEDA_GerberFrame* frame, wxDC* DC, ...@@ -821,29 +823,29 @@ bool GERBER_Descr::Execute_DCODE_Command( WinEDA_GerberFrame* frame, wxDC* DC,
pt_Tool = ReturnToolDescr( m_Layer, m_Current_Tool ); pt_Tool = ReturnToolDescr( m_Layer, m_Current_Tool );
if( pt_Tool ) if( pt_Tool )
{ {
size = pt_Tool->m_Size; size = pt_Tool->m_Size;
dcode = pt_Tool->m_Num_Dcode; dcode = pt_Tool->m_Num_Dcode;
shape = pt_Tool->m_Shape; aperture = pt_Tool->m_Shape;
} }
switch( shape ) switch( aperture )
{ {
case GERB_LINE: case APT_LINE:
case GERB_CIRCLE: case APT_CIRCLE:
Append_1_Flash_ROND_GERBER( dcode, Append_1_Flash_ROND_GERBER( dcode,
frame, DC, frame, DC,
m_CurrentPos, m_CurrentPos,
size.x ); size.x );
break; break;
case GERB_OVALE: case APT_OVAL:
Append_1_Flash_GERBER( dcode, Append_1_Flash_GERBER( dcode,
frame, DC, m_CurrentPos, frame, DC, m_CurrentPos,
size, size,
PAD_OVAL ); PAD_OVAL );
break; break;
case GERB_RECT: case APT_RECT:
Append_1_Flash_GERBER( dcode, Append_1_Flash_GERBER( dcode,
frame, DC, m_CurrentPos, frame, DC, m_CurrentPos,
size, size,
......
...@@ -12,7 +12,8 @@ ...@@ -12,7 +12,8 @@
#define CODE( x, y ) ( ((x) << 8) + (y) ) #define CODE( x, y ) ( ((x) << 8) + (y) )
enum rs274x_parameters { enum RS274X_PARAMETERS
{
FORMAT_STATEMENT = CODE( 'F', 'S' ), FORMAT_STATEMENT = CODE( 'F', 'S' ),
AXIS_SELECT = CODE( 'A', 'S' ), AXIS_SELECT = CODE( 'A', 'S' ),
MIRROR_IMAGE = CODE( 'M', 'I' ), MIRROR_IMAGE = CODE( 'M', 'I' ),
...@@ -30,8 +31,9 @@ enum rs274x_parameters { ...@@ -30,8 +31,9 @@ enum rs274x_parameters {
PLOTTER_FILM = CODE( 'P', 'M' ), PLOTTER_FILM = CODE( 'P', 'M' ),
INCLUDE_FILE = CODE( 'I', 'F' ), INCLUDE_FILE = CODE( 'I', 'F' ),
APERTURE_DESCR = CODE( 'A', 'D' ), AP_DEFINITION = CODE( 'A', 'D' ),
APERTURE_MACRO = CODE( 'A', 'M' ),
AP_MACRO = CODE( 'A', 'M' ),
LAYER_NAME = CODE( 'L', 'N' ), LAYER_NAME = CODE( 'L', 'N' ),
LAYER_POLARITY = CODE( 'L', 'P' ), LAYER_POLARITY = CODE( 'L', 'P' ),
KNOCKOUT = CODE( 'K', 'O' ), KNOCKOUT = CODE( 'K', 'O' ),
...@@ -41,7 +43,6 @@ enum rs274x_parameters { ...@@ -41,7 +43,6 @@ enum rs274x_parameters {
/* Local Functions */ /* Local Functions */
static bool ReadApertureMacro( char aBuff[GERBER_BUFZ], char*& text, FILE* gerber_file );
/** /**
...@@ -79,7 +80,19 @@ static int ReadXCommand( char*& text ) ...@@ -79,7 +80,19 @@ static int ReadXCommand( char*& text )
*/ */
static int ReadInt( char*& text ) static int ReadInt( char*& text )
{ {
return (int) strtol( text, &text, 10 ); char* start = text;
int ret = (int) strtol( text, &text, 10 );
/*
if( text == start ) // no conversion was performed, skip one character forward
++text;
*/
if( *text == ',' )
++text;
return ret;
} }
...@@ -92,12 +105,24 @@ static int ReadInt( char*& text ) ...@@ -92,12 +105,24 @@ static int ReadInt( char*& text )
*/ */
static double ReadDouble( char*& text ) static double ReadDouble( char*& text )
{ {
return strtod( text, &text ); char* start = text;
double ret = strtod( text, &text );
/*
if( text == start ) // no conversion was performed, skip one character forward
++text;
*/
if( *text == ',' )
++text;
return ret;
} }
/****************************************************************************/ /****************************************************************************/
bool GERBER_Descr::ReadRS274XCommand( WinEDA_GerberFrame* frame, wxDC* DC, bool GERBER::ReadRS274XCommand( WinEDA_GerberFrame* frame, wxDC* DC,
char buff[GERBER_BUFZ], char*& text ) char buff[GERBER_BUFZ], char*& text )
/****************************************************************************/ /****************************************************************************/
{ {
...@@ -112,7 +137,7 @@ bool GERBER_Descr::ReadRS274XCommand( WinEDA_GerberFrame* frame, wxDC* DC, ...@@ -112,7 +137,7 @@ bool GERBER_Descr::ReadRS274XCommand( WinEDA_GerberFrame* frame, wxDC* DC,
{ {
switch( *text ) switch( *text )
{ {
case '%': // End commande case '%': // end of command
text++; text++;
m_CommandState = CMD_IDLE; m_CommandState = CMD_IDLE;
goto exit; // success completion goto exit; // success completion
...@@ -136,9 +161,10 @@ bool GERBER_Descr::ReadRS274XCommand( WinEDA_GerberFrame* frame, wxDC* DC, ...@@ -136,9 +161,10 @@ bool GERBER_Descr::ReadRS274XCommand( WinEDA_GerberFrame* frame, wxDC* DC,
} }
} }
// End of current line // end of current line, read another one.
if( fgets( buff, GERBER_BUFZ, m_Current_File ) == NULL ) if( fgets( buff, GERBER_BUFZ, m_Current_File ) == NULL )
{ {
// end of file
ok = false; ok = false;
break; break;
} }
...@@ -152,7 +178,7 @@ exit: ...@@ -152,7 +178,7 @@ exit:
/*******************************************************************************/ /*******************************************************************************/
bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& text ) bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& text )
/*******************************************************************************/ /*******************************************************************************/
{ {
int code; int code;
...@@ -307,7 +333,7 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch ...@@ -307,7 +333,7 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch
m_LayerNegative = FALSE; m_LayerNegative = FALSE;
break; break;
case APERTURE_MACRO: case AP_MACRO:
ReadApertureMacro( buff, text, m_Current_File ); ReadApertureMacro( buff, text, m_Current_File );
break; break;
...@@ -335,7 +361,7 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch ...@@ -335,7 +361,7 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch
m_FilesPtr++; m_FilesPtr++;
break; break;
case APERTURE_DESCR: case AP_DEFINITION:
if( *text != 'D' ) if( *text != 'D' )
{ {
ok = FALSE; ok = FALSE;
...@@ -360,7 +386,7 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch ...@@ -360,7 +386,7 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch
switch( ctmp ) switch( ctmp )
{ {
case 'C': // Circle case 'C': // Circle
dcode->m_Shape = GERB_CIRCLE; dcode->m_Shape = APT_CIRCLE;
while( *text == ' ' ) while( *text == ' ' )
text++; text++;
...@@ -386,9 +412,9 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch ...@@ -386,9 +412,9 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch
dcode->m_Defined = TRUE; dcode->m_Defined = TRUE;
break; break;
case 'O': // ovale case 'O': // oval
case 'R': // rect case 'R': // rect
dcode->m_Shape = (ctmp == 'O') ? GERB_OVALE : GERB_RECT; dcode->m_Shape = (ctmp == 'O') ? APT_OVAL : APT_RECT;
while( *text == ' ' ) while( *text == ' ' )
text++; text++;
...@@ -424,9 +450,8 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch ...@@ -424,9 +450,8 @@ bool GERBER_Descr::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], ch
dcode->m_Defined = TRUE; dcode->m_Defined = TRUE;
break; break;
case 'P': // Polygone case 'P': // Polygon
// A modifier: temporairement la forme ronde est utilise dcode->m_Shape = APT_POLYGON;
dcode->m_Shape = GERB_CIRCLE;
dcode->m_Defined = TRUE; dcode->m_Defined = TRUE;
break; break;
} }
...@@ -472,39 +497,125 @@ bool GetEndOfBlock( char buff[GERBER_BUFZ], char*& text, FILE* gerber_file ) ...@@ -472,39 +497,125 @@ bool GetEndOfBlock( char buff[GERBER_BUFZ], char*& text, FILE* gerber_file )
/*******************************************************************/ /*******************************************************************/
bool ReadApertureMacro( char buff[GERBER_BUFZ], char*& text, FILE* gerber_file ) bool GERBER::ReadApertureMacro( char buff[GERBER_BUFZ], char*& text, FILE* gerber_file )
/*******************************************************************/ /*******************************************************************/
{ {
wxString macro_name; APERTURE_MACRO am;
int macro_type = 0;
// Read macro name // read macro name
while( (text < buff + GERBER_BUFZ) && *text ) while( *text )
{ {
if( *text == '*' ) if( *text == '*' )
{
++text;
break; break;
}
macro_name.Append( *text ); am.name.Append( *text++ );
text++;
} }
if( g_DebugLevel > 0 ) if( g_DebugLevel > 0 )
wxMessageBox( macro_name, wxT( "macro name" ) ); wxMessageBox( am.name, wxT( "macro name" ) );
text = buff;
fgets( buff, GERBER_BUFZ, gerber_file );
// Read parameters
macro_type = ReadInt( text );
while( (text < buff + GERBER_BUFZ) && *text ) for(;;)
{ {
AM_PRIMITIVE prim;
if( *text == '*' ) if( *text == '*' )
return TRUE; ++text;
text++; if( *text == '\n' )
++text;
if( !*text )
{
text = buff;
if( fgets( buff, GERBER_BUFZ, gerber_file ) == NULL )
return false;
}
if( *text == '%' )
break; // exit with text still pointing at %
prim.primitive_id = (AM_PRIMITIVE_ID) ReadInt( text );
int paramCount;
switch( prim.primitive_id )
{
default:
case AMP_CIRCLE:
paramCount = 4;
break;
case AMP_LINE2:
case AMP_LINE20:
paramCount = 7;
break;
case AMP_LINE_CENTER:
case AMP_LINE_LOWER_LEFT:
paramCount = 6;
break;
case AMP_EOF:
paramCount = 0;
break;
case AMP_OUTLINE:
paramCount = 4;
break;
case AMP_POLYGON:
paramCount = 4;
break;
case AMP_MOIRE:
paramCount = 9;
break;
case AMP_THERMAL:
paramCount = 6;
break;
}
DCODE_PARAM param;
for( int i=0; i<paramCount && *text && *text!='*'; ++i )
{
if( *text == '$' )
{
++text;
param.isImmediate = false;
}
else
{
param.isImmediate = true;
}
param.value = ReadDouble( text );
prim.params.push_back( param );
}
if( prim.primitive_id == AMP_OUTLINE )
{
paramCount = (int) prim.params[1].value * 2 + 1;
for( int i=0; i<paramCount && *text && *text!='*'; ++i )
{
if( *text == '$' )
{
++text;
param.isImmediate = false;
}
else
{
param.isImmediate = true;
}
param.value = ReadDouble( text );
prim.params.push_back( param );
}
}
am.primitives.push_back( prim );
} }
return FALSE; m_aperture_macros.insert( am );
return true;
} }
...@@ -129,7 +129,7 @@ WinEDA_SwapLayerFrame::WinEDA_SwapLayerFrame(WinEDA_GerberFrame *parent) : ...@@ -129,7 +129,7 @@ WinEDA_SwapLayerFrame::WinEDA_SwapLayerFrame(WinEDA_GerberFrame *parent) :
g_DesignSettings.m_CopperLayerCount = 0; g_DesignSettings.m_CopperLayerCount = 0;
for( ii = 0; ii < 32; ii++ ) for( ii = 0; ii < 32; ii++ )
{ {
if( g_GERBER_Descr_List[ii] != NULL ) if( g_GERBER_List[ii] != NULL )
g_DesignSettings.m_CopperLayerCount++; g_DesignSettings.m_CopperLayerCount++;
// Specify the default value for each member of these arrays. // Specify the default value for each member of these arrays.
...@@ -140,7 +140,7 @@ WinEDA_SwapLayerFrame::WinEDA_SwapLayerFrame(WinEDA_GerberFrame *parent) : ...@@ -140,7 +140,7 @@ WinEDA_SwapLayerFrame::WinEDA_SwapLayerFrame(WinEDA_GerberFrame *parent) :
int pcb_layer_number = 0; int pcb_layer_number = 0;
for( nb_items = 0, ii = 0; ii < 32; ii++ ) for( nb_items = 0, ii = 0; ii < 32; ii++ )
{ {
if( g_GERBER_Descr_List[ii] == NULL ) if( g_GERBER_List[ii] == NULL )
continue; continue;
if( (pcb_layer_number == g_DesignSettings.m_CopperLayerCount - 1) if( (pcb_layer_number == g_DesignSettings.m_CopperLayerCount - 1)
......
...@@ -150,7 +150,7 @@ void WinEDA_GerberFrame::ReCreateMenuBar( void ) ...@@ -150,7 +150,7 @@ void WinEDA_GerberFrame::ReCreateMenuBar( void )
_( "Open the gerbview manual" ), help_xpm ); _( "Open the gerbview manual" ), help_xpm );
ADD_MENUITEM_WITH_HELP(helpMenu, ADD_MENUITEM_WITH_HELP(helpMenu,
ID_KICAD_ABOUT, _( "&About gerbview" ), ID_KICAD_ABOUT, _( "&About gerbview" ),
_( "About gerbview gerber and drill viewer" ), _( "About gerbview gerber and drill viewer" ),
info_xpm ); info_xpm );
menuBar->Append( m_FilesMenu, _( "&File" ) ); menuBar->Append( m_FilesMenu, _( "&File" ) );
...@@ -192,7 +192,7 @@ void WinEDA_GerberFrame::ReCreateHToolbar( void ) ...@@ -192,7 +192,7 @@ void WinEDA_GerberFrame::ReCreateHToolbar( void )
/***********************************************/ /***********************************************/
{ {
int layer = 0; int layer = 0;
GERBER_Descr* gerber_layer = NULL; GERBER* gerber = NULL;
int ii; int ii;
wxString msg; wxString msg;
...@@ -203,7 +203,7 @@ void WinEDA_GerberFrame::ReCreateHToolbar( void ) ...@@ -203,7 +203,7 @@ void WinEDA_GerberFrame::ReCreateHToolbar( void )
if( GetScreen() ) if( GetScreen() )
{ {
layer = GetScreen()->m_Active_Layer; layer = GetScreen()->m_Active_Layer;
gerber_layer = g_GERBER_Descr_List[layer]; gerber = g_GERBER_List[layer];
} }
m_HToolBar = new WinEDA_Toolbar( TOOLBAR_MAIN, this, ID_H_TOOLBAR, TRUE ); m_HToolBar = new WinEDA_Toolbar( TOOLBAR_MAIN, this, ID_H_TOOLBAR, TRUE );
......
...@@ -31,11 +31,11 @@ void Draw_Track_Buffer( WinEDA_DrawPanel* panel, wxDC* DC, BOARD* Pcb, int draw_ ...@@ -31,11 +31,11 @@ void Draw_Track_Buffer( WinEDA_DrawPanel* panel, wxDC* DC, BOARD* Pcb, int draw_
{ {
TRACK* Track; TRACK* Track;
int layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer; int layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
GERBER_Descr* gerber_layer = g_GERBER_Descr_List[layer]; GERBER* gerber = g_GERBER_List[layer];
int dcode_hightlight = 0; int dcode_hightlight = 0;
if( gerber_layer ) if( gerber )
dcode_hightlight = gerber_layer->m_Selected_Tool; dcode_hightlight = gerber->m_Selected_Tool;
Track = Pcb->m_Track; Track = Pcb->m_Track;
for( ; Track != NULL; Track = (TRACK*) Track->Pnext ) for( ; Track != NULL; Track = (TRACK*) Track->Pnext )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment