pcb-rnd - plugin development - registering I/O

A plugin can serve as an I/O interface. Note the difference between plain import/export and a full I/O - do not implement an I/O for a simple import or export task but do not implement a pair of import/export plugins for an I/O task either.

A plugin can register multiple I/O interfaces. This is typical for formats with multiple versions, or for format families with alternative sub-formats for the same purpose. But the most common setup is that an io plugin registers one I/O interface.

Each I/O interface has a name and priorities. The name is displayed to the user and priorities determine in what order different options are presented - this helps ordering common file formats first, exotic options last.

Each I/O interface also has hooks for testing whether it will be able to load an input file, before doing the real parse. When a file needs to be loaded, the plugins that will attempt to load are not selected by the file name, but by file content.

For more details on the I/O interface fields, callback functions and mechanism, refer to src/plug_io.h.

Registering an I/O interface

Declare a static variable of pcb_plug_io_t and fill it in from the plugin init callback:

static pcb_plug_io_t io_pluginname;

...

int pplg_init_io_pluginname(void)
{
	PCB_API_CHK_VER;

	memset(&io_pluginname, 0, sizeof(io_pluginname));

	/* these are mandatory: */
	io_pluginname.default_fmt = "shortname";
	io_pluginname.description = "longname";
	io_pluginname.save_preference_prio = 89;
	io_pluginname.default_extension = ".foo";
	io_pluginname.fp_extension = ".bar";
	io_pluginname.mime_type = "application/x-pcb-layout";
	io_pluginname.fmt_support_prio = io_pluginname_fmt;
	io_pluginname.test_parse = io_pluginname_test_parse;

	/* these are optional (leave NULL if not supported): */
	io_pluginname.plugin_data = &ctx;
	io_pluginname.parse_pcb = io_pluginname_parse_pcb;
	io_pluginname.parse_footprint = io_pluginname_parse_footprint;
	io_pluginname.parse_font = io_pluginname_parse_font;
	io_pluginname.write_buffer = io_pluginname_write_buffer;
	io_pluginname.write_footprint = io_pluginname_write_footprint;
	io_pluginname.write_pcb = io_pluginname_write_pcb;

	/* the actual registration */
	PCB_HOOK_REGISTER(pcb_plug_io_t, pcb_plug_io_chain, &io_pluginname);

The memset is required in case the core struct is extended with new fields. The convention is that NULL or 0 is the default/unused value. With the memset extending the core struct won't force us to update all plugins.

Unregistering an I/O interface

On plugin uninit any I/O interface registered by the plugin must be removed. This is done using the PCB_HOOK_UNREGISTER() macro:

	PCB_HOOK_UNREGISTER(pcb_plug_io_t, pcb_plug_io_chain, &io_pluginname);