diff --git a/pymolfile/molfile/2 b/pymolfile/molfile/2
new file mode 100644
index 0000000000000000000000000000000000000000..6e6564916a01e5f5c6b2c0876b3fd0d332d84756
--- /dev/null
+++ b/pymolfile/molfile/2
@@ -0,0 +1,502 @@
+/* Hey emacs this is -*- C -*- and this is my editor vim.
+ * 
+ * molfile.c : C and Fortran interfaces for molfile_plugins
+ * Copyright (c) Berk Onat <b.onat@warwick.ac.uk> 2017
+ *
+ * This program is under BSD LICENSE
+ */
+
+/*
+ * The code is written following the plugin test 
+ * context of f77_molfile.c by Axel Kohlmeyer and 
+ * in molfile_plugin/src/f77 and catdcd.c by 
+ * Justin Gullingsrud of VMD plugins.
+ */
+
+/* Get HAVE_CONFIG_H */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <ctype.h>
+
+/* get fixed-width types if we are using ANSI C99 */
+#ifdef HAVE_STDINT_H
+#  include <stdint.h>
+#elif (defined HAVE_INTTYPES_H)
+#  include <inttypes.h>
+#endif
+
+#include "pymolfile.h"
+
+int numplugins=0;
+molfile_plugin_t** plugin_list;
+
+/* * * * * * * * * * * * * * * * * * * * * * *
+ * Helper functions to set and store plugins *
+ * * * * * * * * * * * * * * * * * * * * * * */
+
+#if PY_VERSION_HEX >= 0x03000000
+#define PyInt_AsSsize_t PyLong_AsSsize_t
+#define PyInt_AsLong PyLong_AsLong
+#define PyArray_Check(op) PyObject_TypeCheck(op, &PyArray_Type)
+#define PyString_FromString PyBytes_FromString
+#define PyUString_Check PyUnicode_Check
+#define PyUString_GET_SIZE PyUnicode_GET_SIZE
+#define PyUString_FromFormat PyUnicode_FromFormat
+#define PyInt_FromLong PyLong_FromLong
+#define PyString_Type PyBytes_Type
+#define PyInt_Type PyLong_Type
+
+#else
+#define PyBytes_FromString PyString_FromString
+#endif
+
+
+#define NPY_NEXT_ALIGNED_OFFSET(offset, alignment) \
+                (((offset) + (alignment) - 1) & (-(alignment)))
+
+#if 0
+static NPY_INLINE npy_bool
+_is_basic_python_type(PyTypeObject *tp)
+{
+    return (
+        /* Basic number types */
+        tp == &PyBool_Type ||
+#if PY_VERSION_HEX >= 0x03000000
+        tp == &PyInt_Type ||
+#endif
+        tp == &PyLong_Type ||
+        tp == &PyFloat_Type ||
+        tp == &PyComplex_Type ||
+
+        /* Basic sequence types */
+        tp == &PyList_Type ||
+        tp == &PyTuple_Type ||
+        tp == &PyDict_Type ||
+        tp == &PySet_Type ||
+        tp == &PyFrozenSet_Type ||
+        tp == &PyUnicode_Type ||
+        tp == &PyBytes_Type ||
+#if PY_VERSION_HEX >= 0x03000000
+        tp == &PyString_Type ||
+#endif
+
+        /* other builtins */
+        tp == &PySlice_Type ||
+        tp == Py_TYPE(Py_None) ||
+        tp == Py_TYPE(Py_Ellipsis) ||
+        tp == Py_TYPE(Py_NotImplemented) ||
+
+        /* TODO: ndarray, but we can't see PyArray_Type here */
+
+        /* sentinel to swallow trailing || */
+        NPY_FALSE
+    );
+}
+
+static NPY_INLINE PyObject *
+maybe_get_attr(PyObject *obj, char *name)
+{
+    PyTypeObject *tp = Py_TYPE(obj);
+    PyObject *res = (PyObject *)NULL;
+
+    /* Attribute referenced by (char *)name */
+    if (tp->tp_getattr != NULL) {
+        res = (*tp->tp_getattr)(obj, name);
+        if (res == NULL) {
+            PyErr_Clear();
+        }
+    }
+    /* Attribute referenced by (PyObject *)name */
+    else if (tp->tp_getattro != NULL) {
+#if PY_VERSION_HEX >= 0x03000000
+        PyObject *w = PyUnicode_InternFromString(name);
+#else
+        PyObject *w = PyString_InternFromString(name);
+#endif
+        if (w == NULL) {
+            return (PyObject *)NULL;
+        }
+        res = (*tp->tp_getattro)(obj, w);
+        Py_DECREF(w);
+        if (res == NULL) {
+            PyErr_Clear();
+        }
+    }
+    return res;
+}
+
+static NPY_INLINE PyObject *
+maybe_set_attr(PyObject *obj, char *name, PyObject *attr)
+{
+    PyTypeObject *tp = Py_TYPE(obj);
+    int status;
+
+    /* Attribute referenced by (char *)name */
+    if (tp->tp_setattr != NULL) {
+        status = (*tp->tp_setattr)(obj, name, attr);
+        if (status < 0) {
+            PyErr_Clear();
+            PyErr_Format(PyExc_IOError, "Error: no __array_interface__ attribute in object.");
+            return NULL;
+        }   
+    }   
+    /* Attribute referenced by (PyObject *)name */
+    else if (tp->tp_setattro != NULL) {
+#if PY_VERSION_HEX >= 0x03000000
+        PyObject *w = PyUnicode_InternFromString(name);
+#else
+        PyObject *w = PyString_InternFromString(name);
+#endif
+        if (w == NULL) {
+            printf("Name is NULL\n");
+            PyErr_Clear();
+            PyErr_Format(PyExc_IOError, "Error: no __array_interface__ attribute in object.");
+            return NULL;
+        }
+        //status = (*tp->tp_setattro)(obj, w, attr);
+        //status = PyObject_GenericSetAttr(obj, w, attr);
+        status = PyObject_SetAttrString(obj, name, attr);
+        if (status < 0) {
+            PyErr_Clear();
+            PyErr_Format(PyExc_IOError, "Error: can not set interface attribute.");
+            return NULL;
+        }
+    }
+    return obj;
+}
+
+static int get_array_struct(PyObject* obj, int *maxndim, npy_intp *d_shape, PyArrayInterface* inter)
+{
+    PyTypeObject *tp = Py_TYPE(obj);
+    PyObject* ret;
+    char* str;
+    int i;
+    str = "__array_struct__";
+    /* We do not need to check for special attributes on trivial types */
+    if (_is_basic_python_type(tp)) {
+        ret = NULL;
+    }   
+    /* obj has the __array_struct__ interface */
+    ret = maybe_get_attr(obj, str);
+    if (ret != NULL) {
+        int nd = -1;
+        if (PyCapsule_CheckExact(ret)) {
+            PyArrayInterface *inter;
+            inter = (PyArrayInterface *)NpyCapsule_AsVoidPtr(ret);
+            if (inter->two == 2) {
+                nd = inter->nd;
+                if (nd >= 0) {
+                    if (nd < *maxndim) {
+                        *maxndim = nd;
+                    }
+                    for (i=0; i<*maxndim; i++) {
+                        d_shape[i] = inter->shape[i];
+                    }
+                }
+            }
+        }
+        if(nd >= 0){ 
+            return 0;
+        } else {
+            return -1;
+        }
+    } else {
+        return -1;
+    }
+}
+
+PyObject* get_array_attr_interface(PyObject* obj, char* str, int *maxndim, npy_intp *d_shape){
+    PyTypeObject *tp = Py_TYPE(obj);
+    char* dictstr;
+    int i, failflag=0;
+    dictstr = "__array_interface__";
+    PyObject* ret;
+    PyObject* retuni = NULL;
+    PyObject* newi = NULL;
+    PyObject* objj = NULL;
+    if (_is_basic_python_type(tp)) {
+        ret = NULL;
+    }   
+    /* obj has the __array_interface__ interface */
+    ret = maybe_get_attr(obj, dictstr);
+    if (ret != NULL) {
+        int nd = -1;
+        if (PyDict_Check(ret)) {
+            objj = PyDict_GetItemString(ret, str);
+	    if (str == "shape"){
+              if (objj && PyTuple_Check(objj)) {
+                nd = PyTuple_GET_SIZE(objj);
+                if (nd >= 0) {
+                    maxndim = &nd;
+                    for (i=0; i<nd; i++) {
+                        retuni = PyTuple_GET_ITEM(objj, i);
+                    }
+                }
+              }
+	    } else {
+                PyObject* tuple = PyTuple_New(1);
+                PyTuple_SET_ITEM(tuple, 0, objj);
+                return (PyObject*) tuple;
+            }
+        }
+        if (nd >= 0) {
+            PyObject* tuple = PyTuple_New(1);
+            PyTuple_SET_ITEM(tuple, 0, objj);
+            return (PyObject*) tuple;
+        } else {
+            failflag = 1;
+        }
+    } else {
+        failflag = 1;
+    }
+    if (failflag){
+        PyErr_Clear();
+        PyErr_Format(PyExc_IOError, "Error: can not get attribute of given numpy array.");
+        return NULL;
+    }
+}
+
+PyObject* get_descr_array_interface(PyObject* obj){
+    PyTypeObject *tp = Py_TYPE(obj);
+    char* dictstr;
+    char* descrstr;
+    int i, failflag=0;
+    dictstr = "__array_interface__";
+    descrstr = "descr";
+    PyObject* ret;
+    PyObject* retuni = NULL;
+    PyObject* newi = NULL;
+    PyObject* objj = NULL;
+    if (_is_basic_python_type(tp)) {
+        ret = NULL;
+    }   
+    /* obj has the __array_interface__ interface */
+    ret = maybe_get_attr(obj, dictstr);
+    if (ret != NULL) {
+        if (PyDict_Check(ret)) {
+            objj = PyDict_GetItemString(ret, descrstr);
+            return (PyObject*) objj;
+        } else {
+            failflag = 1;
+        }
+    } else {
+        failflag = 1;
+    }
+    if (failflag){
+        PyErr_Clear();
+        PyErr_Format(PyExc_IOError, "Error: can not get attribute of given numpy array.");
+        return NULL;
+    }
+}
+#endif
+
+molfile_plugin_t* get_plugin(molfile_plugin_t** plug_list, int plug_no)
+{
+    molfile_plugin_t* plugin;
+    if(plug_no < 0){
+	plugin = NULL;
+    } else {
+	plugin = plug_list[plug_no];
+    }
+    return plugin;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Interface functions to initialize molfile plugins *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* check validity of plugins and register them. */
+static int molfile_register(void*, vmdplugin_t *plugin) {
+    if (!plugin->type || !plugin->name || !plugin->author) {
+        // skipping plugin with incomplete header
+        return VMDPLUGIN_ERROR;
+    }
+    else if (plugin->abiversion != vmdplugin_ABIVERSION) {
+        // skipping plugin with incompatible ABI
+        return VMDPLUGIN_ERROR;
+    }
+    else if (0 != strncmp(plugin->type, "mol file", 8)) {
+        // skipping plugin of incompatible type
+        return VMDPLUGIN_ERROR;
+    } 
+    else if (numplugins >= MAXPLUGINS) {
+        // too many plugins: increase MAXPLUGINS
+        return VMDPLUGIN_ERROR;
+    }
+
+    //if (plugin_find(&plugindict, plugin->name) != NULL) {
+        // multiple plugins for file type
+    //    return VMDPLUGIN_ERROR;
+    //} else {
+        plugin_list[numplugins] = (molfile_plugin_t *) plugin;
+	//plugin_add(&plugindict, plugin->name, numplugins);
+        ++numplugins;
+        return VMDPLUGIN_SUCCESS;
+    //}
+}
+
+molfile_plugin_t** molfile_plugin_list(int maxsize)
+{
+    if(maxsize < MAXPLUGINS){
+        maxsize = MAXPLUGINS;
+    }
+    plugin_list = (molfile_plugin_t**) malloc(sizeof(molfile_plugin_t*)*maxsize);
+    return plugin_list;
+}
+
+/* register all available plugins and clear handles. */
+int molfile_init(void) 
+{
+    MOLFILE_INIT_ALL;
+    MOLFILE_REGISTER_ALL(NULL,molfile_register);
+    return numplugins;
+}
+
+/* unregister all available plugins */
+int molfile_finish(void) 
+{
+    MOLFILE_FINI_ALL;
+    return 0;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * *
+ * Wrappers to directly access molfile plugin*
+ *         functions and settings            *
+ * * * * * * * * * * * * * * * * * * * * * * */
+
+/* molfile_plugin_t access */
+
+/* Functions in molfile_plugin_t */
+
+PyObject* read_fill_structure(PyObject* molpack, PyObject* prototype)
+{
+//    Py_Initialize();
+    import_array();
+    int options = 0;
+    molfile_plugin_t* plugin;
+    void* file_handle;
+    molfile_atom_t* data;
+    int numatoms, status;
+    int nd;
+    PyObject *ret = NULL;
+    // Access plugin_handle values
+    MolObject* plugin_handle = (MolObject*) molpack;
+    plugin = plugin_handle->plugin;
+    file_handle = plugin_handle->file_handle;
+    numatoms = plugin_handle->natoms;
+    // Allocate memory for array of molfile_atom_t struct
+    data = (molfile_atom_t *)calloc(numatoms,sizeof(molfile_atom_t));
+    // Get array values in molfile_atom_t
+    if (plugin->read_structure) {
+        status = plugin->read_structure(file_handle, &options, data);
+        // Check if the plugin returns the results
+        if (status!=0){
+            PyErr_Format(PyExc_IOError, "Error accessing molfile_atom_t in read_structure function of plugin.");
+            return NULL;
+        }
+        nd = 1;
+        npy_intp dims[1] = { numatoms };
+        npy_intp strides[1] = { sizeof(molfile_atom_t) };
+        Py_INCREF(prototype);
+        ret = PyArray_NewFromDescr(Py_TYPE(prototype), PyArray_DESCR((PyArrayObject*)prototype), 
+	    	                   nd, dims,
+			           strides, data, 
+			           PyArray_FLAGS((PyArrayObject*)prototype), prototype);
+        Py_DECREF(prototype);
+        return (PyObject*) ret;
+    } else {
+        PyErr_Format(PyExc_AttributeError, "molfile plugin does not have read_structure function.");
+	Py_RETURN_NONE;
+    }
+}
+
+PyObject* read_fill_bonds(PyObject* molpack)
+{
+    import_array();
+    int options = 0;
+    molfile_plugin_t* plugin;
+    void* file_handle;
+    molfile_atom_t* data;
+    int numatoms, status;
+    int nd;
+    PyObject *ret = NULL;
+    PyObject *from_arr = NULL;
+    PyObject *to_arr = NULL;
+    PyObject *bondorder_arr = NULL;
+    PyObject *bondtype_arr = NULL;
+    PyObject *bondtypename_arr = NULL;
+    PyArrayInterface *inter = NULL;
+    // Access plugin_handle values
+    MolObject* plugin_handle = (MolObject*) molpack;
+    plugin = plugin_handle->plugin;
+    file_handle = plugin_handle->file_handle;
+    numatoms = plugin_handle->natoms;
+    if (plugin->read_bonds) {
+        int nbonds, *from, *to, *bondtype, nbondtypes;
+        float *bondorder;
+        char **bondtypename;
+        if ((status = plugin->read_bonds(file_handle, &nbonds, &from, &to, 
+				         &bondorder, &bondtype, &nbondtypes, &bondtypename))) {
+            PyErr_Format(PyExc_IOError, "Error accessing read_bonds function of plugin.");
+            return NULL;
+        }
+        inter = (PyArrayInterface*)malloc(sizeof(PyArrayInterface));
+        if (inter==NULL)
+            return PyErr_NoMemory();
+        inter->flags = NPY_ARRAY_NOTSWAPPED | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE;
+	ret = PyDict_New();
+        nd = 1;
+	if (nbonds>0) {
+            npy_intp dims[1] = { nbonds };
+            npy_intp strides[1] = { NPY_SIZEOF_INT };
+            from_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                            nd, dims,
+                                            strides, from, 
+                                            inter->flags, NULL);
+	    PyDict_SetItemString(ret, "from", from_arr);
+            to_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                          nd, dims,
+                                          strides, to, 
+                                          inter->flags, NULL);
+	    PyDict_SetItemString(ret, "to", to_arr);
+	    if (!bondorder) {
+                strides[0] = { NPY_SIZEOF_FLOAT };
+                bondorder_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_FLOAT), 
+                                                     nd, dims,
+                                                     strides, bondorder, 
+			                             inter->flags, NULL);
+	        PyDict_SetItemString(ret, "bondorder", bondorder_arr);
+	    }
+	    if (!bondtype) {
+                strides[0] = { NPY_SIZEOF_INT };
+                bondtype_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                    nd, dims,
+                                                    strides, bondtype, 
+			                            inter->flags, NULL);
+	        PyDict_SetItemString(ret, "bondtype", bondtype_arr);
+	    }
+	    if (!bondtypename) {
+                dims[0] = { nbondtypes };
+                strides[0] = { sizeof(NPY_STRING) };
+                bondtypename_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_STRING), 
+                                                        nd, dims,
+                                                        strides, bondtypename, 
+	                                                inter->flags, NULL);
+	        PyDict_SetItemString(ret, "bondtypename", bondtypename_arr);
+	    }
+            return (PyObject*) ret;
+	} else {
+            Py_RETURN_NONE;
+	}
+    } else {
+        PyErr_Format(PyExc_AttributeError, "molfile plugin does not have read_bonds function.");
+        Py_RETURN_NONE;
+    }
+}
+
diff --git a/pymolfile/molfile/] b/pymolfile/molfile/]
new file mode 100644
index 0000000000000000000000000000000000000000..8ef5a5c74426edbf644778abf1784348cdc038cf
--- /dev/null
+++ b/pymolfile/molfile/]
@@ -0,0 +1,678 @@
+/* Hey emacs this is -*- C -*- and this is my editor vim.
+ * 
+ * molfile.c : C and Fortran interfaces for molfile_plugins
+ * Copyright (c) Berk Onat <b.onat@warwick.ac.uk> 2017
+ *
+ * This program is under BSD LICENSE
+ */
+
+/*
+ * The code is written following the plugin test 
+ * context of f77_molfile.c by Axel Kohlmeyer and 
+ * in molfile_plugin/src/f77 and catdcd.c by 
+ * Justin Gullingsrud of VMD plugins.
+ */
+
+/* Get HAVE_CONFIG_H */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <ctype.h>
+
+/* get fixed-width types if we are using ANSI C99 */
+#ifdef HAVE_STDINT_H
+#  include <stdint.h>
+#elif (defined HAVE_INTTYPES_H)
+#  include <inttypes.h>
+#endif
+
+#include "pymolfile.h"
+
+int numplugins=0;
+molfile_plugin_t** plugin_list;
+
+/* * * * * * * * * * * * * * * * * * * * * * *
+ * Helper functions to set and store plugins *
+ * * * * * * * * * * * * * * * * * * * * * * */
+
+#if PY_VERSION_HEX >= 0x03000000
+#define PyInt_AsSsize_t PyLong_AsSsize_t
+#define PyInt_AsLong PyLong_AsLong
+#define PyArray_Check(op) PyObject_TypeCheck(op, &PyArray_Type)
+#define PyString_FromString PyBytes_FromString
+#define PyUString_Check PyUnicode_Check
+#define PyUString_GET_SIZE PyUnicode_GET_SIZE
+#define PyUString_FromFormat PyUnicode_FromFormat
+#define PyInt_FromLong PyLong_FromLong
+#define PyString_Type PyBytes_Type
+#define PyInt_Type PyLong_Type
+
+#else
+#define PyBytes_FromString PyString_FromString
+#endif
+
+
+#define NPY_NEXT_ALIGNED_OFFSET(offset, alignment) \
+                (((offset) + (alignment) - 1) & (-(alignment)))
+
+#if 0
+static NPY_INLINE npy_bool
+_is_basic_python_type(PyTypeObject *tp)
+{
+    return (
+        /* Basic number types */
+        tp == &PyBool_Type ||
+#if PY_VERSION_HEX >= 0x03000000
+        tp == &PyInt_Type ||
+#endif
+        tp == &PyLong_Type ||
+        tp == &PyFloat_Type ||
+        tp == &PyComplex_Type ||
+
+        /* Basic sequence types */
+        tp == &PyList_Type ||
+        tp == &PyTuple_Type ||
+        tp == &PyDict_Type ||
+        tp == &PySet_Type ||
+        tp == &PyFrozenSet_Type ||
+        tp == &PyUnicode_Type ||
+        tp == &PyBytes_Type ||
+#if PY_VERSION_HEX >= 0x03000000
+        tp == &PyString_Type ||
+#endif
+
+        /* other builtins */
+        tp == &PySlice_Type ||
+        tp == Py_TYPE(Py_None) ||
+        tp == Py_TYPE(Py_Ellipsis) ||
+        tp == Py_TYPE(Py_NotImplemented) ||
+
+        /* TODO: ndarray, but we can't see PyArray_Type here */
+
+        /* sentinel to swallow trailing || */
+        NPY_FALSE
+    );
+}
+
+static NPY_INLINE PyObject *
+maybe_get_attr(PyObject *obj, char *name)
+{
+    PyTypeObject *tp = Py_TYPE(obj);
+    PyObject *res = (PyObject *)NULL;
+
+    /* Attribute referenced by (char *)name */
+    if (tp->tp_getattr != NULL) {
+        res = (*tp->tp_getattr)(obj, name);
+        if (res == NULL) {
+            PyErr_Clear();
+        }
+    }
+    /* Attribute referenced by (PyObject *)name */
+    else if (tp->tp_getattro != NULL) {
+#if PY_VERSION_HEX >= 0x03000000
+        PyObject *w = PyUnicode_InternFromString(name);
+#else
+        PyObject *w = PyString_InternFromString(name);
+#endif
+        if (w == NULL) {
+            return (PyObject *)NULL;
+        }
+        res = (*tp->tp_getattro)(obj, w);
+        Py_DECREF(w);
+        if (res == NULL) {
+            PyErr_Clear();
+        }
+    }
+    return res;
+}
+
+static NPY_INLINE PyObject *
+maybe_set_attr(PyObject *obj, char *name, PyObject *attr)
+{
+    PyTypeObject *tp = Py_TYPE(obj);
+    int status;
+
+    /* Attribute referenced by (char *)name */
+    if (tp->tp_setattr != NULL) {
+        status = (*tp->tp_setattr)(obj, name, attr);
+        if (status < 0) {
+            PyErr_Clear();
+            PyErr_Format(PyExc_IOError, "Error: no __array_interface__ attribute in object.");
+            return NULL;
+        }   
+    }   
+    /* Attribute referenced by (PyObject *)name */
+    else if (tp->tp_setattro != NULL) {
+#if PY_VERSION_HEX >= 0x03000000
+        PyObject *w = PyUnicode_InternFromString(name);
+#else
+        PyObject *w = PyString_InternFromString(name);
+#endif
+        if (w == NULL) {
+            printf("Name is NULL\n");
+            PyErr_Clear();
+            PyErr_Format(PyExc_IOError, "Error: no __array_interface__ attribute in object.");
+            return NULL;
+        }
+        //status = (*tp->tp_setattro)(obj, w, attr);
+        //status = PyObject_GenericSetAttr(obj, w, attr);
+        status = PyObject_SetAttrString(obj, name, attr);
+        if (status < 0) {
+            PyErr_Clear();
+            PyErr_Format(PyExc_IOError, "Error: can not set interface attribute.");
+            return NULL;
+        }
+    }
+    return obj;
+}
+
+static int get_array_struct(PyObject* obj, int *maxndim, npy_intp *d_shape, PyArrayInterface* inter)
+{
+    PyTypeObject *tp = Py_TYPE(obj);
+    PyObject* ret;
+    char* str;
+    int i;
+    str = "__array_struct__";
+    /* We do not need to check for special attributes on trivial types */
+    if (_is_basic_python_type(tp)) {
+        ret = NULL;
+    }   
+    /* obj has the __array_struct__ interface */
+    ret = maybe_get_attr(obj, str);
+    if (ret != NULL) {
+        int nd = -1;
+        if (PyCapsule_CheckExact(ret)) {
+            PyArrayInterface *inter;
+            inter = (PyArrayInterface *)NpyCapsule_AsVoidPtr(ret);
+            if (inter->two == 2) {
+                nd = inter->nd;
+                if (nd >= 0) {
+                    if (nd < *maxndim) {
+                        *maxndim = nd;
+                    }
+                    for (i=0; i<*maxndim; i++) {
+                        d_shape[i] = inter->shape[i];
+                    }
+                }
+            }
+        }
+        if(nd >= 0){ 
+            return 0;
+        } else {
+            return -1;
+        }
+    } else {
+        return -1;
+    }
+}
+
+PyObject* get_array_attr_interface(PyObject* obj, char* str, int *maxndim, npy_intp *d_shape){
+    PyTypeObject *tp = Py_TYPE(obj);
+    char* dictstr;
+    int i, failflag=0;
+    dictstr = "__array_interface__";
+    PyObject* ret;
+    PyObject* retuni = NULL;
+    PyObject* newi = NULL;
+    PyObject* objj = NULL;
+    if (_is_basic_python_type(tp)) {
+        ret = NULL;
+    }   
+    /* obj has the __array_interface__ interface */
+    ret = maybe_get_attr(obj, dictstr);
+    if (ret != NULL) {
+        int nd = -1;
+        if (PyDict_Check(ret)) {
+            objj = PyDict_GetItemString(ret, str);
+	    if (str == "shape"){
+              if (objj && PyTuple_Check(objj)) {
+                nd = PyTuple_GET_SIZE(objj);
+                if (nd >= 0) {
+                    maxndim = &nd;
+                    for (i=0; i<nd; i++) {
+                        retuni = PyTuple_GET_ITEM(objj, i);
+                    }
+                }
+              }
+	    } else {
+                PyObject* tuple = PyTuple_New(1);
+                PyTuple_SET_ITEM(tuple, 0, objj);
+                return (PyObject*) tuple;
+            }
+        }
+        if (nd >= 0) {
+            PyObject* tuple = PyTuple_New(1);
+            PyTuple_SET_ITEM(tuple, 0, objj);
+            return (PyObject*) tuple;
+        } else {
+            failflag = 1;
+        }
+    } else {
+        failflag = 1;
+    }
+    if (failflag){
+        PyErr_Clear();
+        PyErr_Format(PyExc_IOError, "Error: can not get attribute of given numpy array.");
+        return NULL;
+    }
+}
+
+PyObject* get_descr_array_interface(PyObject* obj){
+    PyTypeObject *tp = Py_TYPE(obj);
+    char* dictstr;
+    char* descrstr;
+    int i, failflag=0;
+    dictstr = "__array_interface__";
+    descrstr = "descr";
+    PyObject* ret;
+    PyObject* retuni = NULL;
+    PyObject* newi = NULL;
+    PyObject* objj = NULL;
+    if (_is_basic_python_type(tp)) {
+        ret = NULL;
+    }   
+    /* obj has the __array_interface__ interface */
+    ret = maybe_get_attr(obj, dictstr);
+    if (ret != NULL) {
+        if (PyDict_Check(ret)) {
+            objj = PyDict_GetItemString(ret, descrstr);
+            return (PyObject*) objj;
+        } else {
+            failflag = 1;
+        }
+    } else {
+        failflag = 1;
+    }
+    if (failflag){
+        PyErr_Clear();
+        PyErr_Format(PyExc_IOError, "Error: can not get attribute of given numpy array.");
+        return NULL;
+    }
+}
+#endif
+
+molfile_plugin_t* get_plugin(molfile_plugin_t** plug_list, int plug_no)
+{
+    molfile_plugin_t* plugin;
+    if(plug_no < 0){
+	plugin = NULL;
+    } else {
+	plugin = plug_list[plug_no];
+    }
+    return plugin;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Interface functions to initialize molfile plugins *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* check validity of plugins and register them. */
+static int molfile_register(void*, vmdplugin_t *plugin) {
+    if (!plugin->type || !plugin->name || !plugin->author) {
+        // skipping plugin with incomplete header
+        return VMDPLUGIN_ERROR;
+    }
+    else if (plugin->abiversion != vmdplugin_ABIVERSION) {
+        // skipping plugin with incompatible ABI
+        return VMDPLUGIN_ERROR;
+    }
+    else if (0 != strncmp(plugin->type, "mol file", 8)) {
+        // skipping plugin of incompatible type
+        return VMDPLUGIN_ERROR;
+    } 
+    else if (numplugins >= MAXPLUGINS) {
+        // too many plugins: increase MAXPLUGINS
+        return VMDPLUGIN_ERROR;
+    }
+
+    //if (plugin_find(&plugindict, plugin->name) != NULL) {
+        // multiple plugins for file type
+    //    return VMDPLUGIN_ERROR;
+    //} else {
+        plugin_list[numplugins] = (molfile_plugin_t *) plugin;
+	//plugin_add(&plugindict, plugin->name, numplugins);
+        ++numplugins;
+        return VMDPLUGIN_SUCCESS;
+    //}
+}
+
+molfile_plugin_t** molfile_plugin_list(int maxsize)
+{
+    if(maxsize < MAXPLUGINS){
+        maxsize = MAXPLUGINS;
+    }
+    plugin_list = (molfile_plugin_t**) malloc(sizeof(molfile_plugin_t*)*maxsize);
+    return plugin_list;
+}
+
+/* register all available plugins and clear handles. */
+int molfile_init(void) 
+{
+    MOLFILE_INIT_ALL;
+    MOLFILE_REGISTER_ALL(NULL,molfile_register);
+    return numplugins;
+}
+
+/* unregister all available plugins */
+int molfile_finish(void) 
+{
+    MOLFILE_FINI_ALL;
+    return 0;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * *
+ * Wrappers to directly access molfile plugin*
+ *         functions and settings            *
+ * * * * * * * * * * * * * * * * * * * * * * */
+
+/* molfile_plugin_t access */
+
+/* Functions in molfile_plugin_t */
+
+PyObject* read_fill_structure(PyObject* molpack, PyObject* prototype)
+{
+//    Py_Initialize();
+    import_array();
+    int options = 0;
+    molfile_plugin_t* plugin;
+    void* file_handle;
+    molfile_atom_t* data;
+    int numatoms, status;
+    int nd;
+    PyObject *ret = NULL;
+    // Access plugin_handle values
+    MolObject* plugin_handle = (MolObject*) molpack;
+    plugin = plugin_handle->plugin;
+    file_handle = plugin_handle->file_handle;
+    numatoms = plugin_handle->natoms;
+    // Allocate memory for array of molfile_atom_t struct
+    data = (molfile_atom_t *)calloc(numatoms,sizeof(molfile_atom_t));
+    // Get array values in molfile_atom_t
+    if (plugin->read_structure) {
+        status = plugin->read_structure(file_handle, &options, data);
+        // Check if the plugin returns the results
+        if (status!=0){
+            PyErr_Format(PyExc_IOError, "Error accessing molfile_atom_t in read_structure function of plugin.");
+            return NULL;
+        }
+        nd = 1;
+        npy_intp dims[1] = { numatoms };
+        npy_intp strides[1] = { sizeof(molfile_atom_t) };
+        Py_INCREF(prototype);
+        ret = PyArray_NewFromDescr(Py_TYPE(prototype), PyArray_DESCR((PyArrayObject*)prototype), 
+	    	                   nd, dims,
+			           strides, data, 
+			           PyArray_FLAGS((PyArrayObject*)prototype), prototype);
+        Py_DECREF(prototype);
+        return (PyObject*) ret;
+    } else {
+        PyErr_Format(PyExc_AttributeError, "molfile plugin does not have read_structure function.");
+	Py_RETURN_NONE;
+    }
+}
+
+PyObject* read_fill_bonds(PyObject* molpack)
+{
+    import_array();
+    int options = 0;
+    molfile_plugin_t* plugin;
+    void* file_handle;
+    molfile_atom_t* data;
+    int numatoms, status;
+    int nd;
+    PyObject *ret = NULL;
+    // Access plugin_handle values
+    MolObject* plugin_handle = (MolObject*) molpack;
+    plugin = plugin_handle->plugin;
+    file_handle = plugin_handle->file_handle;
+    numatoms = plugin_handle->natoms;
+    if (plugin->read_bonds) {
+        int nbonds, *from, *to, *bondtype, nbondtypes;
+        float *bondorder;
+        char **bondtypename;
+        if ((status = plugin->read_bonds(file_handle, &nbonds, &from, &to, 
+				         &bondorder, &bondtype, &nbondtypes, &bondtypename))) {
+            PyErr_Format(PyExc_IOError, "Error accessing read_bonds function of plugin.");
+            return NULL;
+        }
+        PyArrayInterface *inter = NULL;
+        inter = (PyArrayInterface*)malloc(sizeof(PyArrayInterface));
+        if (inter==NULL)
+            return PyErr_NoMemory();
+        inter->flags = NPY_ARRAY_NOTSWAPPED | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE;
+	ret = PyDict_New();
+        nd = 1;
+        npy_intp istrides[1] = { NPY_SIZEOF_INT };
+        npy_intp fstrides[1] = { NPY_SIZEOF_FLOAT };
+        npy_intp cstrides[1] = { sizeof(NPY_STRING) };
+	if (nbonds>0) {
+            PyObject *from_arr = NULL;
+            PyObject *to_arr = NULL;
+            npy_intp dims[1] = { nbonds };
+            from_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                            nd, dims,
+                                            istrides, from, 
+                                            inter->flags, NULL);
+	    PyDict_SetItemString(ret, "from", from_arr);
+            to_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                          nd, dims,
+                                          istrides, to, 
+                                          inter->flags, NULL);
+	    PyDict_SetItemString(ret, "to", to_arr);
+	    if (bondorder!=NULL) {
+                PyObject *bondorder_arr = NULL;
+                bondorder_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_FLOAT), 
+                                                     nd, dims,
+                                                     fstrides, bondorder, 
+			                             inter->flags, NULL);
+	        PyDict_SetItemString(ret, "bondorder", bondorder_arr);
+	    }
+	    if (bondtype!=NULL && nbondtypes>0) {
+                PyObject *bondtype_arr = NULL;
+                bondtype_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                    nd, dims,
+                                                    istrides, bondtype, 
+			                            inter->flags, NULL);
+	        PyDict_SetItemString(ret, "bondtype", bondtype_arr);
+	    }
+	    if (bondtypename!=NULL && nbondtypes>0) {
+                PyObject *bondtypename_arr = NULL;
+                npy_intp cdims[1] = { nbondtypes };
+                bondtypename_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_STRING), 
+                                                        nd, cdims,
+                                                        cstrides, bondtypename, 
+	                                                inter->flags, NULL);
+	        PyDict_SetItemString(ret, "bondtypename", bondtypename_arr);
+	    }
+            return (PyObject*) ret;
+	} else {
+            Py_RETURN_NONE;
+	}
+    } else {
+        PyErr_Format(PyExc_AttributeError, "molfile plugin does not have read_bonds function.");
+        Py_RETURN_NONE;
+    }
+}
+
+PyObject* read_fill_angles(PyObject* molpack)
+{
+    import_array();
+    int options = 0;
+    molfile_plugin_t* plugin;
+    void* file_handle;
+    molfile_atom_t* data;
+    int numatoms, status;
+    int nd;
+    int nodata = 0;
+    PyObject *ret = NULL;
+    // Access plugin_handle values
+    MolObject* plugin_handle = (MolObject*) molpack;
+    plugin = plugin_handle->plugin;
+    file_handle = plugin_handle->file_handle;
+    numatoms = plugin_handle->natoms;
+    // Check if there is read_angles support in this plugin
+    if (plugin->read_angles) {
+	// Angles
+        int numangles, *angles, *angletypes;
+        int numangletypes;
+	char **angletypenames; 
+	// Dihedrals
+	int numdihedrals, *dihedrals, *dihedraltypes;
+	int numdihedraltypes;
+        char **dihedraltypenames; 
+	// Impropers
+	int numimpropers, *impropers, *impropertypes;
+	int numimpropertypes;
+	char **impropertypenames;
+	// Cterms
+        int numcterms, *cterms, ctermcols, ctermrows;
+	// Initilize zeros to number of angles, dihedrals, so on ...
+	numangles = 0;
+	numangletypes = 0;
+	numdihedrals = 0;
+	numdihedraltypes = 0;
+	numimpropers = 0;
+	numimpropertypes = 0;
+	numcterms = 0;
+	// Calling read_angles to gather the information
+        if ((status = plugin->read_angles(file_handle, &numangles, &angles, &angletypes,
+                                          &numangletypes, &angletypenames, &numdihedrals,
+                                          &dihedrals, &dihedraltypes, &numdihedraltypes,
+                                          &dihedraltypenames, &numimpropers, &impropers,        
+                                          &impropertypes, &numimpropertypes, &impropertypenames,
+                                          &numcterms, &cterms, &ctermcols, &ctermrows))) {
+            PyErr_Format(PyExc_IOError, "Error accessing read_angles function of plugin.");
+            return NULL;
+        }
+        PyArrayInterface *inter = NULL;
+        inter = (PyArrayInterface*)malloc(sizeof(PyArrayInterface));
+        if (inter==NULL)
+            return PyErr_NoMemory();
+        inter->flags = NPY_ARRAY_NOTSWAPPED | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE;
+	ret = PyDict_New();
+        nd = 1;
+        npy_intp istrides[1] = { NPY_SIZEOF_INT };
+        npy_intp sstrides[1] = { sizeof(NPY_STRING) };
+	if (numangles>0 && angles!=NULL) {
+	    nodata = 1;
+            PyObject *angles_arr = NULL;
+            npy_intp adims[1] = { numangles };
+            angles_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                              nd, adims,
+                                              istrides, angles, 
+                                              inter->flags, NULL);
+	    PyDict_SetItemString(ret, "angles", angles_arr);
+	    if (angletypes!=NULL) {
+                PyObject *angletypes_arr = NULL;
+                angletypes_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                      nd, adims,
+                                                      istrides, angletypes, 
+                                                      inter->flags, NULL);
+	        PyDict_SetItemString(ret, "angletypes", angletypes_arr);
+	    }
+	}
+	if (numangletypes>0 && angletypenames!=NULL) {
+	    nodata = 1;
+            PyObject *angletypenames_arr = NULL;
+            npy_intp atdims[1] = { numangletypes };
+            angletypenames_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_STRING), 
+                                                      nd, atdims,
+                                                      sstrides, angletypenames, 
+			                              inter->flags, NULL);
+	    PyDict_SetItemString(ret, "angletypenames", angletypenames_arr);
+	}
+	if (numdihedrals>0 && dihedrals!=NULL) {
+	    nodata = 1;
+            PyObject *dihedrals_arr = NULL;
+            npy_intp ddims[1] = { numdihedrals };
+            dihedrals_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                 nd, ddims,
+                                                 istrides, dihedrals, 
+			                         inter->flags, NULL);
+	    PyDict_SetItemString(ret, "dihedrals", dihedrals_arr);
+	    if (dihedraltypes!=NULL) {
+                PyObject *dihedraltypes_arr = NULL;
+                dihedraltypes_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                    nd, ddims,
+                                                    istrides, dihedraltypes, 
+                                                    inter->flags, NULL);
+	        PyDict_SetItemString(ret, "dihedraltypes", dihedraltypes_arr);
+	    }
+	}
+	if (numdihedraltypes>0 && dihedraltypenames!=NULL) {
+            PyObject *dihedraltypenames_arr = NULL;
+            npy_intp dtdims[1] = { numdihedraltypes };
+            dihedraltypenames_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_STRING), 
+                                                         nd, dtdims,
+                                                         sstrides, dihedraltypenames, 
+	                                                 inter->flags, NULL);
+	    PyDict_SetItemString(ret, "dihedraltypenames", dihedraltypenames_arr);
+	}
+	if (numimpropers>0 && impropers!=NULL) {
+	    nodata = 1;
+            PyObject *impropers_arr = NULL;
+            npy_intp idims[1] = { numimpropers };
+            impropers_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                 nd, idims,
+                                                 istrides, impropers, 
+			                         inter->flags, NULL);
+	    PyDict_SetItemString(ret, "impropers", impropers_arr);
+	    if (impropertypes!=NULL) {
+                PyObject *impropertypes_arr = NULL;
+                impropertypes_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                         nd, idims,
+                                                         istrides, impropertypes, 
+                                                         inter->flags, NULL);
+	        PyDict_SetItemString(ret, "impropertypes", impropertypes_arr);
+	    }
+	}
+	if (numimpropertypes>0 && impropertypenames!=NULL) {
+            PyObject *impropertypenames_arr = NULL;
+            npy_intp itdims[1] = { numimpropertypes };
+            impropertypenames_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_STRING), 
+                                                         nd, itdims,
+                                                         sstrides, impropertypenames, 
+	                                                 inter->flags, NULL);
+	    PyDict_SetItemString(ret, "impropertypenames", impropertypenames_arr);
+	}
+	if (numcterms>0 && cterms!=NULL) {
+	    nodata = 1;
+            PyObject *cterms_arr = NULL;
+	    if (ctermrows>0 || ctermcols>0) {
+                int ctermnd = 2;
+                npy_intp ctermdims[2];
+                npy_intp ctermstrides[2];
+	        printf("CTERM:%d %d %d\n",numcterms,ctermrows,ctermcols);
+	        ctermdims[0]=ctermrows;
+	        ctermdims[1]=ctermcols;
+	        ctermstrides[0]=NPY_SIZEOF_INT;
+	        ctermstrides[1]=ctermrows*NPY_SIZEOF_INT;
+	    } else {
+                int ctermnd = 1;
+                npy_intp ctermdims[1] = { numcterms };
+                npy_intp ctermstrides[1] = { NPY_SIZEOF_INT };
+	        printf("CTERM:%d %d %d\n",numcterms,ctermrows,ctermcols);
+	    }
+            cterms_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                              ctermnd, ctermdims,
+                                              ctermstrides, cterms, 
+			                      inter->flags, NULL);
+	    PyDict_SetItemString(ret, "cterms", cterms_arr);
+	}
+	if (nodata>0) {
+            return (PyObject*) ret;
+	} else {
+            Py_RETURN_NONE;
+	}
+    } else {
+        PyErr_Format(PyExc_AttributeError, "molfile plugin does not have read_angles function.");
+        Py_RETURN_NONE;
+    }
+}
+
+
diff --git a/pymolfile/molfile/_libpymolfile.so b/pymolfile/molfile/_libpymolfile.so
index 03e253f4538f2a2643e6601c6dea034fbea0250a..b8d30a01d58656f6776ebb95da891e1b5c6a7acf 100755
Binary files a/pymolfile/molfile/_libpymolfile.so and b/pymolfile/molfile/_libpymolfile.so differ
diff --git a/pymolfile/molfile/_libpymolfile.so.dSYM/Contents/Resources/DWARF/_libpymolfile.so b/pymolfile/molfile/_libpymolfile.so.dSYM/Contents/Resources/DWARF/_libpymolfile.so
index 62e1d9e32365a8ad8fdfdefb9745afed645d9185..4a3a2cb8c4eca1df10dcf22b5761d74dd653021e 100644
Binary files a/pymolfile/molfile/_libpymolfile.so.dSYM/Contents/Resources/DWARF/_libpymolfile.so and b/pymolfile/molfile/_libpymolfile.so.dSYM/Contents/Resources/DWARF/_libpymolfile.so differ
diff --git a/pymolfile/molfile/libpymolfile.i b/pymolfile/molfile/libpymolfile.i
index 9ad19aa099a1b74ce45118fbfbddd88ca6684ffc..770850be4225c574d068500b78b984e7b2407817 100644
--- a/pymolfile/molfile/libpymolfile.i
+++ b/pymolfile/molfile/libpymolfile.i
@@ -21,7 +21,7 @@
 %{
 /* Python SWIG interface to libpymolfile
    Copyright (c) 2017 Berk Onat <b.onat@warwick.ac.uk>
-   Published under BSD LICENSE
+   Published with UIUC LICENSE
  */
 #define SWIG_FILE_WITH_INIT
 #define __STDC_FORMAT_MACROS
@@ -175,6 +175,28 @@ PyObject * my_open_file_read(molfile_plugin_t* plugin, char* fname, char* ftype,
   }
 %}
 
