From cd30da179a2c922460625c000fb3cf079f152e2c Mon Sep 17 00:00:00 2001
From: Marek Roszko <mark.roszko@gmail.com>
Date: Mon, 7 Nov 2022 07:15:55 -0500
Subject: [PATCH] Round out the cli with position file export

---
 common/jobs/job_export_pcb_pos.h              |  78 ++++++++
 kicad/CMakeLists.txt                          |   1 +
 kicad/cli/command_export_pcb_pos.cpp          | 172 ++++++++++++++++++
 kicad/cli/command_export_pcb_pos.h            |  37 ++++
 kicad/kicad_cli.cpp                           |   3 +
 pcbnew/CMakeLists.txt                         |   2 +-
 .../dialogs/dialog_gen_footprint_position.cpp |   2 +-
 ..._placefile.cpp => place_file_exporter.cpp} |   2 +-
 ...ints_placefile.h => place_file_exporter.h} |   0
 pcbnew/pcbnew_jobs_handler.cpp                |  75 ++++++++
 pcbnew/pcbnew_jobs_handler.h                  |   1 +
 pcbnew/python/swig/pcbnew.i                   |   4 +-
 12 files changed, 372 insertions(+), 5 deletions(-)
 create mode 100644 common/jobs/job_export_pcb_pos.h
 create mode 100644 kicad/cli/command_export_pcb_pos.cpp
 create mode 100644 kicad/cli/command_export_pcb_pos.h
 rename pcbnew/exporters/{export_footprints_placefile.cpp => place_file_exporter.cpp} (99%)
 rename pcbnew/exporters/{export_footprints_placefile.h => place_file_exporter.h} (100%)

