summaryrefslogtreecommitdiff
path: root/src/input/input_file.c
diff options
context:
space:
mode:
authorGuenter Bartsch <guenter@users.sourceforge.net>2002-10-14 15:46:48 +0000
committerGuenter Bartsch <guenter@users.sourceforge.net>2002-10-14 15:46:48 +0000
commitbcaee71a3a763a545e1f8457aca26dc679462677 (patch)
tree191c500351cb4073c6d998e6112a6b68f19790f4 /src/input/input_file.c
parentde10300bdc6457c36598f4287d42c4a5b2e82d71 (diff)
downloadxine-lib-bcaee71a3a763a545e1f8457aca26dc679462677.tar.gz
xine-lib-bcaee71a3a763a545e1f8457aca26dc679462677.tar.bz2
introduction of xine_stream_t and async xine events - all still in developement
CVS patchset: 2828 CVS date: 2002/10/14 15:46:48
Diffstat (limited to 'src/input/input_file.c')
-rw-r--r--src/input/input_file.c641
1 files changed, 289 insertions, 352 deletions
diff --git a/src/input/input_file.c b/src/input/input_file.c
index 2550cd2ca..4aeb23796 100644
--- a/src/input/input_file.c
+++ b/src/input/input_file.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: input_file.c,v 1.60 2002/09/22 14:29:40 mroi Exp $
+ * $Id: input_file.c,v 1.61 2002/10/14 15:47:17 guenter Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -43,25 +43,258 @@ extern int errno;
#define MAXFILES 65535
-#ifdef __GNUC__
-#define LOG_MSG_STDERR(xine, message, args...) { \
- xine_log(xine, XINE_LOG_MSG, message, ##args); \
- fprintf(stderr, message, ##args); \
- }
-#define LOG_MSG(xine, message, args...) { \
- xine_log(xine, XINE_LOG_MSG, message, ##args); \
- printf(message, ##args); \
+typedef struct {
+
+ input_class_t input_class;
+
+ xine_t *xine;
+ config_values_t *config;
+
+ int show_hidden_files;
+ char *origin_path;
+
+ int mrls_allocated_entries;
+ xine_mrl_t **mrls;
+
+} file_input_class_t;
+
+typedef struct {
+ input_plugin_t input_plugin;
+
+ xine_stream_t *stream;
+
+ int fh;
+ char *mrl;
+
+ FILE *sub;
+
+} file_input_plugin_t;
+
+
+static uint32_t file_plugin_get_capabilities (input_plugin_t *this_gen) {
+
+ return INPUT_CAP_SEEKABLE | INPUT_CAP_SPULANG;
+}
+
+
+static off_t file_plugin_read (input_plugin_t *this_gen, char *buf, off_t len) {
+ file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
+
+ return read (this->fh, buf, len);
+}
+
+/*
+ * helper function to release buffer
+ * in case demux thread is cancelled
+ */
+static void pool_release_buffer (void *arg) {
+ buf_element_t *buf = (buf_element_t *) arg;
+ if( buf != NULL )
+ buf->free_buffer(buf);
+}
+
+static buf_element_t *file_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo) {
+
+ off_t num_bytes, total_bytes;
+ file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
+ buf_element_t *buf = fifo->buffer_pool_alloc (fifo);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
+ pthread_cleanup_push( pool_release_buffer, buf );
+
+ buf->content = buf->mem;
+ buf->type = BUF_DEMUX_BLOCK;
+ total_bytes = 0;
+
+ while (total_bytes < todo) {
+ pthread_testcancel();
+ num_bytes = read (this->fh, buf->mem + total_bytes, todo-total_bytes);
+ if (num_bytes <= 0) {
+ if (num_bytes < 0)
+ xine_log (this->stream->xine, XINE_LOG_MSG,
+ _("input_file: read error (%s)\n"), strerror(errno));
+ buf->free_buffer (buf);
+ buf = NULL;
+ break;
+ }
+ total_bytes += num_bytes;
}
-#else
-#define LOG_MSG_STDERR(xine, ...) { \
- xine_log(xine, XINE_LOG_MSG, __VA_ARGS__); \
- fprintf(stderr, __VA_ARGS__); \
+
+ if( buf != NULL )
+ buf->size = total_bytes;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
+ pthread_cleanup_pop(0);
+
+ return buf;
+}
+
+static off_t file_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) {
+ file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
+
+ return lseek (this->fh, offset, origin);
+}
+
+static off_t file_plugin_get_current_pos (input_plugin_t *this_gen){
+ file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
+
+ if (this->fh <0)
+ return 0;
+
+ return lseek (this->fh, 0, SEEK_CUR);
+}
+
+static off_t file_plugin_get_length (input_plugin_t *this_gen) {
+
+ struct stat buf ;
+ file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
+
+ if (this->fh <0)
+ return 0;
+
+ if (fstat (this->fh, &buf) == 0) {
+ return buf.st_size;
+ } else
+ perror ("system call fstat");
+ return 0;
+}
+
+static uint32_t file_plugin_get_blocksize (input_plugin_t *this_gen) {
+ return 0;
+}
+
+/*
+ * Return 1 is filepathname is a directory, otherwise 0
+ */
+static int is_a_dir(char *filepathname) {
+ struct stat pstat;
+
+ stat(filepathname, &pstat);
+
+ return (S_ISDIR(pstat.st_mode));
+}
+
+static int file_plugin_eject_media (input_plugin_t *this_gen) {
+ return 1; /* doesn't make sense */
+}
+
+static char* file_plugin_get_mrl (input_plugin_t *this_gen) {
+ file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
+
+ return this->mrl;
+}
+
+static int file_plugin_get_optional_data (input_plugin_t *this_gen,
+ void *data, int data_type) {
+
+ file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
+
+#ifdef LOG
+ printf ("input_file: get optional data, type %08x, sub %p\n",
+ data_type, this->sub);
+#endif
+
+ switch(data_type) {
+ case INPUT_OPTIONAL_DATA_TEXTSPU0:
+ if(this->sub) {
+ FILE **tmp;
+
+ /* dirty hacks... */
+ tmp = data;
+ *tmp = this->sub;
+
+ return INPUT_OPTIONAL_SUCCESS;
+ }
+ break;
+
+ case INPUT_OPTIONAL_DATA_SPULANG:
+ sprintf(data, "%3s", (this->sub) ? "sub" : "none");
+ return INPUT_OPTIONAL_SUCCESS;
+ break;
+
+ default:
+ return INPUT_OPTIONAL_UNSUPPORTED;
+ break;
+
}
-#define LOG_MSG(xine, ...) { \
- xine_log(xine, XINE_LOG_MSG, __VA_ARGS__); \
- printf(__VA_ARGS__); \
+
+ return INPUT_OPTIONAL_UNSUPPORTED;
+}
+
+static void file_plugin_dispose (input_plugin_t *this_gen ) {
+ file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
+
+ close(this->fh);
+
+ if (this->sub)
+ fclose (this->sub);
+
+ free (this->mrl);
+
+ free (this);
+}
+
+static void *open_plugin (void *cls_gen, xine_stream_t *stream,
+ const void *data) {
+
+ file_input_class_t *cls = (file_input_class_t *) cls_gen;
+ file_input_plugin_t *this;
+ char *mrl = strdup ((char *) data);
+ FILE *sub;
+ char *filename, *subtitle;
+ int fh;
+
+ if (!strncasecmp (mrl, "file://", 7))
+ filename = &mrl[7];
+ else
+ filename = mrl;
+
+ subtitle = strrchr (filename, '%');
+ if (subtitle) {
+ *subtitle = 0;
+ subtitle++;
+
+ xine_log (cls->xine, XINE_LOG_MSG,
+ _("input_file: trying to open subtitle file '%s'\n"),
+ subtitle);
+
+ sub = fopen (subtitle, "r");
+
+ } else
+ sub = NULL;
+
+
+ fh = open (filename, O_RDONLY);
+
+ if (fh == -1) {
+ free (mrl);
+ return NULL;
}
-#endif
+
+ this = (file_input_plugin_t *) xine_xmalloc (sizeof (file_input_plugin_t));
+ this->stream = stream;
+ this->mrl = mrl;
+ this->fh = fh;
+ this->sub = sub;
+
+ this->input_plugin.get_capabilities = file_plugin_get_capabilities;
+ this->input_plugin.read = file_plugin_read;
+ this->input_plugin.read_block = file_plugin_read_block;
+ this->input_plugin.seek = file_plugin_seek;
+ this->input_plugin.get_current_pos = file_plugin_get_current_pos;
+ this->input_plugin.get_length = file_plugin_get_length;
+ this->input_plugin.get_blocksize = file_plugin_get_blocksize;
+ this->input_plugin.get_mrl = file_plugin_get_mrl;
+ this->input_plugin.get_optional_data = file_plugin_get_optional_data;
+ this->input_plugin.dispose = file_plugin_dispose;
+
+ return this;
+}
+
+
+/*
+ * plugin class functions
+ */
#ifndef S_ISLNK
#define S_ISLNK(mode) 0
@@ -85,38 +318,16 @@ extern int errno;
#define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
#endif
-typedef struct {
- input_plugin_t input_plugin;
-
- xine_t *xine;
-
- int fh;
- int show_hidden_files;
- char *origin_path;
- FILE *sub;
- char *mrl;
- config_values_t *config;
-
- int mrls_allocated_entries;
- xine_mrl_t **mrls;
-
-} file_input_plugin_t;
-
-
-/* ***************************************************************************
- * PRIVATES FUNCTIONS
- */
-
/*
* Callback for config changes.
*/
static void hidden_bool_cb(void *data, xine_cfg_entry_t *cfg) {
- file_input_plugin_t *this = (file_input_plugin_t *) data;
+ file_input_class_t *this = (file_input_class_t *) data;
this->show_hidden_files = cfg->num_value;
}
static void origin_change_cb(void *data, xine_cfg_entry_t *cfg) {
- file_input_plugin_t *this = (file_input_plugin_t *) data;
+ file_input_class_t *this = (file_input_class_t *) data;
this->origin_path = cfg->str_value;
}
@@ -206,7 +417,9 @@ static uint32_t get_file_type(char *filepathname, char *origin, xine_t *xine) {
if((lstat(filepathname, &pstat)) < 0) {
sprintf(buf, "%s/%s", origin, filepathname);
if((lstat(buf, &pstat)) < 0) {
- LOG_MSG(xine, _("lstat failed for %s{%s}\n"), filepathname, origin);
+#ifdef LOG
+ printf ("lstat failed for %s{%s}\n", filepathname, origin);
+#endif
file_type |= mrl_unknown;
return file_type;
}
@@ -257,179 +470,17 @@ static off_t get_file_size(char *filepathname, char *origin) {
return pstat.st_size;
}
-/*
- * END OF PRIVATES
- *****************************************************************************/
-/*
- *
- */
-static uint32_t file_plugin_get_capabilities (input_plugin_t *this_gen) {
-
- return INPUT_CAP_SEEKABLE | INPUT_CAP_PREVIEW | INPUT_CAP_GET_DIR | INPUT_CAP_SPULANG;
-}
-
-/*
- *
- */
-static int file_plugin_open (input_plugin_t *this_gen, const char *mrl) {
-
- char *filename, *subtitle;
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
-
- if (this->mrl)
- free (this->mrl);
-
- this->mrl = strdup(mrl);
-
- if (!strncasecmp (this->mrl, "file://", 7))
- filename = &this->mrl[7];
- else
- filename = this->mrl;
-
- subtitle = strrchr (filename, '%');
- if (subtitle) {
- *subtitle = 0;
- subtitle++;
-
- LOG_MSG(this->xine, _("input_file: trying to open subtitle file '%s'\n"),
- subtitle);
-
- this->sub = fopen (subtitle, "r");
-
- } else
- this->sub = NULL;
-
-
- this->fh = open (filename, O_RDONLY);
-
- if (this->fh == -1) {
- return 0;
- }
-
- return 1;
-}
-
-/*
- *
- */
-static off_t file_plugin_read (input_plugin_t *this_gen, char *buf, off_t len) {
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
-
- return read (this->fh, buf, len);
-}
-
-/*
- * helper function to release buffer
- * in case demux thread is cancelled
- */
-static void pool_release_buffer (void *arg) {
- buf_element_t *buf = (buf_element_t *) arg;
- if( buf != NULL )
- buf->free_buffer(buf);
-}
-
-/*
- *
- */
-static buf_element_t *file_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo) {
-
- off_t num_bytes, total_bytes;
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
- buf_element_t *buf = fifo->buffer_pool_alloc (fifo);
-
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
- pthread_cleanup_push( pool_release_buffer, buf );
-
- buf->content = buf->mem;
- buf->type = BUF_DEMUX_BLOCK;
- total_bytes = 0;
-
- while (total_bytes < todo) {
- pthread_testcancel();
- num_bytes = read (this->fh, buf->mem + total_bytes, todo-total_bytes);
- if (num_bytes <= 0) {
- if (num_bytes < 0)
- LOG_MSG_STDERR(this->xine, _("input_file: read error (%s)\n"), strerror(errno));
- buf->free_buffer (buf);
- buf = NULL;
- break;
- }
- total_bytes += num_bytes;
- }
-
- if( buf != NULL )
- buf->size = total_bytes;
-
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
- pthread_cleanup_pop(0);
-
- return buf;
-}
-
-/*
- *
- */
-static off_t file_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) {
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
-
- return lseek (this->fh, offset, origin);
-}
-
-/*
- *
- */
-static off_t file_plugin_get_current_pos (input_plugin_t *this_gen){
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
-
- if (this->fh <0)
- return 0;
-
- return lseek (this->fh, 0, SEEK_CUR);
-}
-
-/*
- *
- */
-static off_t file_plugin_get_length (input_plugin_t *this_gen) {
-
- struct stat buf ;
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
-
- if (this->fh <0)
- return 0;
-
- if (fstat (this->fh, &buf) == 0) {
- return buf.st_size;
- } else
- perror ("system call fstat");
- return 0;
+static char *file_class_get_description (input_class_t *this_gen) {
+ return _("file input plugin");
}
-/*
- *
- */
-static uint32_t file_plugin_get_blocksize (input_plugin_t *this_gen) {
- return 0;
-}
+static xine_mrl_t **file_class_get_dir (input_class_t *this_gen,
+ const char *filename, int *nFiles) {
-/*
- * Return 1 is filepathname is a directory, otherwise 0
- */
-static int is_a_dir(char *filepathname) {
- struct stat pstat;
-
- stat(filepathname, &pstat);
+ /* FIXME: this code needs cleanup badly */
- return (S_ISDIR(pstat.st_mode));
-}
-
-/*
- *
- */
-static xine_mrl_t **file_plugin_get_dir (input_plugin_t *this_gen,
- const char *filename, int *nFiles) {
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
+ file_input_class_t *this = (file_input_class_t *) this_gen;
struct dirent *pdirent;
DIR *pdir;
xine_mrl_t *hide_files, *dir_files, *norm_files;
@@ -522,10 +573,8 @@ static xine_mrl_t **file_plugin_get_dir (input_plugin_t *this_gen,
memset(linkbuf, 0, sizeof(linkbuf));
linksize = readlink(fullfilename, linkbuf, XINE_PATH_MAX + XINE_NAME_MAX);
- if(linksize < 0) {
- LOG_MSG_STDERR(this->xine, _("%s(%d): readlink() failed: %s\n"),
- __XINE_FUNCTION__, __LINE__, strerror(errno));
- }
+ if(linksize < 0)
+ printf ("input_file: readlink() failed: %s\n", strerror(errno));
else {
dir_files[num_dir_files].link = (char *) xine_xmalloc(linksize + 1);
strncpy(dir_files[num_dir_files].link, linkbuf, linksize);
@@ -562,8 +611,7 @@ static xine_mrl_t **file_plugin_get_dir (input_plugin_t *this_gen,
linksize = readlink(fullfilename, linkbuf, XINE_PATH_MAX + XINE_NAME_MAX);
if(linksize < 0) {
- LOG_MSG_STDERR(this->xine, _("%s(%d): readlink() failed: %s\n"),
- __XINE_FUNCTION__, __LINE__, strerror(errno));
+ printf ("input_file: readlink() failed: %s\n", strerror(errno));
}
else {
hide_files[num_hide_files].link = (char *)
@@ -598,8 +646,7 @@ static xine_mrl_t **file_plugin_get_dir (input_plugin_t *this_gen,
linksize = readlink(fullfilename, linkbuf, XINE_PATH_MAX + XINE_NAME_MAX);
if(linksize < 0) {
- LOG_MSG_STDERR(this->xine, _("%s(%d): readlink() failed: %s\n"),
- __XINE_FUNCTION__, __LINE__, strerror(errno));
+ printf ("input_file: readlink() failed: %s\n", strerror(errno));
}
else {
norm_files[num_norm_files].link = (char *)
@@ -743,143 +790,29 @@ static xine_mrl_t **file_plugin_get_dir (input_plugin_t *this_gen,
return this->mrls;
}
-/*
- *
- */
-static int file_plugin_eject_media (input_plugin_t *this_gen) {
- return 1; /* doesn't make sense */
-}
-
-/*
- *
- */
-static char* file_plugin_get_mrl (input_plugin_t *this_gen) {
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
-
- return this->mrl;
-}
-
-/*
- *
- */
-static void file_plugin_close (input_plugin_t *this_gen) {
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
-
- close(this->fh);
- this->fh = -1;
-
- if (this->sub) {
- fclose (this->sub);
- this->sub = NULL;
- }
-}
-
-/*
- *
- */
-static void file_plugin_stop (input_plugin_t *this_gen) {
-
- file_plugin_close(this_gen);
-}
-
-/*
- *
- */
-static char *file_plugin_get_description (input_plugin_t *this_gen) {
- return _("plain file input plugin as shipped with xine");
-}
-
-/*
- *
- */
-static char *file_plugin_get_identifier (input_plugin_t *this_gen) {
- return "file";
-}
-
-/*
- *
- */
-static int file_plugin_get_optional_data (input_plugin_t *this_gen,
- void *data, int data_type) {
-
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
-
-#ifdef LOG
- LOG_MSG(this->xine, _("input_file: get optional data, type %08x, sub %p\n"),
- data_type, this->sub);
-#endif
-
- switch(data_type) {
- case INPUT_OPTIONAL_DATA_TEXTSPU0:
- if(this->sub) {
- FILE **tmp;
-
- /* dirty hacks... */
- tmp = data;
- *tmp = this->sub;
-
- return INPUT_OPTIONAL_SUCCESS;
- }
- break;
-
- case INPUT_OPTIONAL_DATA_SPULANG:
- sprintf(data, "%3s", (this->sub) ? "sub" : "none");
- return INPUT_OPTIONAL_SUCCESS;
- break;
-
- default:
- return INPUT_OPTIONAL_UNSUPPORTED;
- break;
-
- }
-
- return INPUT_OPTIONAL_UNSUPPORTED;
-}
-
-static void file_plugin_dispose (input_plugin_t *this_gen ) {
- file_input_plugin_t *this = (file_input_plugin_t *) this_gen;
-
- if (this->mrl)
- free (this->mrl);
+static void file_class_dispose (input_class_t *this_gen) {
+ file_input_class_t *this = (file_input_class_t *) this_gen;
free (this->mrls);
free (this);
}
-static void *init_input_plugin (xine_t *xine, void *data) {
+static void *init_plugin (xine_t *xine, void *data) {
- file_input_plugin_t *this;
+ file_input_class_t *this;
config_values_t *config;
- this = (file_input_plugin_t *) xine_xmalloc (sizeof (file_input_plugin_t));
- config = xine->config;
- this->xine = xine;
+ this = (file_input_class_t *) xine_xmalloc (sizeof (file_input_class_t));
- this->input_plugin.get_capabilities = file_plugin_get_capabilities;
- this->input_plugin.open = file_plugin_open;
- this->input_plugin.read = file_plugin_read;
- this->input_plugin.read_block = file_plugin_read_block;
- this->input_plugin.seek = file_plugin_seek;
- this->input_plugin.get_current_pos = file_plugin_get_current_pos;
- this->input_plugin.get_length = file_plugin_get_length;
- this->input_plugin.get_blocksize = file_plugin_get_blocksize;
- this->input_plugin.get_dir = file_plugin_get_dir;
- this->input_plugin.eject_media = file_plugin_eject_media;
- this->input_plugin.get_mrl = file_plugin_get_mrl;
- this->input_plugin.close = file_plugin_close;
- this->input_plugin.stop = file_plugin_stop;
- this->input_plugin.get_description = file_plugin_get_description;
- this->input_plugin.get_identifier = file_plugin_get_identifier;
- this->input_plugin.get_autoplay_list = NULL;
- this->input_plugin.get_optional_data = file_plugin_get_optional_data;
- this->input_plugin.dispose = file_plugin_dispose;
- this->input_plugin.is_branch_possible = NULL;
+ this->xine = xine;
+ this->config = xine->config;
+ config = xine->config;
+
+ this->input_class.get_dir = file_class_get_dir;
+ this->input_class.get_description = file_class_get_description;
+ this->input_class.get_autoplay_list = NULL;
+ this->input_class.dispose = file_class_dispose;
- this->fh = -1;
- this->sub = NULL;
- this->mrl = NULL;
- this->config = config;
-
this->mrls = (xine_mrl_t **) xine_xmalloc(sizeof(xine_mrl_t*));
this->mrls_allocated_entries = 0;
@@ -889,14 +822,18 @@ static void *init_input_plugin (xine_t *xine, void *data) {
if(getcwd(current_dir, sizeof(current_dir)) == NULL)
strcpy(current_dir, ".");
- this->origin_path = config->register_string(this->config, "input.file_origin_path",
- current_dir, _("file browsing start location"),
- NULL, 0, origin_change_cb, (void *) this);
+ this->origin_path = config->register_string(config, "input.file_origin_path",
+ current_dir,
+ _("file browsing start location"),
+ NULL, 0, origin_change_cb,
+ (void *) this);
}
- this->show_hidden_files = this->config->register_bool(this->config, "input.file_hidden_files",
- 1, _("list hidden files"),
- NULL, 10, hidden_bool_cb, (void *) this);
+ this->show_hidden_files = config->register_bool(config,
+ "input.file_hidden_files",
+ 1, _("list hidden files"),
+ NULL, 10, hidden_bool_cb,
+ (void *) this);
return this;
}
@@ -907,7 +844,7 @@ static void *init_input_plugin (xine_t *xine, void *data) {
plugin_info_t xine_plugin_info[] = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_INPUT, 8, "file", XINE_VERSION_CODE, NULL, init_input_plugin },
+ { PLUGIN_INPUT, 8, "file", XINE_VERSION_CODE, NULL, init_plugin, open_plugin },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};