+%feature("autodoc", "0") my_close_file_read;
+%rename (close_file_read) my_close_file_read;
+%exception my_close_file_read {
+  $action
+  if (PyErr_Occurred()) SWIG_fail;
+}
+%inline %{
+PyObject * my_close_file_read(PyObject* molpack) {
+    molfile_plugin_t* plugin;
+    void* file_handle;
+    int numatoms;
+    MolObject* plugin_handle = (MolObject*) molpack;
+    plugin = plugin_handle->plugin;
+    file_handle = plugin_handle->file_handle;
+    numatoms = plugin_handle->natoms;
+    plugin->close_file_read(file_handle); 
+    Py_DECREF(plugin_handle);
+    Py_DECREF(molpack);
+    Py_RETURN_NONE;
+  }
+%}
+
 /*
 %typemap( argout ) ( char **MolfileAtomT_CharArray )
 {
@@ -202,16 +224,22 @@ PyObject * my_open_file_read(molfile_plugin_t* plugin, char* fname, char* ftype,
 }
 */
 
+%feature("autodoc", "0") read_fill_structure;
+extern PyObject * read_fill_structure(PyObject* molpack, PyObject* prototype);
+
+%feature("autodoc", "0") read_fill_bonds;
+extern PyObject * read_fill_bonds(PyObject* molpack);
+
+%feature("autodoc", "0") read_fill_angles;
+extern PyObject * read_fill_angles(PyObject* molpack);
+
 /*
 #define DIM 3
-typedef int imatrix[DIM][DIM];
 typedef int ivec[DIM];
-typedef float fmatrix[DIM][DIM];
 typedef float fvec[DIM];
-*/
 