diff --git a/common/jobs/job_export_pcb_pos.h b/common/jobs/job_export_pcb_pos.h
new file mode 100644
index 0000000000..4ca4f73dcc
--- /dev/null
+++ b/common/jobs/job_export_pcb_pos.h
@@ -0,0 +1,78 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
+ * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef JOB_EXPORT_PCB_POS_H
+#define JOB_EXPORT_PCB_POS_H
+
+#include <layer_ids.h>
+#include <wx/string.h>
+#include "job.h"
+
+class JOB_EXPORT_PCB_POS : public JOB
+{
+public:
+    JOB_EXPORT_PCB_POS( bool aIsCli ) :
+            JOB( "pos", aIsCli ), m_filename(),
+            m_outputFile(),
+            m_excludeFootprintsWithTh( true ),
+            m_useDrillPlaceFileOrigin( true ),
+            m_smdOnly( false )
+    {
+    }
+
+    wxString m_filename;
+    wxString m_outputFile;
+
+    bool m_useDrillPlaceFileOrigin;
+    bool m_smdOnly;
+    bool m_excludeFootprintsWithTh;
+    bool m_negateBottomX;
+
+    enum class SIDE
+    {
+        FRONT,
+        BACK,
+        BOTH
+    };
+
+    SIDE m_side;
+
+    enum class UNITS
+    {
+        INCHES,
+        MILLIMETERS
+    };
+
+    UNITS m_units;
+
+
+    enum class FORMAT
+    {
+        ASCII,
+        CSV,
+        GERBER
+    };
+
+    FORMAT m_format;
+
+    bool m_gerberBoardEdge;
+};
+
+#endif
\ No newline at end of file
diff --git a/kicad/CMakeLists.txt b/kicad/CMakeLists.txt
index 561165b82d..6fe6d60211 100644
--- a/kicad/CMakeLists.txt
+++ b/kicad/CMakeLists.txt
@@ -21,6 +21,7 @@ set( KICAD_SRCS
     cli/command_export_pcb_dxf.cpp
     cli/command_export_pcb_gerber.cpp
     cli/command_export_pcb_pdf.cpp
+    cli/command_export_pcb_pos.cpp
     cli/command_export_pcb_step.cpp
     cli/command_export_pcb_svg.cpp
     cli/command_pcb.cpp
diff --git a/kicad/cli/command_export_pcb_pos.cpp b/kicad/cli/command_export_pcb_pos.cpp
new file mode 100644
index 0000000000..13b4ff28b9
--- /dev/null
+++ b/kicad/cli/command_export_pcb_pos.cpp
@@ -0,0 +1,172 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
+ * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "command_export_pcb_pos.h"
+#include <cli/exit_codes.h>
+#include "jobs/job_export_pcb_pos.h"
+#include <kiface_base.h>
+#include <layer_ids.h>
+#include <wx/crt.h>
+
+#include <macros.h>
+
+#include <locale_io.h>
+
+#define ARG_SIDE "--side"
+#define ARG_FORMAT "--format"
+#define ARG_UNITS "--units"
+#define ARG_NEGATE_BOTTOM_X "--bottom-negate-x"
+#define ARG_USE_DRILL_FILE_ORIGIN "--use-drill-file-origin"
+#define ARG_SMD_ONLY "--smd-only"
+#define ARG_EXCLUDE_FOOTPRINTS_TH "--exclude-fp-th"
+#define ARG_GERBER_BOARD_EDGE "--gerber-board-edge"
+
+
+CLI::EXPORT_PCB_POS_COMMAND::EXPORT_PCB_POS_COMMAND() : EXPORT_PCB_BASE_COMMAND( "pos" )
+{
+    m_argParser.add_argument( ARG_SIDE )
+            .default_value( std::string( "both" ) )
+            .help( "valid options: front,back,both" );
+
+    m_argParser.add_argument( ARG_FORMAT )
+            .default_value( std::string( "ascii" ) )
+            .help( "valid options: ascii,csv,gerber" );
+
+    m_argParser.add_argument( ARG_UNITS )
+            .default_value( std::string( "in" ) )
+            .help( "output units, valid options are in or mm (ascii or csv only)" );
+
+    m_argParser.add_argument( ARG_NEGATE_BOTTOM_X )
+            .help( "Use negative X coordinates for footprints on bottom layer (ascii or csv only)" )
+            .implicit_value( true )
+            .default_value( false );
+
+    m_argParser.add_argument( ARG_USE_DRILL_FILE_ORIGIN )
+            .help( "Use drill/place file origin (ascii or csv only)" )
+            .implicit_value( true )
+            .default_value( false );
+
+    m_argParser.add_argument( ARG_SMD_ONLY )
+            .help( "Include only SMD footprints (ascii or csv only)" )
+            .implicit_value( true )
+            .default_value( false );
+
+    m_argParser.add_argument( ARG_EXCLUDE_FOOTPRINTS_TH )
+            .help( "Exclue all footprints with through-hole pads (ascii or csv only)" )
+            .implicit_value( true )
+            .default_value( false );
+
+    m_argParser.add_argument( ARG_GERBER_BOARD_EDGE )
+            .help( "Include board edge layer (gerber only)" )
+            .implicit_value( true )
+            .default_value( false );
+}
+
+
+int CLI::EXPORT_PCB_POS_COMMAND::Perform( KIWAY& aKiway )
+{
+    int baseExit = EXPORT_PCB_BASE_COMMAND::Perform( aKiway );
+    if( baseExit != EXIT_CODES::OK )
+        return baseExit;
+
+    std::unique_ptr<JOB_EXPORT_PCB_POS> aPosJob( new JOB_EXPORT_PCB_POS( true ) );
+
+    aPosJob->m_filename = FROM_UTF8( m_argParser.get<std::string>( ARG_INPUT ).c_str() );
+    aPosJob->m_outputFile = FROM_UTF8( m_argParser.get<std::string>( ARG_OUTPUT ).c_str() );
+
+    if( !wxFile::Exists( aPosJob->m_filename ) )
+    {
+        wxFprintf( stderr, _( "Board file does not exist or is not accessible\n" ) );
+        return EXIT_CODES::ERR_INVALID_INPUT_FILE;
+    }
+
+    aPosJob->m_negateBottomX = m_argParser.get<bool>( ARG_NEGATE_BOTTOM_X );
+    aPosJob->m_smdOnly = m_argParser.get<bool>( ARG_SMD_ONLY );
+    aPosJob->m_excludeFootprintsWithTh = m_argParser.get<bool>( ARG_EXCLUDE_FOOTPRINTS_TH );
+    aPosJob->m_useDrillPlaceFileOrigin = m_argParser.get<bool>( ARG_USE_DRILL_FILE_ORIGIN );
+    aPosJob->m_useDrillPlaceFileOrigin = m_argParser.get<bool>( ARG_GERBER_BOARD_EDGE );
+
+    wxString format = FROM_UTF8( m_argParser.get<std::string>( ARG_FORMAT ).c_str() );
+    if( format == wxS( "ascii" ) )
+    {
+        aPosJob->m_format = JOB_EXPORT_PCB_POS::FORMAT::ASCII;
+    }
+    else if( format == wxS( "csv" ) )
+    {
+        aPosJob->m_format = JOB_EXPORT_PCB_POS::FORMAT::CSV;
+    }
+    else if( format == wxS( "gerber" ) )
+    {
+        aPosJob->m_format = JOB_EXPORT_PCB_POS::FORMAT::GERBER;
+    }
+    else
+    {
+        wxFprintf( stderr, _( "Invalid format\n" ) );
+        return EXIT_CODES::ERR_ARGS;
+    }
+
+    wxString units = FROM_UTF8( m_argParser.get<std::string>( ARG_UNITS ).c_str() );
+
+    if( units == wxS( "mm" ) )
+    {
+        aPosJob->m_units = JOB_EXPORT_PCB_POS::UNITS::MILLIMETERS;
+    }
+    else if( units == wxS( "in" ) )
+    {
+        aPosJob->m_units = JOB_EXPORT_PCB_POS::UNITS::INCHES;
+    }
+    else
+    {
+        wxFprintf( stderr, _( "Invalid units specified\n" ) );
+        return EXIT_CODES::ERR_ARGS;
+    }
+
+    wxString side = FROM_UTF8( m_argParser.get<std::string>( ARG_SIDE ).c_str() );
+
+    if( units == wxS( "both" ) )
+    {
+        if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
+        {
+            wxFprintf( stderr, _( "\"both\" not supported for gerber format\n" ) );
+            return EXIT_CODES::ERR_ARGS;
+        }
+
+        aPosJob->m_side = JOB_EXPORT_PCB_POS::SIDE::BOTH;
+    }
+    else if( units == wxS( "front" ) )
+    {
+        aPosJob->m_side = JOB_EXPORT_PCB_POS::SIDE::FRONT;
+    }
+    else if( units == wxS( "back" ) )
+    {
+        aPosJob->m_side = JOB_EXPORT_PCB_POS::SIDE::BACK;
+    }
+    else
+    {
+        wxFprintf( stderr, _( "Invalid side specified\n" ) );
+        return EXIT_CODES::ERR_ARGS;
+    }
+
+
+    LOCALE_IO dummy;
+    int       exitCode = aKiway.ProcessJob( KIWAY::FACE_PCB, aPosJob.get() );
+
+    return exitCode;
+}
\ No newline at end of file
diff --git a/kicad/cli/command_export_pcb_pos.h b/kicad/cli/command_export_pcb_pos.h
new file mode 100644
index 0000000000..a61afb394a
--- /dev/null
+++ b/kicad/cli/command_export_pcb_pos.h
@@ -0,0 +1,37 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
+ * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COMMAND_EXPORT_PCB_POS_H
+#define COMMAND_EXPORT_PCB_POS_H
+
+#include "command_export_pcb_base.h"
+
+namespace CLI
+{
+class EXPORT_PCB_POS_COMMAND : public EXPORT_PCB_BASE_COMMAND
+{
+public:
+    EXPORT_PCB_POS_COMMAND();
+
+    int Perform( KIWAY& aKiway ) override;
+};
+} // namespace CLI
+
+#endif
\ No newline at end of file
diff --git a/kicad/kicad_cli.cpp b/kicad/kicad_cli.cpp
index 34a2a252f6..2ee5efcc08 100644
--- a/kicad/kicad_cli.cpp
+++ b/kicad/kicad_cli.cpp
@@ -52,6 +52,7 @@
 #include "cli/command_export_pcb_dxf.h"
 #include "cli/command_export_pcb_gerber.h"
 #include "cli/command_export_pcb_pdf.h"
+#include "cli/command_export_pcb_pos.h"
 #include "cli/command_export_pcb_svg.h"
 #include "cli/command_export_pcb_step.h"
 #include "cli/command_export_sch_pdf.h"
@@ -110,6 +111,7 @@ static CLI::EXPORT_PCB_DXF_COMMAND    exportPcbDxfCmd{};
 static CLI::EXPORT_PCB_STEP_COMMAND   exportPcbStepCmd{};
 static CLI::EXPORT_PCB_SVG_COMMAND    exportPcbSvgCmd{};
 static CLI::EXPORT_PCB_PDF_COMMAND    exportPcbPdfCmd{};
+static CLI::EXPORT_PCB_POS_COMMAND    exportPcbPosCmd{};
 static CLI::EXPORT_PCB_GERBER_COMMAND exportPcbGerberCmd{};
 static CLI::EXPORT_PCB_COMMAND        exportPcbCmd{};
 static CLI::PCB_COMMAND               pcbCmd{};
@@ -128,6 +130,7 @@ static std::vector<COMMAND_ENTRY> commandStack = {
                     &exportPcbDxfCmd,
                     &exportPcbGerberCmd,
                     &exportPcbPdfCmd,
+                    &exportPcbPosCmd,
                     &exportPcbStepCmd,
                     &exportPcbSvgCmd
                 }
diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt
index 87d7fa2e47..a069305cfa 100644
--- a/pcbnew/CMakeLists.txt
+++ b/pcbnew/CMakeLists.txt
@@ -224,7 +224,7 @@ set( PCBNEW_EXPORTERS
     exporters/export_gencad.cpp
     exporters/export_idf.cpp
     exporters/exporter_vrml.cpp
-    exporters/export_footprints_placefile.cpp
+    exporters/place_file_exporter.cpp
     exporters/gen_drill_report_files.cpp
     exporters/gendrill_Excellon_writer.cpp
     exporters/gendrill_file_writer_base.cpp
diff --git a/pcbnew/dialogs/dialog_gen_footprint_position.cpp b/pcbnew/dialogs/dialog_gen_footprint_position.cpp
index 48f5c37184..d60fa63a58 100644
--- a/pcbnew/dialogs/dialog_gen_footprint_position.cpp
+++ b/pcbnew/dialogs/dialog_gen_footprint_position.cpp
@@ -39,7 +39,7 @@
 #include <kiface_base.h>
 #include "widgets/wx_html_report_panel.h"
 #include <dialog_gen_footprint_position_file_base.h>
-#include <export_footprints_placefile.h>
+#include <exporters/place_file_exporter.h>
 #include "gerber_placefile_writer.h"
 
 #include <wx/dirdlg.h>
diff --git a/pcbnew/exporters/export_footprints_placefile.cpp b/pcbnew/exporters/place_file_exporter.cpp
similarity index 99%
rename from pcbnew/exporters/export_footprints_placefile.cpp
rename to pcbnew/exporters/place_file_exporter.cpp
index a4d5ebc6f5..0a43fa9194 100644
--- a/pcbnew/exporters/export_footprints_placefile.cpp
+++ b/pcbnew/exporters/place_file_exporter.cpp
@@ -31,7 +31,7 @@
 #include <locale_io.h>
 #include <board_design_settings.h>
 #include <build_version.h>
-#include <export_footprints_placefile.h>
+#include <exporters/place_file_exporter.h>
 #include <pad.h>
 
 #include <wx/dirdlg.h>
diff --git a/pcbnew/exporters/export_footprints_placefile.h b/pcbnew/exporters/place_file_exporter.h
similarity index 100%
rename from pcbnew/exporters/export_footprints_placefile.h
rename to pcbnew/exporters/place_file_exporter.h
diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp
index d18469f58c..b8dffdff28 100644
--- a/pcbnew/pcbnew_jobs_handler.cpp
+++ b/pcbnew/pcbnew_jobs_handler.cpp
@@ -24,12 +24,15 @@
 #include <jobs/job_export_pcb_drill.h>
 #include <jobs/job_export_pcb_dxf.h>
 #include <jobs/job_export_pcb_pdf.h>
+#include <jobs/job_export_pcb_pos.h>
 #include <jobs/job_export_pcb_svg.h>
 #include <jobs/job_export_pcb_step.h>
 #include <cli/exit_codes.h>
 #include <plotters/plotter_dxf.h>
 #include <plotters/plotter_gerber.h>
 #include <plotters/plotters_pslike.h>
+#include <exporters/place_file_exporter.h>
+#include "gerber_placefile_writer.h"
 #include <pgm_base.h>
 #include <pcbplot.h>
 #include <board_design_settings.h>
@@ -38,6 +41,7 @@
 #include <pcb_plot_svg.h>
 #include <gendrill_Excellon_writer.h>
 #include <gendrill_gerber_writer.h>
+#include <wildcards_and_files_ext.h>
 
 #include "pcbnew_scripting_helpers.h"
 
@@ -368,5 +372,76 @@ int PCBNEW_JOBS_HANDLER::JobExportDrill( JOB* aJob )
                                                 aDrillJob->m_generateMap, nullptr );
     }
 
