# 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);