-/* Reading from xdr files */
-/*
+
+
 %apply (float INPLACE_ARRAY2[ANY][ANY]) {(matrix box)}
 %apply (int DIM1, int DIM2, float* INPLACE_ARRAY2) {(int natoms,  int _DIM,  float *x),
                                                     (int vnatoms, int v_DIM, float *v),
@@ -224,70 +252,23 @@ typedef float fvec[DIM];
 %apply (int DIM1, float* INPLACE_FARRAY2) {(int mnatoms, float* MolAtom_mass),
                                            (int anatoms, float* MolAtom_atomicnumber)}
 */
-/*
-%inline %{
-int structure_read(molfile_plugin_t* plugin, void* fhandle, int *options, 
-                   int* natoms, char** MolAtom_name, 
-                   int* natoms, char** MolAtom_type, 
-                   int* natoms, char** MolAtom_resname,
-                   int* natoms, int**  MolAtom_resid, 
-                   int* natoms, char** MolAtom_segid,
-                   int* natoms, char** MolAtom_chain,
-                   int* natoms, char** MolAtom_altloc,
-                   int* natoms, char** MolAtom_insertion,
-                   int* natoms, float** MolAtom_occupancy,
-                   int* natoms, float** MolAtom_bfactor,
-                   int* natoms, float** MolAtom_mass,
-                   int* natoms, float** MolAtom_charge,
-                   int* natoms, float** MolAtom_radius,
-                   int* natoms, float** MolAtom_atomicnumber,
-                   int* natoms, float** MolAtom_ctnumber) {
-    molfile_atom_t* atoms;
-    atoms = (molfile_atom_t *)calloc(natoms,sizeof(molfile_atom_t));
-    plugin->read_structure(fhandle, options, atoms);
-    MolAtom_name = (char **)malloc(natoms,sizeof(char*));
-    MolAtom_type = (char **)malloc(natoms,sizeof(char*));
-    MolAtom_resname = (char **)malloc(natoms,sizeof(char*));
-    MolAtom_resid = (int **)malloc(natoms,sizeof(int*));
-%}
-*/
-/*
+
+
+/*  
+%feature("autodoc", "read_bonds(MOLOBJECT, nbonds, from, to, bondorder, bondtype, nbondtypes, bondtypename) -> status") my_read_bonds;
+%rename (read_bonds) my_read_bonds;
 %inline %{
-int structure_read(molfile_plugin_t* plugin, void* fhandle, int *options, 
-                   int natoms, char** MolAtom_name, 
-                   int tnatoms, char** MolAtom_type, 
-                   int rnatoms, int*  MolAtom_resid, 
-                   int mnatoms, float* MolAtom_mass,
-                   int anatoms, float* MolAtom_atomicnumber) {
-    int i;
-    molfile_atom_t* atoms;
-    molfile_atom_t atm;
-    atoms = (molfile_atom_t *)calloc(natoms,sizeof(molfile_atom_t));
-    plugin->read_structure(fhandle, options, atoms);
-    if(atoms == NULL) { free(atoms); return 1; }
-    if(atoms->type == NULL || atoms->name == NULL){ free(atoms); return 1; }
-    MolAtom_name = (char **)malloc(natoms,sizeof(char*));
-    MolAtom_type = (char **)malloc(natoms,sizeof(char*));
-    MolAtom_resid = (int *)malloc(natoms,sizeof(int));
-    MolAtom_mass = (float *)malloc(natoms,sizeof(float));
-    MolAtom_atomicnumber = (float *)malloc(natoms,sizeof(float));
-    for (i=0;i<natoms;i++){
-        atm = atoms[i];
-        MolAtom_name[i] = atm.name;
-        MolAtom_type[i] = atm.type;
-        MolAtom_resid[i] = atm.resid;
-        MolAtom_mass[i] = atm.mass;
-        MolAtom_atomicnumber[i] = atm.atomicnumber;
-    }
-    return 0;
-    }
+PyObject * read_bonds(PyObject* molpack, int f_DIM,  int   *from, 
+                                         int t_DIM,  int   *to, 
+                                         int bo_DIM, float *bondorder,
+                                         int bt_DIM, int   *bondtype,
+                                         int n_DIM, char  *bondtypename){
+
+(*read_bonds)(void *, int *nbonds, int **from, int **to, float **bondorder, 
+                  int **bondtype, int *nbondtypes, char ***bondtypename);
+}
 %}
 */