+    return CLI::EXIT_CODES::OK;
+}
+
+
+int PCBNEW_JOBS_HANDLER::JobExportPos( JOB* aJob )
+{
+    JOB_EXPORT_PCB_POS* aPosJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( aJob );
+
+    if( aPosJob == nullptr )
+        return CLI::EXIT_CODES::ERR_UNKNOWN;
+
+    if( aJob->IsCli() )
+        wxPrintf( _( "Loading board\n" ) );
+
+    BOARD* brd = LoadBoard( aPosJob->m_filename );
+
+    if( aPosJob->m_outputFile.IsEmpty() )
+    {
+        wxFileName fn = brd->GetFileName();
+        fn.SetName( fn.GetName() );
+
+        if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::ASCII )
+            fn.SetExt( FootprintPlaceFileExtension );
+        else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV )
+            fn.SetExt( CsvFileExtension );
+        else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
+            fn.SetExt( GerberFileExtension );
+
+        aPosJob->m_outputFile = fn.GetFullName();
+    }
+
+    FILE* file = nullptr;
+    file = wxFopen( aPosJob->m_outputFile, wxS( "wt" ) );
+
+    if( file == nullptr )
+        return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT;
+
+    if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::ASCII || aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV )
+    {
+        std::string         data;
+
+        bool frontSide = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT
+                         || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH;
+
+        bool backSide = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK
+                         || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH;
+
+        PLACE_FILE_EXPORTER exporter( brd, aPosJob->m_units == JOB_EXPORT_PCB_POS::UNITS::MILLIMETERS,
+                                        aPosJob->m_smdOnly, aPosJob->m_excludeFootprintsWithTh,
+                                        frontSide, backSide,
+                                        aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV,
+                                        aPosJob->m_useDrillPlaceFileOrigin,
+                                        aPosJob->m_negateBottomX );
+        data = exporter.GenPositionData();
+
+        fputs( data.c_str(), file );
+        fclose( file );
+    }
+    else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
+    {
+        PLACEFILE_GERBER_WRITER exporter( brd );
+
+        PCB_LAYER_ID gbrLayer;
+        if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT )
+            gbrLayer = F_Cu;
+        else if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK )
+            gbrLayer = B_Cu;
+
+        exporter.CreatePlaceFile( aPosJob->m_outputFile, gbrLayer, aPosJob->m_gerberBoardEdge );
+    }
+
     return CLI::EXIT_CODES::OK;
 }