-
-
-%feature("autodoc", "0") read_fill_structure;
-extern PyObject * read_fill_structure(PyObject* molpack, PyObject* prototype);
-
 /* 
    python wrappers for functions 
    and structure data in  molfile_plugin.h
diff --git a/pymolfile/molfile/libpymolfile.py b/pymolfile/molfile/libpymolfile.py
index 59ca29c413c05a6381b225d8b856a63a5e9be4db..a76c3e7b8805045e773114cbe3c1e292b710ee13 100644
--- a/pymolfile/molfile/libpymolfile.py
+++ b/pymolfile/molfile/libpymolfile.py
@@ -154,9 +154,21 @@ def open_file_read(plugin: 'molfile_plugin_t *', fname: 'char *', ftype: 'char *
     """open_file_read(plugin, fname, ftype, natoms) -> PyObject *"""
     return _libpymolfile.open_file_read(plugin, fname, ftype, natoms)
 
+def close_file_read(molpack: 'PyObject *') -> "PyObject *":
+    """close_file_read(molpack) -> PyObject *"""
+    return _libpymolfile.close_file_read(molpack)
+
 def read_fill_structure(molpack: 'PyObject *', prototype: 'PyObject *') -> "PyObject *":
     """read_fill_structure(molpack, prototype) -> PyObject *"""
     return _libpymolfile.read_fill_structure(molpack, prototype)
+
+def read_fill_bonds(molpack: 'PyObject *') -> "PyObject *":
+    """read_fill_bonds(molpack) -> PyObject *"""
+    return _libpymolfile.read_fill_bonds(molpack)
+
+def read_fill_angles(molpack: 'PyObject *') -> "PyObject *":
+    """read_fill_angles(molpack) -> PyObject *"""
+    return _libpymolfile.read_fill_angles(molpack)
 # This file is compatible with both classic and new-style classes.
 
 
diff --git a/pymolfile/molfile/libpymolfile_wrap.cxx b/pymolfile/molfile/libpymolfile_wrap.cxx
index 0738ff2b648ca34fcdff415f9afa5bd152e2106c..644f5ad189ead99565c55b78fa192b179f522059 100644
--- a/pymolfile/molfile/libpymolfile_wrap.cxx
+++ b/pymolfile/molfile/libpymolfile_wrap.cxx
@@ -3114,7 +3114,7 @@ namespace swig {
 
 /* Python SWIG interface to libpymolfile
    Copyright (c) 2017 Berk Onat <b.onat@warwick.ac.uk>
-   Published under BSD LICENSE
+   Published with UIUC LICENSE
  */
 #define SWIG_FILE_WITH_INIT
 #define __STDC_FORMAT_MACROS
@@ -3511,6 +3511,21 @@ SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
 
 
 
+
+PyObject * my_close_file_read(PyObject* molpack) {
+    molfile_plugin_t* plugin;
+    void* file_handle;
+    int numatoms;
+    MolObject* plugin_handle = (MolObject*) molpack;
+    plugin = plugin_handle->plugin;
+    file_handle = plugin_handle->file_handle;
+    numatoms = plugin_handle->natoms;
+    plugin->close_file_read(file_handle); 
+    Py_DECREF(plugin_handle);
+    Py_DECREF(molpack);
+    Py_RETURN_NONE;
+  }
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -3749,6 +3764,25 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_close_file_read(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  PyObject *arg1 = (PyObject *) 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:close_file_read",&obj0)) SWIG_fail;
+  arg1 = obj0;
+  {
+    result = (PyObject *)my_close_file_read(arg1);
+    if (PyErr_Occurred()) SWIG_fail;
+  }
+  resultobj = result;
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_read_fill_structure(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   PyObject *arg1 = (PyObject *) 0 ;
@@ -3768,6 +3802,38 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_read_fill_bonds(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  PyObject *arg1 = (PyObject *) 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:read_fill_bonds",&obj0)) SWIG_fail;
+  arg1 = obj0;
+  result = (PyObject *)read_fill_bonds(arg1);
+  resultobj = result;
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_read_fill_angles(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  PyObject *arg1 = (PyObject *) 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:read_fill_angles",&obj0)) SWIG_fail;
+  arg1 = obj0;
+  result = (PyObject *)read_fill_angles(arg1);
+  resultobj = result;
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 static PyMethodDef SwigMethods[] = {
 	 { (char *)"SWIG_PyInstanceMethod_New", (PyCFunction)SWIG_PyInstanceMethod_New, METH_O, NULL},
 	 { (char *)"del_plugin", _wrap_del_plugin, METH_VARARGS, NULL},
@@ -3780,7 +3846,10 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"get_plugin", _wrap_get_plugin, METH_VARARGS, (char *)"get_plugin(plugin_list, plugin_no) -> molfile_plugin_t *"},
 	 { (char *)"molfile_plugin_info", _wrap_molfile_plugin_info, METH_VARARGS, (char *)"molfile_plugin_info(plugin_list, plugin_no) -> PyObject *"},
 	 { (char *)"open_file_read", _wrap_open_file_read, METH_VARARGS, (char *)"open_file_read(plugin, fname, ftype, natoms) -> PyObject *"},
+	 { (char *)"close_file_read", _wrap_close_file_read, METH_VARARGS, (char *)"close_file_read(molpack) -> PyObject *"},
 	 { (char *)"read_fill_structure", _wrap_read_fill_structure, METH_VARARGS, (char *)"read_fill_structure(molpack, prototype) -> PyObject *"},
+	 { (char *)"read_fill_bonds", _wrap_read_fill_bonds, METH_VARARGS, (char *)"read_fill_bonds(molpack) -> PyObject *"},
+	 { (char *)"read_fill_angles", _wrap_read_fill_angles, METH_VARARGS, (char *)"read_fill_angles(molpack) -> PyObject *"},
 	 { NULL, NULL, 0, NULL }
 };
 
diff --git a/pymolfile/molfile/pymolfile.c b/pymolfile/molfile/pymolfile.c
index 22d9bb261a4b9f7746c55f0f2072da60db833f72..d54586869fc30fd5f61d860cb4ca4e83bbf8eeed 100644
--- a/pymolfile/molfile/pymolfile.c
+++ b/pymolfile/molfile/pymolfile.c
@@ -376,7 +376,7 @@ int molfile_finish(void)
 
 PyObject* read_fill_structure(PyObject* molpack, PyObject* prototype)
 {
-    Py_Initialize();
+//    Py_Initialize();
     import_array();
     int options = 0;
     molfile_plugin_t* plugin;
@@ -387,9 +387,24 @@ PyObject* read_fill_structure(PyObject* molpack, PyObject* prototype)
     PyObject *ret = NULL;
     // Access plugin_handle values
     MolObject* plugin_handle = (MolObject*) molpack;
-    plugin = plugin_handle->plugin;
-    file_handle = plugin_handle->file_handle;
-    numatoms = plugin_handle->natoms;
+    if (!plugin_handle->plugin) {
+        plugin = plugin_handle->plugin;
+    } else { 
+        PyErr_Format(PyExc_IOError, "molfile plugin is not active.");
+	return NULL 
+    } 
+    if (!plugin_handle->file_handle) {
+        file_handle = plugin_handle->file_handle;
+    } else { 
+        PyErr_Format(PyExc_IOError, "no file handle in molfile plugin handle.");
+	return NULL 
+    } 
+    if (!plugin_handle->natoms) {
+        numatoms = plugin_handle->natoms;
+    } else { 
+        PyErr_Format(PyExc_IOError, "no assigned number of atoms in molfile plugin handle.");
+	return NULL 
+    } 
     // Allocate memory for array of molfile_atom_t struct
     data = (molfile_atom_t *)calloc(numatoms,sizeof(molfile_atom_t));
     // Get array values in molfile_atom_t
@@ -400,20 +415,287 @@ PyObject* read_fill_structure(PyObject* molpack, PyObject* prototype)
             PyErr_Format(PyExc_IOError, "Error accessing molfile_atom_t in read_structure function of plugin.");
             return NULL;
         }
-        nd = 1;
-        npy_intp dims[1] = { numatoms };
-        npy_intp strides[1] = { sizeof(molfile_atom_t) };
-        Py_INCREF(prototype);
-        ret = PyArray_NewFromDescr(Py_TYPE(prototype), PyArray_DESCR((PyArrayObject*)prototype), 
-	    	                   nd, dims,
-			           strides, data, 
-			           PyArray_FLAGS((PyArrayObject*)prototype), prototype);
-        Py_DECREF(prototype);
-        return (PyObject*) ret;
+	if(numatoms>0){
+            nd = 1;
+            npy_intp dims[1] = { numatoms };
+            npy_intp strides[1] = { sizeof(molfile_atom_t) };
+            Py_INCREF(prototype);
+            ret = PyArray_NewFromDescr(Py_TYPE(prototype), PyArray_DESCR((PyArrayObject*)prototype), 
+	       	                       nd, dims,
+		                       strides, data, 
+			               PyArray_FLAGS((PyArrayObject*)prototype), prototype);
+            Py_DECREF(prototype);
+            return (PyObject*) ret;
+	} else {
+            PyErr_Format(PyExc_AttributeError, "plugin read_structure does not have atoms information.");
+	    Py_RETURN_NONE;
+	}
     } else {
         PyErr_Format(PyExc_AttributeError, "molfile plugin does not have read_structure function.");
 	Py_RETURN_NONE;
     }
 }
 
+PyObject* read_fill_bonds(PyObject* molpack)
+{
+    import_array();
+    int options = 0;
+    molfile_plugin_t* plugin;
+    void* file_handle;
+    molfile_atom_t* data;
+    int numatoms, status;
+    int nd;
+    PyObject *ret = NULL;
+    // Access plugin_handle values
+    MolObject* plugin_handle = (MolObject*) molpack;
+    plugin = plugin_handle->plugin;
+    file_handle = plugin_handle->file_handle;
+    numatoms = plugin_handle->natoms;
+    if (plugin->read_bonds) {
+        int nbonds, *from, *to, *bondtype, nbondtypes;
+        float *bondorder;
+        char **bondtypename;
+        if ((status = plugin->read_bonds(file_handle, &nbonds, &from, &to, 
+				         &bondorder, &bondtype, &nbondtypes, &bondtypename))) {
+            PyErr_Format(PyExc_IOError, "Error accessing read_bonds function of plugin.");
+            return NULL;
+        }
+        PyArrayInterface *inter = NULL;
+        inter = (PyArrayInterface*)malloc(sizeof(PyArrayInterface));
+        if (inter==NULL)
+            return PyErr_NoMemory();
+        inter->flags = NPY_ARRAY_NOTSWAPPED | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE;
+	ret = PyDict_New();
+        nd = 1;
+        npy_intp istrides[1] = { NPY_SIZEOF_INT };
+        npy_intp fstrides[1] = { NPY_SIZEOF_FLOAT };
+        npy_intp cstrides[1] = { sizeof(NPY_STRING) };
+	if (nbonds>0) {
+            PyObject *from_arr = NULL;
+            PyObject *to_arr = NULL;
+            npy_intp dims[1] = { nbonds };
+            from_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                            nd, dims,
+                                            istrides, from, 
+                                            inter->flags, NULL);
+	    PyDict_SetItemString(ret, "from", from_arr);
+            to_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                          nd, dims,
+                                          istrides, to, 
+                                          inter->flags, NULL);
+	    PyDict_SetItemString(ret, "to", to_arr);
+	    if (bondorder!=NULL) {
+                PyObject *bondorder_arr = NULL;
+                bondorder_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_FLOAT), 
+                                                     nd, dims,
+                                                     fstrides, bondorder, 
+			                             inter->flags, NULL);
+	        PyDict_SetItemString(ret, "bondorder", bondorder_arr);
+	    }
+	    if (bondtype!=NULL && nbondtypes>0) {
+                PyObject *bondtype_arr = NULL;
+                bondtype_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                    nd, dims,
+                                                    istrides, bondtype, 
+			                            inter->flags, NULL);
+	        PyDict_SetItemString(ret, "bondtype", bondtype_arr);
+	    }
+	    if (bondtypename!=NULL && nbondtypes>0) {
+                PyObject *bondtypename_arr = NULL;
+                npy_intp cdims[1] = { nbondtypes };
+                bondtypename_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_STRING), 
+                                                        nd, cdims,
+                                                        cstrides, bondtypename, 
+	                                                inter->flags, NULL);
+	        PyDict_SetItemString(ret, "bondtypename", bondtypename_arr);
+	    }
+            return (PyObject*) ret;
+	} else {
+            Py_RETURN_NONE;
+	}
+    } else {
+        PyErr_Format(PyExc_AttributeError, "molfile plugin does not have read_bonds function.");
+        Py_RETURN_NONE;
+    }
+}
+
+PyObject* read_fill_angles(PyObject* molpack)
+{
+    import_array();
+    int options = 0;
+    molfile_plugin_t* plugin;
+    void* file_handle;
+    molfile_atom_t* data;
+    int numatoms, status;
+    int nd;
+    int nodata = 0;
+    PyObject *ret = NULL;
+    // Access plugin_handle values
+    MolObject* plugin_handle = (MolObject*) molpack;
+    plugin = plugin_handle->plugin;
+    file_handle = plugin_handle->file_handle;
+    numatoms = plugin_handle->natoms;
+    // Check if there is read_angles support in this plugin
+    if (plugin->read_angles) {
+	// Angles
+        int numangles, *angles, *angletypes;
+        int numangletypes;
+	char **angletypenames; 
+	// Dihedrals
+	int numdihedrals, *dihedrals, *dihedraltypes;
+	int numdihedraltypes;
+        char **dihedraltypenames; 
+	// Impropers
+	int numimpropers, *impropers, *impropertypes;
+	int numimpropertypes;
+	char **impropertypenames;
+	// Cterms
+        int numcterms, *cterms, ctermcols, ctermrows;
+	// Initilize zeros to number of angles, dihedrals, so on ...
+	numangles = 0;
+	numangletypes = 0;
+	numdihedrals = 0;
+	numdihedraltypes = 0;
+	numimpropers = 0;
+	numimpropertypes = 0;
+	numcterms = 0;
+	// Calling read_angles to gather the information
+        if ((status = plugin->read_angles(file_handle, &numangles, &angles, &angletypes,
+                                          &numangletypes, &angletypenames, &numdihedrals,
+                                          &dihedrals, &dihedraltypes, &numdihedraltypes,
+                                          &dihedraltypenames, &numimpropers, &impropers,        
+                                          &impropertypes, &numimpropertypes, &impropertypenames,
+                                          &numcterms, &cterms, &ctermcols, &ctermrows))) {
+            PyErr_Format(PyExc_IOError, "Error accessing read_angles function of plugin.");
+            return NULL;
+        }
+        PyArrayInterface *inter = NULL;
+        inter = (PyArrayInterface*)malloc(sizeof(PyArrayInterface));
+        if (inter==NULL)
+            return PyErr_NoMemory();
+        inter->flags = NPY_ARRAY_NOTSWAPPED | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE;
+	ret = PyDict_New();
+        nd = 1;
+        npy_intp istrides[1] = { NPY_SIZEOF_INT };
+        npy_intp sstrides[1] = { sizeof(NPY_STRING) };
+	if (numangles>0 && angles!=NULL) {
+	    nodata = 1;
+            PyObject *angles_arr = NULL;
+            npy_intp adims[1] = { numangles };
+            angles_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                              nd, adims,
+                                              istrides, angles, 
+                                              inter->flags, NULL);
+	    PyDict_SetItemString(ret, "angles", angles_arr);
+	    if (angletypes!=NULL) {
+                PyObject *angletypes_arr = NULL;
+                angletypes_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                      nd, adims,
+                                                      istrides, angletypes, 
+                                                      inter->flags, NULL);
+	        PyDict_SetItemString(ret, "angletypes", angletypes_arr);
+	    }
+	}
+	if (numangletypes>0 && angletypenames!=NULL) {
+	    nodata = 1;
+            PyObject *angletypenames_arr = NULL;
+            npy_intp atdims[1] = { numangletypes };
+            angletypenames_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_STRING), 
+                                                      nd, atdims,
+                                                      sstrides, angletypenames, 
+			                              inter->flags, NULL);
+	    PyDict_SetItemString(ret, "angletypenames", angletypenames_arr);
+	}
+	if (numdihedrals>0 && dihedrals!=NULL) {
+	    nodata = 1;
+            PyObject *dihedrals_arr = NULL;
+            npy_intp ddims[1] = { numdihedrals };
+            dihedrals_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                 nd, ddims,
+                                                 istrides, dihedrals, 
+			                         inter->flags, NULL);
+	    PyDict_SetItemString(ret, "dihedrals", dihedrals_arr);
+	    if (dihedraltypes!=NULL) {
+                PyObject *dihedraltypes_arr = NULL;
+                dihedraltypes_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                    nd, ddims,
+                                                    istrides, dihedraltypes, 
+                                                    inter->flags, NULL);
+	        PyDict_SetItemString(ret, "dihedraltypes", dihedraltypes_arr);
+	    }
+	}
+	if (numdihedraltypes>0 && dihedraltypenames!=NULL) {
+            PyObject *dihedraltypenames_arr = NULL;
+            npy_intp dtdims[1] = { numdihedraltypes };
+            dihedraltypenames_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_STRING), 
+                                                         nd, dtdims,
+                                                         sstrides, dihedraltypenames, 
+	                                                 inter->flags, NULL);
+	    PyDict_SetItemString(ret, "dihedraltypenames", dihedraltypenames_arr);
+	}
+	if (numimpropers>0 && impropers!=NULL) {
+	    nodata = 1;
+            PyObject *impropers_arr = NULL;
+            npy_intp idims[1] = { numimpropers };
+            impropers_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                 nd, idims,
+                                                 istrides, impropers, 
+			                         inter->flags, NULL);
+	    PyDict_SetItemString(ret, "impropers", impropers_arr);
+	    if (impropertypes!=NULL) {
+                PyObject *impropertypes_arr = NULL;
+                impropertypes_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                                         nd, idims,
+                                                         istrides, impropertypes, 
+                                                         inter->flags, NULL);
+	        PyDict_SetItemString(ret, "impropertypes", impropertypes_arr);
+	    }
+	}
+	if (numimpropertypes>0 && impropertypenames!=NULL) {
+            PyObject *impropertypenames_arr = NULL;
+            npy_intp itdims[1] = { numimpropertypes };
+            impropertypenames_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_STRING), 
+                                                         nd, itdims,
+                                                         sstrides, impropertypenames, 
+	                                                 inter->flags, NULL);
+	    PyDict_SetItemString(ret, "impropertypenames", impropertypenames_arr);
+	}
+	if (numcterms>0 && cterms!=NULL) {
+	    nodata = 1;
+	    int ctermnd;
+            npy_intp *ctermdims;
+	    npy_intp *ctermstrides;
+            PyObject *cterms_arr = NULL;
+	    if (ctermrows>0 || ctermcols>0) {
+		ctermnd = 2;
+                ctermdims = (npy_intp*)calloc(ctermnd,sizeof(int));
+                ctermstrides = (npy_intp*)calloc(ctermnd,sizeof(int));
+	        ctermdims[0] = ctermrows;
+	        ctermdims[1] = ctermcols;
+	        ctermstrides[0] = NPY_SIZEOF_INT;
+	        ctermstrides[1] = ctermcols*NPY_SIZEOF_INT;
+	    } else {
+		ctermnd = 1;
+                ctermdims = (npy_intp*)calloc(ctermnd,sizeof(int));
+                ctermstrides = (npy_intp*)calloc(ctermnd,sizeof(int));
+	        ctermdims[0] = 8*numcterms;
+	        ctermstrides[0] = NPY_SIZEOF_INT;
+	    }
+            cterms_arr = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_INT), 
+                                              ctermnd, ctermdims,
+                                              ctermstrides, cterms, 
+			                      inter->flags, NULL);
+	    PyDict_SetItemString(ret, "cterms", cterms_arr);
+	}
+	if (nodata>0) {
+            return (PyObject*) ret;
+	} else {
+            Py_RETURN_NONE;
+	}
+    } else {
+        PyErr_Format(PyExc_AttributeError, "molfile plugin does not have read_angles function.");
+        Py_RETURN_NONE;
+    }
+}
+
 