\ No newline at end of file
diff --git a/pcbnew/pcbnew_jobs_handler.h b/pcbnew/pcbnew_jobs_handler.h
index 2c4aecf3e2..6af19b4afe 100644
--- a/pcbnew/pcbnew_jobs_handler.h
+++ b/pcbnew/pcbnew_jobs_handler.h
@@ -33,6 +33,7 @@ public:
     int JobExportPdf( JOB* aJob );
     int JobExportGerber( JOB* aJob );
     int JobExportDrill( JOB* aJob );
+    int JobExportPos( JOB* aJob );
 };
 
 #endif
\ No newline at end of file
diff --git a/pcbnew/python/swig/pcbnew.i b/pcbnew/python/swig/pcbnew.i
index cd7f468f86..33f02893fe 100644
--- a/pcbnew/python/swig/pcbnew.i
+++ b/pcbnew/python/swig/pcbnew.i
@@ -70,7 +70,7 @@ class BASE_SET {};
 #include <plotcontroller.h>
 #include <pcb_plot_params.h>
 #include <exporters/export_d356.h>
-#include <exporters/export_footprints_placefile.h>
+#include <exporters/place_file_exporter.h>
 #include <exporters/export_vrml.h>
 #include <exporters/gendrill_file_writer_base.h>
 #include <exporters/gendrill_Excellon_writer.h>
@@ -115,7 +115,7 @@ HANDLE_EXCEPTIONS(PLUGIN::FootprintDelete)
 %include <pcb_plot_params.h>
 %include <plotters/plotter.h>
 %include <exporters/export_d356.h>
-%include <exporters/export_footprints_placefile.h>
+%include <exporters/place_file_exporter.h>
 %include <exporters/export_vrml.h>
 %include <exporters/gendrill_file_writer_base.h>
 %include <exporters/gendrill_Excellon_writer.h>