diff --git a/pymolfile/molfile/pymolfile.h b/pymolfile/molfile/pymolfile.h
index a98d95e9a9deabc6d21be76372b6fe9261c23678..b4a0e6970cb780eb2b11c10b5ef51eec0684bd66 100644
--- a/pymolfile/molfile/pymolfile.h
+++ b/pymolfile/molfile/pymolfile.h
@@ -185,6 +185,8 @@ static PyTypeObject MolObjectType = {
 };
 
 PyObject * read_fill_structure(PyObject* molpack, PyObject* prototype);
+PyObject * read_fill_bonds(PyObject* molpack);
+PyObject * read_fill_angles(PyObject* molpack);
 
 molfile_plugin_t* get_plugin(molfile_plugin_t** plug_list, int plug_no);
 
diff --git a/pymolfile/molfile/test.py b/pymolfile/molfile/test.py
index a4bab3b292b965e2778ce67a84add83e08e0c4ee..0a31176db766cb8ed8b4fc48245fc8982ca62627 100644
--- a/pymolfile/molfile/test.py
+++ b/pymolfile/molfile/test.py
@@ -132,9 +132,9 @@ for i in range(numlist):
     print(i, testplugin)
 
 #plugin = mylib.get_plugin(mylist, 99) #pdb
-plugin = mylib.get_plugin(mylist, 83) #trr
+#plugin = mylib.get_plugin(mylist, 83) #trr
 #plugin = mylib.get_plugin(mylist, 85) #xtc
-#plugin = mylib.get_plugin(mylist, 105) #psf
+plugin = mylib.get_plugin(mylist, 105) #psf
 #plugin = mylib.get_plugin(mylist, 81) #gro
 #plugin = mylib.get_plugin(mylist, 69) #dcd
 print(plugin)
@@ -144,14 +144,14 @@ numatoms=molnatoms(natoms)
 #fname="../../test/md.gro"
 #fname="../../test/ala3.dcd"
 #fname="../../test/ala3.pdb"
-#fname="../../test/ala3.psf"
-fname="../../test/md.trr"
+fname="../../test/ala3.psf"
+#fname="../../test/md.trr"
 #fname="../../test/md.xtc"
 #fname="../../test/md_1u19.xtc"
 #ftype="pdb"
-ftype="trr"
+#ftype="trr"
 #ftype="xtc"
-#ftype="psf"
+ftype="psf"
 #ftype="gro"
 #ftype="dcd"
 
@@ -184,10 +184,19 @@ print(y)
 print(len(y))
 print(y.__array_interface__)
 print(y.__array_interface__["descr"])
+z = mylib.read_fill_bonds(pluginhandle)
+print(z)
+print(len(z))
+a = mylib.read_fill_angles(pluginhandle)
+print(a)
+print(len(a))
 #outarray = mylib.get_structure(pluginhandle)
 #print(outarray)
 #print(type(outarray))
 #for i in outarray:
 #    print(i)
+mylib.close_file_read(pluginhandle)
+y = mylib.read_fill_structure(pluginhandle, x)
+mylib.molfile_finish()