[med-svn] [python-cutadapt] 04/12: Imported Upstream version 1.10

Andreas Tille tille at debian.org
Mon Jun 20 13:39:51 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository python-cutadapt.

commit 250b0dc7c728a2b80be31466297ad922aecde710
Author: Andreas Tille <tille at debian.org>
Date:   Mon Jun 20 15:26:00 2016 +0200

    Imported Upstream version 1.10
---
 CHANGES.rst                  |   22 +
 LICENSE                      |    2 +-
 PKG-INFO                     |    2 +-
 cutadapt/__init__.py         |    2 +-
 cutadapt/__main__.py         |   12 -
 cutadapt/_align.c            | 4016 +++++++++---------------------------------
 cutadapt/_align.pyx          |    1 +
 cutadapt/_align.so           |  Bin 532496 -> 0 bytes
 cutadapt/_qualtrim.c         |  743 ++++++--
 cutadapt/_qualtrim.pyx       |   36 +
 cutadapt/_qualtrim.so        |  Bin 92136 -> 0 bytes
 cutadapt/_seqio.c            | 2320 ++++++++----------------
 cutadapt/_seqio.pyx          |   59 +-
 cutadapt/_seqio.so           |  Bin 397664 -> 0 bytes
 cutadapt/adapters.py         |  264 ++-
 cutadapt/filters.py          |    8 +-
 cutadapt/modifiers.py        |   63 +-
 cutadapt/qualtrim.py         |   31 +-
 cutadapt/report.py           |   35 +-
 cutadapt/scripts/cutadapt.py |  214 +--
 cutadapt/seqio.py            |  413 +++--
 cutadapt/xopen.py            |   10 +-
 doc/colorspace.rst           |   23 +-
 doc/conf.py                  |    2 +-
 doc/guide.rst                |   59 +-
 doc/ideas.rst                |   14 +-
 doc/installation.rst         |   72 +-
 setup.py                     |   57 +-
 tests/cut/linked.fasta       |   10 +
 tests/cut/nextseq.fastq      |    8 +
 tests/cut/small.fasta        |    6 +
 tests/data/linked.fasta      |   10 +
 tests/data/nextseq.fastq     |    8 +
 tests/testadapters.py        |   43 +-
 tests/testpaired.py          |   11 +-
 tests/testqualtrim.py        |   14 +
 tests/tests.py               |   30 +-
 tests/testseqio.py           |   53 +-
 tests/utils.py               |    2 +-
 39 files changed, 3324 insertions(+), 5351 deletions(-)

diff --git a/CHANGES.rst b/CHANGES.rst
index deafe82..c3c97b2 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -2,6 +2,28 @@
 Changes
 =======
 
+v1.10
+-----
+
+* Added a new “linked adapter” type, which can be used to search for a 5' and a
+  3' adapter at the same time. Use ``-a ADAPTER1...ADAPTER2` to search
+  for a linked adapter. ADAPTER1 is interpreted as an anchored 5' adapter, which
+  is searched for first. Only if ADAPTER1 is found will ADAPTER2 be searched
+  for, which is a regular 3' adapter.
+* Added experimental ``--nextseq-trim`` option for quality trimming of NextSeq
+  data. This is necessary because that machine cannot distinguish between G and
+  reaching the end of the fragment (it encodes G as 'black').
+* Even when trimming FASTQ files, output can now be FASTA (quality values are
+  simply dropped). Use the ``-o``/``-p`` options with a file name that ends in
+  ``.fasta`` or ``.fa`` to enable this.
+* Cutadapt does not bundle pre-compiled C extension modules (``.so`` files)
+  anymore. This affects only users that run cutadapt directly from an unpacked
+  tarball. Install through ``pip`` or ``conda`` instead.
+* Fix issue #167: Option ``--quiet`` was not entirely quiet.
+* Fix issue #199: Be less strict when checking for properly-paired reads.
+* This is the last version of cutadapt to support Python 2.6. Future versions
+  will require at least Python 2.7.
+
 v1.9.1
 ------
 
diff --git a/LICENSE b/LICENSE
index e3ebf36..df04e21 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2010-2015 Marcel Martin <marcel.martin at scilifelab.se>
+Copyright (c) 2010-2016 Marcel Martin <marcel.martin at scilifelab.se>
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/PKG-INFO b/PKG-INFO
index 55eefca..85f3ecb 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cutadapt
-Version: 1.9.1
+Version: 1.10
 Summary: trim adapters from high-throughput sequencing reads
 Home-page: https://cutadapt.readthedocs.org/
 Author: Marcel Martin
diff --git a/cutadapt/__init__.py b/cutadapt/__init__.py
index c999841..e3422c7 100644
--- a/cutadapt/__init__.py
+++ b/cutadapt/__init__.py
@@ -2,7 +2,7 @@
 from __future__ import print_function, division, absolute_import
 import sys
 
-__version__ = '1.9.1'
+__version__ = '1.10'
 
 def check_importability():  # pragma: no cover
 	try:
diff --git a/cutadapt/__main__.py b/cutadapt/__main__.py
deleted file mode 100755
index 5f29857..0000000
--- a/cutadapt/__main__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-from __future__ import print_function, division, absolute_import
-import sys
-
-try:
-	import _preamble
-except ImportError:
-	pass
-
-from cutadapt.scripts import cutadapt
-cutadapt.main()
diff --git a/cutadapt/_align.c b/cutadapt/_align.c
index 9770fbf..aec12bb 100644
--- a/cutadapt/_align.c
+++ b/cutadapt/_align.c
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.23.4 */
+/* Generated by Cython 0.24 */
 
 /* BEGIN: Cython Metadata
 {
@@ -15,10 +15,10 @@ END: Cython Metadata */
 #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03020000)
     #error Cython requires Python 2.6+ or Python 3.2+.
 #else
-#define CYTHON_ABI "0_23_4"
+#define CYTHON_ABI "0_24"
 #include <stddef.h>
 #ifndef offsetof
-#define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
+  #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
 #endif
 #if !defined(WIN32) && !defined(MS_WINDOWS)
   #ifndef __stdcall
@@ -44,17 +44,23 @@ END: Cython Metadata */
   #define Py_HUGE_VAL HUGE_VAL
 #endif
 #ifdef PYPY_VERSION
-#define CYTHON_COMPILING_IN_PYPY 1
-#define CYTHON_COMPILING_IN_CPYTHON 0
+  #define CYTHON_COMPILING_IN_PYPY 1
+  #define CYTHON_COMPILING_IN_CPYTHON 0
 #else
-#define CYTHON_COMPILING_IN_PYPY 0
-#define CYTHON_COMPILING_IN_CPYTHON 1
+  #define CYTHON_COMPILING_IN_PYPY 0
+  #define CYTHON_COMPILING_IN_CPYTHON 1
 #endif
 #if !defined(CYTHON_USE_PYLONG_INTERNALS) && CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070000
-#define CYTHON_USE_PYLONG_INTERNALS 1
+  #define CYTHON_USE_PYLONG_INTERNALS 1
+#endif
+#if CYTHON_USE_PYLONG_INTERNALS
+  #include "longintrepr.h"
+  #undef SHIFT
+  #undef BASE
+  #undef MASK
 #endif
 #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag)
-#define Py_OptimizeFlag 0
+  #define Py_OptimizeFlag 0
 #endif
 #define __PYX_BUILD_PY_SSIZE_T "n"
 #define CYTHON_FORMAT_SSIZE_T "z"
@@ -90,6 +96,7 @@ END: Cython Metadata */
   #define __Pyx_PyUnicode_KIND(u)         PyUnicode_KIND(u)
   #define __Pyx_PyUnicode_DATA(u)         PyUnicode_DATA(u)
   #define __Pyx_PyUnicode_READ(k, d, i)   PyUnicode_READ(k, d, i)
+  #define __Pyx_PyUnicode_IS_TRUE(u)      (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u)))
 #else
   #define CYTHON_PEP393_ENABLED 0
   #define __Pyx_PyUnicode_READY(op)       (0)
@@ -98,6 +105,7 @@ END: Cython Metadata */
   #define __Pyx_PyUnicode_KIND(u)         (sizeof(Py_UNICODE))
   #define __Pyx_PyUnicode_DATA(u)         ((void*)PyUnicode_AS_UNICODE(u))
   #define __Pyx_PyUnicode_READ(k, d, i)   ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i]))
+  #define __Pyx_PyUnicode_IS_TRUE(u)      (0 != PyUnicode_GET_SIZE(u))
 #endif
 #if CYTHON_COMPILING_IN_PYPY
   #define __Pyx_PyUnicode_Concat(a, b)      PyNumber_Add(a, b)
@@ -110,6 +118,14 @@ END: Cython Metadata */
 #if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains)
   #define PyUnicode_Contains(u, s)  PySequence_Contains(u, s)
 #endif
+#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format)
+  #define PyObject_Format(obj, fmt)  PyObject_CallMethod(obj, "__format__", "O", fmt)
+#endif
+#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc)
+  #define PyObject_Malloc(s)   PyMem_Malloc(s)
+  #define PyObject_Free(p)     PyMem_Free(p)
+  #define PyObject_Realloc(p)  PyMem_Realloc(p)
+#endif
 #define __Pyx_PyString_FormatSafe(a, b)   ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b))
 #define __Pyx_PyUnicode_FormatSafe(a, b)  ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b))
 #if PY_MAJOR_VERSION >= 3
@@ -117,6 +133,9 @@ END: Cython Metadata */
 #else
   #define __Pyx_PyString_Format(a, b)  PyString_Format(a, b)
 #endif
+#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII)
+  #define PyObject_ASCII(o)            PyObject_Repr(o)
+#endif
 #if PY_MAJOR_VERSION >= 3
   #define PyBaseString_Type            PyUnicode_Type
   #define PyStringObject               PyUnicodeObject
@@ -226,6 +245,11 @@ static CYTHON_INLINE float __PYX_NAN() {
 #endif
 
 
+#define __PYX_ERR(f_index, lineno, Ln_error) \
+{ \
+  __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \
+}
+
 #if PY_MAJOR_VERSION >= 3
   #define __Pyx_PyNumber_Divide(x,y)         PyNumber_TrueDivide(x,y)
   #define __Pyx_PyNumber_InPlaceDivide(x,y)  PyNumber_InPlaceTrueDivide(x,y)
@@ -272,7 +296,7 @@ static CYTHON_INLINE float __PYX_NAN() {
 #  define CYTHON_NCP_UNUSED CYTHON_UNUSED
 # endif
 #endif
-typedef struct {PyObject **p; char *s; const Py_ssize_t n; const char* encoding;
+typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding;
                 const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry;
 
 #define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0
@@ -346,7 +370,7 @@ static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)
 #define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None)
 #define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False))
 static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
-static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
 static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
 static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
 #if CYTHON_COMPILING_IN_CPYTHON
@@ -355,6 +379,12 @@ static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
 #define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x)
 #endif
 #define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x))
+#if PY_MAJOR_VERSION >= 3
+#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x))
+#else
+#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x))
+#endif
+#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x))
 #if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII
 static int __Pyx_sys_getdefaultencoding_not_ascii;
 static int __Pyx_init_sys_getdefaultencoding_params(void) {
@@ -445,6 +475,7 @@ static PyObject *__pyx_d;
 static PyObject *__pyx_b;
 static PyObject *__pyx_empty_tuple;
 static PyObject *__pyx_empty_bytes;
+static PyObject *__pyx_empty_unicode;
 static int __pyx_lineno;
 static int __pyx_clineno = 0;
 static const char * __pyx_cfilenm= __FILE__;
@@ -465,26 +496,12 @@ typedef struct __pyx_t_8cutadapt_6_align__Entry __pyx_t_8cutadapt_6_align__Entry
 struct __pyx_t_8cutadapt_6_align__Match;
 typedef struct __pyx_t_8cutadapt_6_align__Match __pyx_t_8cutadapt_6_align__Match;
 
-/* "cutadapt/_align.pyx":10
- * 
- * # structure for a DP matrix entry
- * ctypedef struct _Entry:             # <<<<<<<<<<<<<<
- * 	int cost
- * 	int matches  # no. of matches in this alignment
- */
 struct __pyx_t_8cutadapt_6_align__Entry {
   int cost;
   int matches;
   int origin;
 };
 
-/* "cutadapt/_align.pyx":16
- * 
- * 
- * ctypedef struct _Match:             # <<<<<<<<<<<<<<
- * 	int origin
- * 	int cost
- */
 struct __pyx_t_8cutadapt_6_align__Match {
   int origin;
   int cost;
@@ -493,13 +510,6 @@ struct __pyx_t_8cutadapt_6_align__Match {
   int query_stop;
 };
 
-/* "cutadapt/_align.pyx":118
- * 
- * 
- * cdef class Aligner:             # <<<<<<<<<<<<<<
- * 	"""
- * 	TODO documentation still uses s1 (reference) and s2 (query).
- */
 struct __pyx_obj_8cutadapt_6_align_Aligner {
   PyObject_HEAD
   int m;
@@ -518,13 +528,6 @@ struct __pyx_obj_8cutadapt_6_align_Aligner {
 };
 
 
-/* "cutadapt/_align.pyx":107
- * 		self._rows[i][j] = cost
- * 
- * 	def __str__(self):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Return a representation of the matrix as a string.
- */
 struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ {
   PyObject_HEAD
   PyObject *__pyx_v_row;
@@ -532,13 +535,6 @@ struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ {
 };
 
 
-/* "cutadapt/_align.pyx":111
- * 		Return a representation of the matrix as a string.
- * 		"""
- * 		rows = ['     ' + ' '.join(c.rjust(2) for c in self.query)]             # <<<<<<<<<<<<<<
- * 		for c, row in zip(' ' + self.reference, self._rows):
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)
- */
 struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_1_genexpr {
   PyObject_HEAD
   struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ *__pyx_outer_scope;
@@ -549,13 +545,6 @@ struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_1_genexpr {
 };
 
 
-/* "cutadapt/_align.pyx":113
- * 		rows = ['     ' + ' '.join(c.rjust(2) for c in self.query)]
- * 		for c, row in zip(' ' + self.reference, self._rows):
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)             # <<<<<<<<<<<<<<
- * 			rows.append(r)
- * 		return '\n'.join(rows)
- */
 struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_2_genexpr {
   PyObject_HEAD
   struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ *__pyx_outer_scope;
@@ -567,6 +556,7 @@ struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_2_genexpr {
 
 
 /* --- Runtime support code (head) --- */
+/* Refnanny.proto */
 #ifndef CYTHON_REFNANNY
   #define CYTHON_REFNANNY 0
 #endif
@@ -629,6 +619,7 @@ struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_2_genexpr {
 #define __Pyx_CLEAR(r)    do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0)
 #define __Pyx_XCLEAR(r)   do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0)
 
+/* PyObjectGetAttrStr.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) {
     PyTypeObject* tp = Py_TYPE(obj);
@@ -644,16 +635,20 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject
 #define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n)
 #endif
 
+/* GetBuiltinName.proto */
 static PyObject *__Pyx_GetBuiltinName(PyObject *name);
 
+/* PyObjectCall.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw);
 #else
 #define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw)
 #endif
 
+/* py_dict_items.proto */
 static CYTHON_INLINE PyObject* __Pyx_PyDict_Items(PyObject* d);
 
+/* UnpackUnboundCMethod.proto */
 typedef struct {
     PyObject *type;
     PyObject **method_name;
@@ -662,6 +657,7 @@ typedef struct {
     int flag;
 } __Pyx_CachedCFunction;
 
+/* CallUnboundCMethod0.proto */
 static PyObject* __Pyx__CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObject* self);
 #if CYTHON_COMPILING_IN_CPYTHON
 #define __Pyx_CallUnboundCMethod0(cfunc, self)\
@@ -674,16 +670,22 @@ static PyObject* __Pyx__CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObje
 #define __Pyx_CallUnboundCMethod0(cfunc, self)  __Pyx__CallUnboundCMethod0(cfunc, self)
 #endif
 
+/* RaiseTooManyValuesToUnpack.proto */
 static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected);
 
+/* RaiseNeedMoreValuesToUnpack.proto */
 static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
 
+/* IterFinish.proto */
 static CYTHON_INLINE int __Pyx_IterFinish(void);
 
+/* UnpackItemEndCheck.proto */
 static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected);
 
+/* UnicodeAsUCS4.proto */
 static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject*);
 
+/* object_ord.proto */
 #if PY_MAJOR_VERSION >= 3
 #define __Pyx_PyObject_Ord(c)\
     (likely(PyUnicode_Check(c)) ? (long)__Pyx_PyUnicode_AsPy_UCS4(c) : __Pyx__PyObject_Ord(c))
@@ -692,6 +694,7 @@ static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject*);
 #endif
 static long __Pyx__PyObject_Ord(PyObject* c);
 
+/* SetItemIntByteArray.proto */
 #define __Pyx_SetItemInt_ByteArray(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
     (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
     __Pyx_SetItemInt_ByteArray_Fast(o, (Py_ssize_t)i, v, wraparound, boundscheck) :\
@@ -699,27 +702,34 @@ static long __Pyx__PyObject_Ord(PyObject* c);
 static CYTHON_INLINE int __Pyx_SetItemInt_ByteArray_Fast(PyObject* string, Py_ssize_t i, unsigned char v,
                                                          int wraparound, int boundscheck);
 
+/* PyObjectCallMethO.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg);
 #endif
 
+/* PyObjectCallOneArg.proto */
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg);
 
+/* PyObjectCallNoArg.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func);
 #else
 #define __Pyx_PyObject_CallNoArg(func) __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL)
 #endif
 
+/* RaiseArgTupleInvalid.proto */
 static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
     Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found);
 
+/* RaiseDoubleKeywords.proto */
 static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name);
 
+/* ParseKeywords.proto */
 static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\
     PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\
     const char* function_name);
 
+/* PyIntBinop.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace);
 #else
@@ -727,6 +737,7 @@ static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, long intval,
     (inplace ? PyNumber_InPlaceAdd(op1, op2) : PyNumber_Add(op1, op2))
 #endif
 
+/* ListCompAppend.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) {
     PyListObject* L = (PyListObject*) list;
@@ -743,6 +754,7 @@ static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) {
 #define __Pyx_ListComp_Append(L,x) PyList_Append(L,x)
 #endif
 
+/* PyObjectSetAttrStr.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 #define __Pyx_PyObject_DelAttrStr(o,n) __Pyx_PyObject_SetAttrStr(o,n,NULL)
 static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value) {
@@ -760,6 +772,7 @@ static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr
 #define __Pyx_PyObject_SetAttrStr(o,n,v) PyObject_SetAttr(o,n,v)
 #endif
 
+/* GetItemInt.proto */
 #define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
     (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
     __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\
@@ -781,6 +794,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
                                                      int is_list, int wraparound, int boundscheck);
 
+/* SetItemInt.proto */
 #define __Pyx_SetItemInt(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
     (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
     __Pyx_SetItemInt_Fast(o, (Py_ssize_t)i, v, is_list, wraparound, boundscheck) :\
@@ -790,8 +804,10 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyOb
 static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v,
                                                int is_list, int wraparound, int boundscheck);
 
+/* None.proto */
 static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname);
 
+/* StringJoin.proto */
 #if PY_MAJOR_VERSION < 3
 #define __Pyx_PyString_Join __Pyx_PyBytes_Join
 #define __Pyx_PyBaseString_Join(s, v) (PyUnicode_CheckExact(s) ? PyUnicode_Join(s, v) : __Pyx_PyBytes_Join(s, v))
@@ -809,6 +825,7 @@ static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname);
 static CYTHON_INLINE PyObject* __Pyx_PyBytes_Join(PyObject* sep, PyObject* values);
 #endif
 
+/* ListAppend.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) {
     PyListObject* L = (PyListObject*) list;
@@ -825,24 +842,52 @@ static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) {
 #define __Pyx_PyList_Append(L,x) PyList_Append(L,x)
 #endif
 
+/* ArgTypeTest.proto */
 static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
     const char *name, int exact);
 
-static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb);
-static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb);
+/* PyThreadStateGet.proto */
+#if CYTHON_COMPILING_IN_CPYTHON
+#define __Pyx_PyThreadState_declare  PyThreadState *__pyx_tstate;
+#define __Pyx_PyThreadState_assign  __pyx_tstate = PyThreadState_GET();
+#else
+#define __Pyx_PyThreadState_declare
+#define __Pyx_PyThreadState_assign
+#endif
+
+/* PyErrFetchRestore.proto */
+#if CYTHON_COMPILING_IN_CPYTHON
+#define __Pyx_ErrRestoreWithState(type, value, tb)  __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb)
+#define __Pyx_ErrFetchWithState(type, value, tb)    __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb)
+#define __Pyx_ErrRestore(type, value, tb)  __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb)
+#define __Pyx_ErrFetch(type, value, tb)    __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb)
+static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb);
+static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
+#else
+#define __Pyx_ErrRestoreWithState(type, value, tb)  PyErr_Restore(type, value, tb)
+#define __Pyx_ErrFetchWithState(type, value, tb)  PyErr_Fetch(type, value, tb)
+#define __Pyx_ErrRestore(type, value, tb)  PyErr_Restore(type, value, tb)
+#define __Pyx_ErrFetch(type, value, tb)  PyErr_Fetch(type, value, tb)
+#endif
 
+/* RaiseException.proto */
 static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause);
 
+/* GetModuleGlobalName.proto */
 static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name);
 
+/* ForceInitThreads.proto */
 #ifndef __PYX_FORCE_INIT_THREADS
   #define __PYX_FORCE_INIT_THREADS 0
 #endif
 
+/* IncludeStringH.proto */
 #include <string.h>
 
+/* FetchCommonType.proto */
 static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type);
 
+/* CythonFunction.proto */
 #define __Pyx_CyFunction_USED 1
 #include <structmember.h>
 #define __Pyx_CYFUNCTION_STATICMETHOD  0x01
@@ -896,16 +941,19 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m,
                                                               PyObject *dict);
 static int __pyx_CyFunction_init(void);
 
+/* CalculateMetaclass.proto */
 static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases);
 
+/* Py3ClassCreate.proto */
 static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname,
                                            PyObject *mkw, PyObject *modname, PyObject *doc);
 static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict,
                                       PyObject *mkw, int calculate_metaclass, int allow_py2_metaclass);
 
+/* CodeObjectCache.proto */
 typedef struct {
-    int code_line;
     PyCodeObject* code_object;
+    int code_line;
 } __Pyx_CodeObjectCacheEntry;
 struct __Pyx_CodeObjectCache {
     int count;
@@ -917,23 +965,37 @@ static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int co
 static PyCodeObject *__pyx_find_code_object(int code_line);
 static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object);
 
+/* AddTraceback.proto */
 static void __Pyx_AddTraceback(const char *funcname, int c_line,
                                int py_line, const char *filename);
 
-static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *);
-
+/* CIntToPy.proto */
 static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value);
 
-static CYTHON_INLINE unsigned char __Pyx_PyInt_As_unsigned_char(PyObject *);
-
+/* CIntToPy.proto */
 static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value);
 
+/* CIntFromPy.proto */
+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *);
+
+/* CIntFromPy.proto */
+static CYTHON_INLINE unsigned char __Pyx_PyInt_As_unsigned_char(PyObject *);
+
+/* CIntFromPy.proto */
 static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *);
 
+/* SwapException.proto */
+#if CYTHON_COMPILING_IN_CPYTHON
+#define __Pyx_ExceptionSwap(type, value, tb)  __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb)
+static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
+#else
 static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb);
+#endif
 
+/* PyObjectCallMethod1.proto */
 static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg);
 
+/* CoroutineBase.proto */
 typedef PyObject *(*__pyx_coroutine_body_t)(PyObject *, PyObject *);
 typedef struct {
     PyObject_HEAD
@@ -959,10 +1021,13 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue);
 #define __Pyx_PyGen_FetchStopIterationValue(pvalue) PyGen_FetchStopIterationValue(pvalue)
 #endif
 
+/* PatchModuleWithCoroutine.proto */
 static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code);
 
+/* PatchGeneratorABC.proto */
 static int __Pyx_patch_abc(void);
 
+/* Generator.proto */
 #define __Pyx_Generator_USED
 static PyTypeObject *__pyx_GeneratorType = 0;
 #define __Pyx_Generator_CheckExact(obj) (Py_TYPE(obj) == __pyx_GeneratorType)
@@ -971,8 +1036,10 @@ static PyTypeObject *__pyx_GeneratorType = 0;
 static PyObject *__Pyx_Generator_Next(PyObject *self);
 static int __pyx_Generator_init(void);
 
+/* CheckBinaryVersion.proto */
 static int __Pyx_check_binary_version(void);
 
+/* InitStrings.proto */
 static int __Pyx_InitStrings(__Pyx_StringTabEntry *t);
 
 
@@ -993,103 +1060,101 @@ static PyObject *__pyx_builtin_range;
 static PyObject *__pyx_builtin_zip;
 static PyObject *__pyx_builtin_ValueError;
 static PyObject *__pyx_builtin_MemoryError;
-static char __pyx_k_[] = "\000";
-static char __pyx_k_A[] = "A";
-static char __pyx_k_B[] = "B";
-static char __pyx_k_C[] = "C";
-static char __pyx_k_D[] = "D";
-static char __pyx_k_G[] = "G";
-static char __pyx_k_H[] = "H";
-static char __pyx_k_K[] = "K";
-static char __pyx_k_M[] = "M";
-static char __pyx_k_N[] = "N";
-static char __pyx_k_R[] = "R";
-static char __pyx_k_S[] = "S";
-static char __pyx_k_T[] = "T";
-static char __pyx_k_U[] = "U";
-static char __pyx_k_V[] = "V";
-static char __pyx_k_W[] = "W";
-static char __pyx_k_X[] = "X";
-static char __pyx_k_Y[] = "Y";
-static char __pyx_k_c[] = "c";
-static char __pyx_k_d[] = "d";
-static char __pyx_k_i[] = "i";
-static char __pyx_k_j[] = "j";
-static char __pyx_k_m[] = "m";
-static char __pyx_k_n[] = "n";
-static char __pyx_k_r[] = "r";
-static char __pyx_k_t[] = "t";
-static char __pyx_k_v[] = "v";
-static char __pyx_k__5[] = "  ";
-static char __pyx_k__6[] = "     ";
-static char __pyx_k__7[] = " ";
-static char __pyx_k__8[] = "\n";
-static char __pyx_k__19[] = "_";
-static char __pyx_k_doc[] = "__doc__";
-static char __pyx_k_ref[] = "ref";
-static char __pyx_k_row[] = "row";
-static char __pyx_k_str[] = "__str__";
-static char __pyx_k_zip[] = "zip";
-static char __pyx_k_0_2d[] = "{0:2d}";
-static char __pyx_k_args[] = "args";
-static char __pyx_k_cost[] = "cost";
-static char __pyx_k_init[] = "__init__";
-static char __pyx_k_join[] = "join";
-static char __pyx_k_main[] = "__main__";
-static char __pyx_k_rows[] = "_rows";
-static char __pyx_k_self[] = "self";
-static char __pyx_k_send[] = "send";
-static char __pyx_k_test[] = "__test__";
-static char __pyx_k_ascii[] = "ascii";
-static char __pyx_k_close[] = "close";
-static char __pyx_k_flags[] = "flags";
-static char __pyx_k_items[] = "items";
-static char __pyx_k_lower[] = "lower";
-static char __pyx_k_q_ptr[] = "q_ptr";
-static char __pyx_k_query[] = "query";
-static char __pyx_k_r_ptr[] = "r_ptr";
-static char __pyx_k_range[] = "range";
-static char __pyx_k_rjust[] = "rjust";
-static char __pyx_k_throw[] = "throw";
-static char __pyx_k_encode[] = "encode";
-static char __pyx_k_format[] = "format";
-static char __pyx_k_length[] = "length";
-static char __pyx_k_locate[] = "locate";
-static char __pyx_k_module[] = "__module__";
-static char __pyx_k_rows_2[] = "rows";
-static char __pyx_k_aligner[] = "aligner";
-static char __pyx_k_genexpr[] = "genexpr";
-static char __pyx_k_matches[] = "matches";
-static char __pyx_k_prepare[] = "__prepare__";
-static char __pyx_k_DPMatrix[] = "DPMatrix";
-static char __pyx_k_qualname[] = "__qualname__";
-static char __pyx_k_metaclass[] = "__metaclass__";
-static char __pyx_k_ref_bytes[] = "ref_bytes";
-static char __pyx_k_reference[] = "reference";
-static char __pyx_k_set_entry[] = "set_entry";
-static char __pyx_k_translate[] = "translate";
-static char __pyx_k_ValueError[] = "ValueError";
-static char __pyx_k_acgt_table[] = "_acgt_table";
-static char __pyx_k_MemoryError[] = "MemoryError";
-static char __pyx_k_iupac_table[] = "_iupac_table";
-static char __pyx_k_min_overlap[] = "min_overlap";
-static char __pyx_k_query_bytes[] = "query_bytes";
-static char __pyx_k_wildcard_ref[] = "wildcard_ref";
-static char __pyx_k_compare_ascii[] = "compare_ascii";
-static char __pyx_k_DPMatrix___str[] = "DPMatrix.__str__";
-static char __pyx_k_max_error_rate[] = "max_error_rate";
-static char __pyx_k_wildcard_query[] = "wildcard_query";
-static char __pyx_k_DPMatrix___init[] = "DPMatrix.__init__";
-static char __pyx_k_cutadapt__align[] = "cutadapt._align";
-static char __pyx_k_compare_prefixes[] = "compare_prefixes";
-static char __pyx_k_DPMatrix_set_entry[] = "DPMatrix.set_entry";
-static char __pyx_k_Matches_cost_0_mismatches_cost[] = "\n\t\tMatches cost 0, mismatches cost 1. Only insertion/deletion costs can be\n\t\tchanged.\n\t\t";
-static char __pyx_k_The_dynamic_programming_matrix[] = "\n\t\tThe dynamic programming matrix as a DPMatrix object. This attribute is\n\t\tusually None, unless debugging has been enabled with enable_debug().\n\t\t";
-static char __pyx_k_DPMatrix___str___locals_genexpr[] = "DPMatrix.__str__.<locals>.genexpr";
-static char __pyx_k_Insertion_deletion_cost_must_be[] = "Insertion/deletion cost must be at leat 1";
-static char __pyx_k_Representation_of_the_dynamic_p[] = "\n\tRepresentation of the dynamic-programming matrix.\n\n\tThis used only when debugging is enabled in the Aligner class since the\n\tmatrix is normally not stored in full.\n\n\tEntries in the matrix may be None, in which case that value was not\n\tcomputed.\n\t";
-static char __pyx_k_home_marcel_scm_cutadapt_cutada[] = "/home/marcel/scm/cutadapt/cutadapt/_align.pyx";
-static char __pyx_k_Minimum_overlap_must_be_at_least[] = "Minimum overlap must be at least 1";
+static const char __pyx_k_[] = "\000";
+static const char __pyx_k_A[] = "A";
+static const char __pyx_k_B[] = "B";
+static const char __pyx_k_C[] = "C";
+static const char __pyx_k_D[] = "D";
+static const char __pyx_k_G[] = "G";
+static const char __pyx_k_H[] = "H";
+static const char __pyx_k_K[] = "K";
+static const char __pyx_k_M[] = "M";
+static const char __pyx_k_N[] = "N";
+static const char __pyx_k_R[] = "R";
+static const char __pyx_k_S[] = "S";
+static const char __pyx_k_T[] = "T";
+static const char __pyx_k_U[] = "U";
+static const char __pyx_k_V[] = "V";
+static const char __pyx_k_W[] = "W";
+static const char __pyx_k_X[] = "X";
+static const char __pyx_k_Y[] = "Y";
+static const char __pyx_k_c[] = "c";
+static const char __pyx_k_d[] = "d";
+static const char __pyx_k_i[] = "i";
+static const char __pyx_k_j[] = "j";
+static const char __pyx_k_m[] = "m";
+static const char __pyx_k_n[] = "n";
+static const char __pyx_k_r[] = "r";
+static const char __pyx_k_t[] = "t";
+static const char __pyx_k_v[] = "v";
+static const char __pyx_k__5[] = "  ";
+static const char __pyx_k__6[] = "     ";
+static const char __pyx_k__7[] = " ";
+static const char __pyx_k__8[] = "\n";
+static const char __pyx_k__19[] = "_";
+static const char __pyx_k_doc[] = "__doc__";
+static const char __pyx_k_ref[] = "ref";
+static const char __pyx_k_row[] = "row";
+static const char __pyx_k_str[] = "__str__";
+static const char __pyx_k_zip[] = "zip";
+static const char __pyx_k_0_2d[] = "{0:2d}";
+static const char __pyx_k_args[] = "args";
+static const char __pyx_k_cost[] = "cost";
+static const char __pyx_k_init[] = "__init__";
+static const char __pyx_k_join[] = "join";
+static const char __pyx_k_main[] = "__main__";
+static const char __pyx_k_rows[] = "_rows";
+static const char __pyx_k_self[] = "self";
+static const char __pyx_k_send[] = "send";
+static const char __pyx_k_test[] = "__test__";
+static const char __pyx_k_ascii[] = "ascii";
+static const char __pyx_k_close[] = "close";
+static const char __pyx_k_flags[] = "flags";
+static const char __pyx_k_items[] = "items";
+static const char __pyx_k_lower[] = "lower";
+static const char __pyx_k_q_ptr[] = "q_ptr";
+static const char __pyx_k_query[] = "query";
+static const char __pyx_k_r_ptr[] = "r_ptr";
+static const char __pyx_k_range[] = "range";
+static const char __pyx_k_rjust[] = "rjust";
+static const char __pyx_k_throw[] = "throw";
+static const char __pyx_k_encode[] = "encode";
+static const char __pyx_k_format[] = "format";
+static const char __pyx_k_length[] = "length";
+static const char __pyx_k_locate[] = "locate";
+static const char __pyx_k_module[] = "__module__";
+static const char __pyx_k_rows_2[] = "rows";
+static const char __pyx_k_aligner[] = "aligner";
+static const char __pyx_k_genexpr[] = "genexpr";
+static const char __pyx_k_matches[] = "matches";
+static const char __pyx_k_prepare[] = "__prepare__";
+static const char __pyx_k_DPMatrix[] = "DPMatrix";
+static const char __pyx_k_qualname[] = "__qualname__";
+static const char __pyx_k_metaclass[] = "__metaclass__";
+static const char __pyx_k_ref_bytes[] = "ref_bytes";
+static const char __pyx_k_reference[] = "reference";
+static const char __pyx_k_set_entry[] = "set_entry";
+static const char __pyx_k_translate[] = "translate";
+static const char __pyx_k_ValueError[] = "ValueError";
+static const char __pyx_k_acgt_table[] = "_acgt_table";
+static const char __pyx_k_MemoryError[] = "MemoryError";
+static const char __pyx_k_iupac_table[] = "_iupac_table";
+static const char __pyx_k_min_overlap[] = "min_overlap";
+static const char __pyx_k_query_bytes[] = "query_bytes";
+static const char __pyx_k_wildcard_ref[] = "wildcard_ref";
+static const char __pyx_k_compare_ascii[] = "compare_ascii";
+static const char __pyx_k_DPMatrix___str[] = "DPMatrix.__str__";
+static const char __pyx_k_max_error_rate[] = "max_error_rate";
+static const char __pyx_k_wildcard_query[] = "wildcard_query";
+static const char __pyx_k_DPMatrix___init[] = "DPMatrix.__init__";
+static const char __pyx_k_cutadapt__align[] = "cutadapt._align";
+static const char __pyx_k_compare_prefixes[] = "compare_prefixes";
+static const char __pyx_k_DPMatrix_set_entry[] = "DPMatrix.set_entry";
+static const char __pyx_k_DPMatrix___str___locals_genexpr[] = "DPMatrix.__str__.<locals>.genexpr";
+static const char __pyx_k_Insertion_deletion_cost_must_be[] = "Insertion/deletion cost must be at leat 1";
+static const char __pyx_k_Representation_of_the_dynamic_p[] = "\n\tRepresentation of the dynamic-programming matrix.\n\n\tThis used only when debugging is enabled in the Aligner class since the\n\tmatrix is normally not stored in full.\n\n\tEntries in the matrix may be None, in which case that value was not\n\tcomputed.\n\t";
+static const char __pyx_k_home_marcel_scm_cutadapt_cutada[] = "/home/marcel/scm/cutadapt/cutadapt/_align.pyx";
+static const char __pyx_k_Minimum_overlap_must_be_at_least[] = "Minimum overlap must be at least 1";
 static PyObject *__pyx_kp_b_;
 static PyObject *__pyx_kp_s_0_2d;
 static PyObject *__pyx_n_s_A;
@@ -1239,13 +1304,6 @@ static PyObject *__pyx_codeobj__25;
 static PyObject *__pyx_codeobj__27;
 static PyObject *__pyx_codeobj__29;
 
-/* "cutadapt/_align.pyx":24
- * 
- * 
- * def _acgt_table():             # <<<<<<<<<<<<<<
- * 	"""
- * 	Return a translation table that maps A, C, G, T characters to the lower
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_1_acgt_table(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/
@@ -1279,60 +1337,36 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
   PyObject *(*__pyx_t_8)(PyObject *);
   unsigned char __pyx_t_9;
   long __pyx_t_10;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("_acgt_table", 0);
 
-  /* "cutadapt/_align.pyx":32
- * 	Lowercase versions are also translated, and U is treated the same as T.
- * 	"""
- * 	d = dict(A=1, C=2, G=4, T=8, U=8)             # <<<<<<<<<<<<<<
- * 	t = bytearray(b'\0') * 256
- * 	for c, v in d.items():
- */
-  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 33, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_A, __pyx_int_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_C, __pyx_int_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_G, __pyx_int_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_T, __pyx_int_8) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_U, __pyx_int_8) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_A, __pyx_int_1) < 0) __PYX_ERR(0, 33, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_C, __pyx_int_2) < 0) __PYX_ERR(0, 33, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_G, __pyx_int_4) < 0) __PYX_ERR(0, 33, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_T, __pyx_int_8) < 0) __PYX_ERR(0, 33, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_U, __pyx_int_8) < 0) __PYX_ERR(0, 33, __pyx_L1_error)
   __pyx_v_d = ((PyObject*)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":33
- * 	"""
- * 	d = dict(A=1, C=2, G=4, T=8, U=8)
- * 	t = bytearray(b'\0') * 256             # <<<<<<<<<<<<<<
- * 	for c, v in d.items():
- * 		t[ord(c)] = v
- */
-  __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)(&PyByteArray_Type)), __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)(&PyByteArray_Type)), __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 34, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyNumber_Multiply(__pyx_t_1, __pyx_int_256); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyNumber_Multiply(__pyx_t_1, __pyx_int_256); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 34, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (!(likely(PyByteArray_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytearray", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyByteArray_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytearray", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 34, __pyx_L1_error)
   __pyx_v_t = ((PyObject*)__pyx_t_2);
   __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":34
- * 	d = dict(A=1, C=2, G=4, T=8, U=8)
- * 	t = bytearray(b'\0') * 256
- * 	for c, v in d.items():             # <<<<<<<<<<<<<<
- * 		t[ord(c)] = v
- * 		t[ord(c.lower())] = v
- */
-  __pyx_t_2 = __Pyx_PyDict_Items(__pyx_v_d); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyDict_Items(__pyx_v_d); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 35, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) {
     __pyx_t_1 = __pyx_t_2; __Pyx_INCREF(__pyx_t_1); __pyx_t_3 = 0;
     __pyx_t_4 = NULL;
   } else {
-    __pyx_t_3 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 35, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_4 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 35, __pyx_L1_error)
   }
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   for (;;) {
@@ -1340,17 +1374,17 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
       if (likely(PyList_CheckExact(__pyx_t_1))) {
         if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_1)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 35, __pyx_L1_error)
         #else
-        __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 35, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_2);
         #endif
       } else {
         if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 35, __pyx_L1_error)
         #else
-        __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 35, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_2);
         #endif
       }
@@ -1360,7 +1394,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
         PyObject* exc_type = PyErr_Occurred();
         if (exc_type) {
           if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else __PYX_ERR(0, 35, __pyx_L1_error)
         }
         break;
       }
@@ -1376,7 +1410,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
       if (unlikely(size != 2)) {
         if (size > 2) __Pyx_RaiseTooManyValuesError(2);
         else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
-        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __PYX_ERR(0, 35, __pyx_L1_error)
       }
       #if CYTHON_COMPILING_IN_CPYTHON
       if (likely(PyTuple_CheckExact(sequence))) {
@@ -1389,15 +1423,15 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
       __Pyx_INCREF(__pyx_t_5);
       __Pyx_INCREF(__pyx_t_6);
       #else
-      __pyx_t_5 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_5 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 35, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_5);
-      __pyx_t_6 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_6 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 35, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_6);
       #endif
       __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     } else {
       Py_ssize_t index = -1;
-      __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 35, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_7);
       __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
       __pyx_t_8 = Py_TYPE(__pyx_t_7)->tp_iternext;
@@ -1405,7 +1439,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
       __Pyx_GOTREF(__pyx_t_5);
       index = 1; __pyx_t_6 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_6)) goto __pyx_L5_unpacking_failed;
       __Pyx_GOTREF(__pyx_t_6);
-      if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) __PYX_ERR(0, 35, __pyx_L1_error)
       __pyx_t_8 = NULL;
       __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
       goto __pyx_L6_unpacking_done;
@@ -1413,7 +1447,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
       __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
       __pyx_t_8 = NULL;
       if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
-      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __PYX_ERR(0, 35, __pyx_L1_error)
       __pyx_L6_unpacking_done:;
     }
     __Pyx_XDECREF_SET(__pyx_v_c, __pyx_t_5);
@@ -1421,26 +1455,12 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
     __Pyx_XDECREF_SET(__pyx_v_v, __pyx_t_6);
     __pyx_t_6 = 0;
 
-    /* "cutadapt/_align.pyx":35
- * 	t = bytearray(b'\0') * 256
- * 	for c, v in d.items():
- * 		t[ord(c)] = v             # <<<<<<<<<<<<<<
- * 		t[ord(c.lower())] = v
- * 	return bytes(t)
- */
-    __pyx_t_9 = __Pyx_PyInt_As_unsigned_char(__pyx_v_v); if (unlikely((__pyx_t_9 == (unsigned char)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_10 = __Pyx_PyObject_Ord(__pyx_v_c); if (unlikely(__pyx_t_10 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    if (unlikely(__Pyx_SetItemInt_ByteArray(__pyx_v_t, __pyx_t_10, __pyx_t_9, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_align.pyx":36
- * 	for c, v in d.items():
- * 		t[ord(c)] = v
- * 		t[ord(c.lower())] = v             # <<<<<<<<<<<<<<
- * 	return bytes(t)
- * 
- */
-    __pyx_t_9 = __Pyx_PyInt_As_unsigned_char(__pyx_v_v); if (unlikely((__pyx_t_9 == (unsigned char)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_c, __pyx_n_s_lower); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_9 = __Pyx_PyInt_As_unsigned_char(__pyx_v_v); if (unlikely((__pyx_t_9 == (unsigned char)-1) && PyErr_Occurred())) __PYX_ERR(0, 36, __pyx_L1_error)
+    __pyx_t_10 = __Pyx_PyObject_Ord(__pyx_v_c); if (unlikely(__pyx_t_10 == (long)(Py_UCS4)-1)) __PYX_ERR(0, 36, __pyx_L1_error)
+    if (unlikely(__Pyx_SetItemInt_ByteArray(__pyx_v_t, __pyx_t_10, __pyx_t_9, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) __PYX_ERR(0, 36, __pyx_L1_error)
+
+    __pyx_t_9 = __Pyx_PyInt_As_unsigned_char(__pyx_v_v); if (unlikely((__pyx_t_9 == (unsigned char)-1) && PyErr_Occurred())) __PYX_ERR(0, 37, __pyx_L1_error)
+    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_c, __pyx_n_s_lower); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 37, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
     __pyx_t_5 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_6))) {
@@ -1453,54 +1473,33 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
       }
     }
     if (__pyx_t_5) {
-      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_5); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 37, __pyx_L1_error)
       __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
     } else {
-      __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_6); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_6); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 37, __pyx_L1_error)
     }
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-    __pyx_t_10 = __Pyx_PyObject_Ord(__pyx_t_2); if (unlikely(__pyx_t_10 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_10 = __Pyx_PyObject_Ord(__pyx_t_2); if (unlikely(__pyx_t_10 == (long)(Py_UCS4)-1)) __PYX_ERR(0, 37, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    if (unlikely(__Pyx_SetItemInt_ByteArray(__pyx_v_t, __pyx_t_10, __pyx_t_9, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_align.pyx":34
- * 	d = dict(A=1, C=2, G=4, T=8, U=8)
- * 	t = bytearray(b'\0') * 256
- * 	for c, v in d.items():             # <<<<<<<<<<<<<<
- * 		t[ord(c)] = v
- * 		t[ord(c.lower())] = v
- */
+    if (unlikely(__Pyx_SetItemInt_ByteArray(__pyx_v_t, __pyx_t_10, __pyx_t_9, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) __PYX_ERR(0, 37, __pyx_L1_error)
+
   }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":37
- * 		t[ord(c)] = v
- * 		t[ord(c.lower())] = v
- * 	return bytes(t)             # <<<<<<<<<<<<<<
- * 
- * 
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 38, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(__pyx_v_t);
   __Pyx_GIVEREF(__pyx_v_t);
   PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_t);
-  __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)(&PyBytes_Type)), __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)(&PyBytes_Type)), __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 38, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __pyx_r = __pyx_t_2;
   __pyx_t_2 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_align.pyx":24
- * 
- * 
- * def _acgt_table():             # <<<<<<<<<<<<<<
- * 	"""
- * 	Return a translation table that maps A, C, G, T characters to the lower
- */
 
   /* function exit code */
   __pyx_L1_error:;
@@ -1521,13 +1520,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":40
- * 
- * 
- * def _iupac_table():             # <<<<<<<<<<<<<<
- * 	"""
- * 	Return a translation table for IUPAC characters.
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_3_iupac_table(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/
@@ -1565,284 +1557,120 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
   PyObject *(*__pyx_t_8)(PyObject *);
   unsigned char __pyx_t_9;
   long __pyx_t_10;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("_iupac_table", 0);
 
-  /* "cutadapt/_align.pyx":50
- * 	expression "x & y != 0".
- * 	"""
- * 	A = 1             # <<<<<<<<<<<<<<
- * 	C = 2
- * 	G = 4
- */
   __pyx_v_A = 1;
 
-  /* "cutadapt/_align.pyx":51
- * 	"""
- * 	A = 1
- * 	C = 2             # <<<<<<<<<<<<<<
- * 	G = 4
- * 	T = 8
- */
   __pyx_v_C = 2;
 
-  /* "cutadapt/_align.pyx":52
- * 	A = 1
- * 	C = 2
- * 	G = 4             # <<<<<<<<<<<<<<
- * 	T = 8
- * 	d = dict(
- */
   __pyx_v_G = 4;
 
-  /* "cutadapt/_align.pyx":53
- * 	C = 2
- * 	G = 4
- * 	T = 8             # <<<<<<<<<<<<<<
- * 	d = dict(
- * 		X=0,
- */
   __pyx_v_T = 8;
 
-  /* "cutadapt/_align.pyx":55
- * 	T = 8
- * 	d = dict(
- * 		X=0,             # <<<<<<<<<<<<<<
- * 		A=A,
- * 		C=C,
- */
-  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_X, __pyx_int_0) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":56
- * 	d = dict(
- * 		X=0,
- * 		A=A,             # <<<<<<<<<<<<<<
- * 		C=C,
- * 		G=G,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_A); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_X, __pyx_int_0) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
+
+  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_A); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 57, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_A, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_A, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":57
- * 		X=0,
- * 		A=A,
- * 		C=C,             # <<<<<<<<<<<<<<
- * 		G=G,
- * 		T=T,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_C); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_C); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 58, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_C, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_C, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":58
- * 		A=A,
- * 		C=C,
- * 		G=G,             # <<<<<<<<<<<<<<
- * 		T=T,
- * 		U=T,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_G); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_G); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 59, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_G, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_G, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":59
- * 		C=C,
- * 		G=G,
- * 		T=T,             # <<<<<<<<<<<<<<
- * 		U=T,
- * 		R=A|G,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_T); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_T); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 60, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_T, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_T, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":60
- * 		G=G,
- * 		T=T,
- * 		U=T,             # <<<<<<<<<<<<<<
- * 		R=A|G,
- * 		Y=C|T,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_T); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_T); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 61, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_U, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_U, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":61
- * 		T=T,
- * 		U=T,
- * 		R=A|G,             # <<<<<<<<<<<<<<
- * 		Y=C|T,
- * 		S=G|C,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_A | __pyx_v_G)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_A | __pyx_v_G)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 62, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_R, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_R, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":62
- * 		U=T,
- * 		R=A|G,
- * 		Y=C|T,             # <<<<<<<<<<<<<<
- * 		S=G|C,
- * 		W=A|T,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_C | __pyx_v_T)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_C | __pyx_v_T)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 63, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_Y, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_Y, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":63
- * 		R=A|G,
- * 		Y=C|T,
- * 		S=G|C,             # <<<<<<<<<<<<<<
- * 		W=A|T,
- * 		K=G|T,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_G | __pyx_v_C)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_G | __pyx_v_C)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 64, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_S, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_S, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":64
- * 		Y=C|T,
- * 		S=G|C,
- * 		W=A|T,             # <<<<<<<<<<<<<<
- * 		K=G|T,
- * 		M=A|C,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_A | __pyx_v_T)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_A | __pyx_v_T)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 65, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_W, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_W, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":65
- * 		S=G|C,
- * 		W=A|T,
- * 		K=G|T,             # <<<<<<<<<<<<<<
- * 		M=A|C,
- * 		B=C|G|T,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_G | __pyx_v_T)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_G | __pyx_v_T)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 66, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_K, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_K, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":66
- * 		W=A|T,
- * 		K=G|T,
- * 		M=A|C,             # <<<<<<<<<<<<<<
- * 		B=C|G|T,
- * 		D=A|G|T,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_A | __pyx_v_C)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long((__pyx_v_A | __pyx_v_C)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 67, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_M, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_M, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":67
- * 		K=G|T,
- * 		M=A|C,
- * 		B=C|G|T,             # <<<<<<<<<<<<<<
- * 		D=A|G|T,
- * 		H=A|C|T,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long(((__pyx_v_C | __pyx_v_G) | __pyx_v_T)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long(((__pyx_v_C | __pyx_v_G) | __pyx_v_T)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 68, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_B, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_B, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":68
- * 		M=A|C,
- * 		B=C|G|T,
- * 		D=A|G|T,             # <<<<<<<<<<<<<<
- * 		H=A|C|T,
- * 		V=A|C|G,
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long(((__pyx_v_A | __pyx_v_G) | __pyx_v_T)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long(((__pyx_v_A | __pyx_v_G) | __pyx_v_T)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 69, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_D, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_D, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":69
- * 		B=C|G|T,
- * 		D=A|G|T,
- * 		H=A|C|T,             # <<<<<<<<<<<<<<
- * 		V=A|C|G,
- * 		N=A|C|G|T
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long(((__pyx_v_A | __pyx_v_C) | __pyx_v_T)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long(((__pyx_v_A | __pyx_v_C) | __pyx_v_T)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 70, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_H, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_H, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":70
- * 		D=A|G|T,
- * 		H=A|C|T,
- * 		V=A|C|G,             # <<<<<<<<<<<<<<
- * 		N=A|C|G|T
- * 	)
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long(((__pyx_v_A | __pyx_v_C) | __pyx_v_G)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long(((__pyx_v_A | __pyx_v_C) | __pyx_v_G)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 71, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_V, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_V, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":71
- * 		H=A|C|T,
- * 		V=A|C|G,
- * 		N=A|C|G|T             # <<<<<<<<<<<<<<
- * 	)
- * 	t = bytearray(b'\0') * 256
- */
-  __pyx_t_2 = __Pyx_PyInt_From_long((((__pyx_v_A | __pyx_v_C) | __pyx_v_G) | __pyx_v_T)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 71; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_long((((__pyx_v_A | __pyx_v_C) | __pyx_v_G) | __pyx_v_T)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 72, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_N, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_N, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_v_d = ((PyObject*)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":73
- * 		N=A|C|G|T
- * 	)
- * 	t = bytearray(b'\0') * 256             # <<<<<<<<<<<<<<
- * 	for c, v in d.items():
- * 		t[ord(c)] = v
- */
-  __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)(&PyByteArray_Type)), __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)(&PyByteArray_Type)), __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyNumber_Multiply(__pyx_t_1, __pyx_int_256); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyNumber_Multiply(__pyx_t_1, __pyx_int_256); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 74, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (!(likely(PyByteArray_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytearray", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyByteArray_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytearray", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 74, __pyx_L1_error)
   __pyx_v_t = ((PyObject*)__pyx_t_2);
   __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":74
- * 	)
- * 	t = bytearray(b'\0') * 256
- * 	for c, v in d.items():             # <<<<<<<<<<<<<<
- * 		t[ord(c)] = v
- * 		t[ord(c.lower())] = v
- */
-  __pyx_t_2 = __Pyx_PyDict_Items(__pyx_v_d); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyDict_Items(__pyx_v_d); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) {
     __pyx_t_1 = __pyx_t_2; __Pyx_INCREF(__pyx_t_1); __pyx_t_3 = 0;
     __pyx_t_4 = NULL;
   } else {
-    __pyx_t_3 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 75, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_4 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 75, __pyx_L1_error)
   }
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   for (;;) {
@@ -1850,17 +1678,17 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
       if (likely(PyList_CheckExact(__pyx_t_1))) {
         if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_1)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 75, __pyx_L1_error)
         #else
-        __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_2);
         #endif
       } else {
         if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 75, __pyx_L1_error)
         #else
-        __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_2);
         #endif
       }
@@ -1870,7 +1698,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
         PyObject* exc_type = PyErr_Occurred();
         if (exc_type) {
           if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else __PYX_ERR(0, 75, __pyx_L1_error)
         }
         break;
       }
@@ -1886,7 +1714,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
       if (unlikely(size != 2)) {
         if (size > 2) __Pyx_RaiseTooManyValuesError(2);
         else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
-        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __PYX_ERR(0, 75, __pyx_L1_error)
       }
       #if CYTHON_COMPILING_IN_CPYTHON
       if (likely(PyTuple_CheckExact(sequence))) {
@@ -1899,15 +1727,15 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
       __Pyx_INCREF(__pyx_t_5);
       __Pyx_INCREF(__pyx_t_6);
       #else
-      __pyx_t_5 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_5 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 75, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_5);
-      __pyx_t_6 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_6 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 75, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_6);
       #endif
       __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     } else {
       Py_ssize_t index = -1;
-      __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 75, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_7);
       __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
       __pyx_t_8 = Py_TYPE(__pyx_t_7)->tp_iternext;
@@ -1915,7 +1743,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
       __Pyx_GOTREF(__pyx_t_5);
       index = 1; __pyx_t_6 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_6)) goto __pyx_L5_unpacking_failed;
       __Pyx_GOTREF(__pyx_t_6);
-      if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) __PYX_ERR(0, 75, __pyx_L1_error)
       __pyx_t_8 = NULL;
       __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
       goto __pyx_L6_unpacking_done;
@@ -1923,7 +1751,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
       __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
       __pyx_t_8 = NULL;
       if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
-      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __PYX_ERR(0, 75, __pyx_L1_error)
       __pyx_L6_unpacking_done:;
     }
     __Pyx_XDECREF_SET(__pyx_v_c, __pyx_t_5);
@@ -1931,26 +1759,12 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
     __Pyx_XDECREF_SET(__pyx_v_v, __pyx_t_6);
     __pyx_t_6 = 0;
 
-    /* "cutadapt/_align.pyx":75
- * 	t = bytearray(b'\0') * 256
- * 	for c, v in d.items():
- * 		t[ord(c)] = v             # <<<<<<<<<<<<<<
- * 		t[ord(c.lower())] = v
- * 	return bytes(t)
- */
-    __pyx_t_9 = __Pyx_PyInt_As_unsigned_char(__pyx_v_v); if (unlikely((__pyx_t_9 == (unsigned char)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_10 = __Pyx_PyObject_Ord(__pyx_v_c); if (unlikely(__pyx_t_10 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    if (unlikely(__Pyx_SetItemInt_ByteArray(__pyx_v_t, __pyx_t_10, __pyx_t_9, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_align.pyx":76
- * 	for c, v in d.items():
- * 		t[ord(c)] = v
- * 		t[ord(c.lower())] = v             # <<<<<<<<<<<<<<
- * 	return bytes(t)
- * 
- */
-    __pyx_t_9 = __Pyx_PyInt_As_unsigned_char(__pyx_v_v); if (unlikely((__pyx_t_9 == (unsigned char)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_c, __pyx_n_s_lower); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_9 = __Pyx_PyInt_As_unsigned_char(__pyx_v_v); if (unlikely((__pyx_t_9 == (unsigned char)-1) && PyErr_Occurred())) __PYX_ERR(0, 76, __pyx_L1_error)
+    __pyx_t_10 = __Pyx_PyObject_Ord(__pyx_v_c); if (unlikely(__pyx_t_10 == (long)(Py_UCS4)-1)) __PYX_ERR(0, 76, __pyx_L1_error)
+    if (unlikely(__Pyx_SetItemInt_ByteArray(__pyx_v_t, __pyx_t_10, __pyx_t_9, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) __PYX_ERR(0, 76, __pyx_L1_error)
+
+    __pyx_t_9 = __Pyx_PyInt_As_unsigned_char(__pyx_v_v); if (unlikely((__pyx_t_9 == (unsigned char)-1) && PyErr_Occurred())) __PYX_ERR(0, 77, __pyx_L1_error)
+    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_c, __pyx_n_s_lower); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 77, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
     __pyx_t_5 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_6))) {
@@ -1963,54 +1777,33 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
       }
     }
     if (__pyx_t_5) {
-      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_5); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 77, __pyx_L1_error)
       __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
     } else {
-      __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_6); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_6); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 77, __pyx_L1_error)
     }
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-    __pyx_t_10 = __Pyx_PyObject_Ord(__pyx_t_2); if (unlikely(__pyx_t_10 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_10 = __Pyx_PyObject_Ord(__pyx_t_2); if (unlikely(__pyx_t_10 == (long)(Py_UCS4)-1)) __PYX_ERR(0, 77, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    if (unlikely(__Pyx_SetItemInt_ByteArray(__pyx_v_t, __pyx_t_10, __pyx_t_9, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_align.pyx":74
- * 	)
- * 	t = bytearray(b'\0') * 256
- * 	for c, v in d.items():             # <<<<<<<<<<<<<<
- * 		t[ord(c)] = v
- * 		t[ord(c.lower())] = v
- */
+    if (unlikely(__Pyx_SetItemInt_ByteArray(__pyx_v_t, __pyx_t_10, __pyx_t_9, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) __PYX_ERR(0, 77, __pyx_L1_error)
+
   }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":77
- * 		t[ord(c)] = v
- * 		t[ord(c.lower())] = v
- * 	return bytes(t)             # <<<<<<<<<<<<<<
- * 
- * 
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 78, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(__pyx_v_t);
   __Pyx_GIVEREF(__pyx_v_t);
   PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_t);
-  __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)(&PyBytes_Type)), __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)(&PyBytes_Type)), __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 78, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __pyx_r = __pyx_t_2;
   __pyx_t_2 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_align.pyx":40
- * 
- * 
- * def _iupac_table():             # <<<<<<<<<<<<<<
- * 	"""
- * 	Return a translation table for IUPAC characters.
- */
 
   /* function exit code */
   __pyx_L1_error:;
@@ -2031,13 +1824,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":94
- * 	computed.
- * 	"""
- * 	def __init__(self, reference, query):             # <<<<<<<<<<<<<<
- * 		m = len(reference)
- * 		n = len(query)
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_1__init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
@@ -2046,9 +1832,6 @@ static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_1__init__(PyObject *__pyx_
   PyObject *__pyx_v_self = 0;
   PyObject *__pyx_v_reference = 0;
   PyObject *__pyx_v_query = 0;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
@@ -2073,16 +1856,16 @@ static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_1__init__(PyObject *__pyx_
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_reference)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); __PYX_ERR(0, 95, __pyx_L3_error)
         }
         case  2:
         if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_query)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); __PYX_ERR(0, 95, __pyx_L3_error)
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 95, __pyx_L3_error)
       }
     } else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
       goto __pyx_L5_argtuple_error;
@@ -2097,7 +1880,7 @@ static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_1__init__(PyObject *__pyx_
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 95, __pyx_L3_error)
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._align.DPMatrix.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
@@ -2122,63 +1905,39 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix___init__(CYTHON_UNUSED PyO
   PyObject *__pyx_t_4 = NULL;
   PyObject *(*__pyx_t_5)(PyObject *);
   PyObject *__pyx_t_6 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__init__", 0);
 
-  /* "cutadapt/_align.pyx":95
- * 	"""
- * 	def __init__(self, reference, query):
- * 		m = len(reference)             # <<<<<<<<<<<<<<
- * 		n = len(query)
- * 		self._rows = [ [None] * (n+1) for _ in range(m + 1) ]
- */
-  __pyx_t_1 = PyObject_Length(__pyx_v_reference); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_reference); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 96, __pyx_L1_error)
+  __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 96, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __pyx_v_m = __pyx_t_2;
   __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":96
- * 	def __init__(self, reference, query):
- * 		m = len(reference)
- * 		n = len(query)             # <<<<<<<<<<<<<<
- * 		self._rows = [ [None] * (n+1) for _ in range(m + 1) ]
- * 		self.reference = reference
- */
-  __pyx_t_1 = PyObject_Length(__pyx_v_query); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 96; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 96; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_query); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 97, __pyx_L1_error)
+  __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 97, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __pyx_v_n = __pyx_t_2;
   __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":97
- * 		m = len(reference)
- * 		n = len(query)
- * 		self._rows = [ [None] * (n+1) for _ in range(m + 1) ]             # <<<<<<<<<<<<<<
- * 		self.reference = reference
- * 		self.query = query
- */
-  __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 98, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = __Pyx_PyInt_AddObjC(__pyx_v_m, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyInt_AddObjC(__pyx_v_m, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 98, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 98, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
   __Pyx_GIVEREF(__pyx_t_3);
   PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3);
   __pyx_t_3 = 0;
-  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_range, __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_range, __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 98, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
   if (likely(PyList_CheckExact(__pyx_t_3)) || PyTuple_CheckExact(__pyx_t_3)) {
     __pyx_t_4 = __pyx_t_3; __Pyx_INCREF(__pyx_t_4); __pyx_t_1 = 0;
     __pyx_t_5 = NULL;
   } else {
-    __pyx_t_1 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 98, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_5 = Py_TYPE(__pyx_t_4)->tp_iternext; if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = Py_TYPE(__pyx_t_4)->tp_iternext; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 98, __pyx_L1_error)
   }
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   for (;;) {
@@ -2186,17 +1945,17 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix___init__(CYTHON_UNUSED PyO
       if (likely(PyList_CheckExact(__pyx_t_4))) {
         if (__pyx_t_1 >= PyList_GET_SIZE(__pyx_t_4)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_3 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_1); __Pyx_INCREF(__pyx_t_3); __pyx_t_1++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_3 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_1); __Pyx_INCREF(__pyx_t_3); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 98, __pyx_L1_error)
         #else
-        __pyx_t_3 = PySequence_ITEM(__pyx_t_4, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_3 = PySequence_ITEM(__pyx_t_4, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 98, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_3);
         #endif
       } else {
         if (__pyx_t_1 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_1); __Pyx_INCREF(__pyx_t_3); __pyx_t_1++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_1); __Pyx_INCREF(__pyx_t_3); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 98, __pyx_L1_error)
         #else
-        __pyx_t_3 = PySequence_ITEM(__pyx_t_4, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_3 = PySequence_ITEM(__pyx_t_4, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 98, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_3);
         #endif
       }
@@ -2206,7 +1965,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix___init__(CYTHON_UNUSED PyO
         PyObject* exc_type = PyErr_Occurred();
         if (exc_type) {
           if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else __PYX_ERR(0, 98, __pyx_L1_error)
         }
         break;
       }
@@ -2214,51 +1973,30 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix___init__(CYTHON_UNUSED PyO
     }
     __Pyx_XDECREF_SET(__pyx_v__, __pyx_t_3);
     __pyx_t_3 = 0;
-    __pyx_t_3 = __Pyx_PyInt_AddObjC(__pyx_v_n, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_PyInt_AddObjC(__pyx_v_n, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 98, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_6 = PyList_New(1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_6 = PyList_New(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 98, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
     __Pyx_INCREF(Py_None);
     __Pyx_GIVEREF(Py_None);
     PyList_SET_ITEM(__pyx_t_6, 0, Py_None);
-    { PyObject* __pyx_temp = PyNumber_InPlaceMultiply(__pyx_t_6, __pyx_t_3); if (unlikely(!__pyx_temp)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    { PyObject* __pyx_temp = PyNumber_InPlaceMultiply(__pyx_t_6, __pyx_t_3); if (unlikely(!__pyx_temp)) __PYX_ERR(0, 98, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_temp);
       __Pyx_DECREF(__pyx_t_6);
       __pyx_t_6 = __pyx_temp;
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_6))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_6))) __PYX_ERR(0, 98, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
   }
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_rows, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_rows, __pyx_t_2) < 0) __PYX_ERR(0, 98, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":98
- * 		n = len(query)
- * 		self._rows = [ [None] * (n+1) for _ in range(m + 1) ]
- * 		self.reference = reference             # <<<<<<<<<<<<<<
- * 		self.query = query
- * 
- */
-  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_reference, __pyx_v_reference) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":99
- * 		self._rows = [ [None] * (n+1) for _ in range(m + 1) ]
- * 		self.reference = reference
- * 		self.query = query             # <<<<<<<<<<<<<<
- * 
- * 	def set_entry(self, int i, int j, cost):
- */
-  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_query, __pyx_v_query) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":94
- * 	computed.
- * 	"""
- * 	def __init__(self, reference, query):             # <<<<<<<<<<<<<<
- * 		m = len(reference)
- * 		n = len(query)
- */
+  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_reference, __pyx_v_reference) < 0) __PYX_ERR(0, 99, __pyx_L1_error)
+
+  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_query, __pyx_v_query) < 0) __PYX_ERR(0, 100, __pyx_L1_error)
+
 
   /* function exit code */
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
@@ -2279,13 +2017,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix___init__(CYTHON_UNUSED PyO
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":101
- * 		self.query = query
- * 
- * 	def set_entry(self, int i, int j, cost):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Set an entry in the dynamic programming matrix.
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_3set_entry(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
@@ -2296,9 +2027,6 @@ static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_3set_entry(PyObject *__pyx
   int __pyx_v_i;
   int __pyx_v_j;
   PyObject *__pyx_v_cost = 0;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("set_entry (wrapper)", 0);
@@ -2324,21 +2052,21 @@ static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_3set_entry(PyObject *__pyx
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_i)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("set_entry", 1, 4, 4, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("set_entry", 1, 4, 4, 1); __PYX_ERR(0, 102, __pyx_L3_error)
         }
         case  2:
         if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_j)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("set_entry", 1, 4, 4, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("set_entry", 1, 4, 4, 2); __PYX_ERR(0, 102, __pyx_L3_error)
         }
         case  3:
         if (likely((values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_cost)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("set_entry", 1, 4, 4, 3); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("set_entry", 1, 4, 4, 3); __PYX_ERR(0, 102, __pyx_L3_error)
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "set_entry") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "set_entry") < 0)) __PYX_ERR(0, 102, __pyx_L3_error)
       }
     } else if (PyTuple_GET_SIZE(__pyx_args) != 4) {
       goto __pyx_L5_argtuple_error;
@@ -2349,13 +2077,13 @@ static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_3set_entry(PyObject *__pyx
       values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
     }
     __pyx_v_self = values[0];
-    __pyx_v_i = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_i == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-    __pyx_v_j = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_j == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_i = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_i == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 102, __pyx_L3_error)
+    __pyx_v_j = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_j == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 102, __pyx_L3_error)
     __pyx_v_cost = values[3];
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("set_entry", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("set_entry", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 102, __pyx_L3_error)
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._align.DPMatrix.set_entry", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
@@ -2373,33 +2101,16 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_2set_entry(CYTHON_UNUSED P
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
   PyObject *__pyx_t_2 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("set_entry", 0);
 
-  /* "cutadapt/_align.pyx":105
- * 		Set an entry in the dynamic programming matrix.
- * 		"""
- * 		self._rows[i][j] = cost             # <<<<<<<<<<<<<<
- * 
- * 	def __str__(self):
- */
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_rows); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_rows); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_1, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_2 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_1, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 106, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (unlikely(__Pyx_SetItemInt(__pyx_t_2, __pyx_v_j, __pyx_v_cost, int, 1, __Pyx_PyInt_From_int, 0, 1, 1) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(__Pyx_SetItemInt(__pyx_t_2, __pyx_v_j, __pyx_v_cost, int, 1, __Pyx_PyInt_From_int, 0, 1, 1) < 0)) __PYX_ERR(0, 106, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":101
- * 		self.query = query
- * 
- * 	def set_entry(self, int i, int j, cost):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Set an entry in the dynamic programming matrix.
- */
 
   /* function exit code */
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
@@ -2415,13 +2126,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_2set_entry(CYTHON_UNUSED P
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":107
- * 		self._rows[i][j] = cost
- * 
- * 	def __str__(self):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Return a representation of the matrix as a string.
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_5__str__(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/
@@ -2439,21 +2143,11 @@ static PyObject *__pyx_pw_8cutadapt_6_align_8DPMatrix_5__str__(PyObject *__pyx_s
 }
 static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_CoroutineObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
-/* "cutadapt/_align.pyx":111
- * 		Return a representation of the matrix as a string.
- * 		"""
- * 		rows = ['     ' + ' '.join(c.rjust(2) for c in self.query)]             # <<<<<<<<<<<<<<
- * 		for c, row in zip(' ' + self.reference, self._rows):
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)
- */
 
 static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___genexpr(PyObject *__pyx_self) {
   struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_1_genexpr *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("genexpr", 0);
   __pyx_cur_scope = (struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_1_genexpr *)__pyx_tp_new_8cutadapt_6_align___pyx_scope_struct_1_genexpr(__pyx_ptype_8cutadapt_6_align___pyx_scope_struct_1_genexpr, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
@@ -2465,7 +2159,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___genexpr(PyObject
   __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
   __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
   {
-    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_DPMatrix___str___locals_genexpr); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_DPMatrix___str___locals_genexpr); if (unlikely(!gen)) __PYX_ERR(0, 112, __pyx_L1_error)
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -2490,9 +2184,6 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
   Py_ssize_t __pyx_t_3;
   PyObject *(*__pyx_t_4)(PyObject *);
   PyObject *__pyx_t_5 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
@@ -2503,17 +2194,17 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self, __pyx_n_s_query); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 112, __pyx_L1_error)
+  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); __PYX_ERR(0, 112, __pyx_L1_error) }
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self, __pyx_n_s_query); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) {
     __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); __pyx_t_3 = 0;
     __pyx_t_4 = NULL;
   } else {
-    __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 112, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_4 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 112, __pyx_L1_error)
   }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   for (;;) {
@@ -2521,17 +2212,17 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
       if (likely(PyList_CheckExact(__pyx_t_2))) {
         if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_2)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 112, __pyx_L1_error)
         #else
-        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_1);
         #endif
       } else {
         if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 112, __pyx_L1_error)
         #else
-        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_1);
         #endif
       }
@@ -2541,7 +2232,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
         PyObject* exc_type = PyErr_Occurred();
         if (exc_type) {
           if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else __PYX_ERR(0, 112, __pyx_L1_error)
         }
         break;
       }
@@ -2551,9 +2242,9 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
     __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_c, __pyx_t_1);
     __Pyx_GIVEREF(__pyx_t_1);
     __pyx_t_1 = 0;
-    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_c, __pyx_n_s_rjust); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_c, __pyx_n_s_rjust); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 112, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_5);
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     __pyx_r = __pyx_t_5;
@@ -2573,7 +2264,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
     __Pyx_XGOTREF(__pyx_t_2);
     __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
     __pyx_t_4 = __pyx_cur_scope->__pyx_t_2;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 112, __pyx_L1_error)
   }
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
@@ -2594,21 +2285,11 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
 }
 static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx_CoroutineObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
-/* "cutadapt/_align.pyx":113
- * 		rows = ['     ' + ' '.join(c.rjust(2) for c in self.query)]
- * 		for c, row in zip(' ' + self.reference, self._rows):
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)             # <<<<<<<<<<<<<<
- * 			rows.append(r)
- * 		return '\n'.join(rows)
- */
 
 static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___3genexpr(PyObject *__pyx_self) {
   struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_2_genexpr *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("genexpr", 0);
   __pyx_cur_scope = (struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_2_genexpr *)__pyx_tp_new_8cutadapt_6_align___pyx_scope_struct_2_genexpr(__pyx_ptype_8cutadapt_6_align___pyx_scope_struct_2_genexpr, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
@@ -2620,7 +2301,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___3genexpr(PyObject
   __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
   __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
   {
-    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_DPMatrix___str___locals_genexpr); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1, (PyObject *) __pyx_cur_scope, __pyx_n_s_genexpr, __pyx_n_s_DPMatrix___str___locals_genexpr); if (unlikely(!gen)) __PYX_ERR(0, 114, __pyx_L1_error)
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -2649,9 +2330,6 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
   PyObject *__pyx_t_7 = NULL;
   PyObject *__pyx_t_8 = NULL;
   PyObject *__pyx_t_9 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
@@ -2662,32 +2340,32 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_row)) { __Pyx_RaiseClosureNameError("row"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
+  if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 114, __pyx_L1_error)
+  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_row)) { __Pyx_RaiseClosureNameError("row"); __PYX_ERR(0, 114, __pyx_L1_error) }
   if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_row)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_row)) {
     __pyx_t_1 = __pyx_cur_scope->__pyx_outer_scope->__pyx_v_row; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0;
     __pyx_t_3 = NULL;
   } else {
-    __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_row); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_row); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 114, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_3 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 114, __pyx_L1_error)
   }
   for (;;) {
     if (likely(!__pyx_t_3)) {
       if (likely(PyList_CheckExact(__pyx_t_1))) {
         if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_1)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(0, 114, __pyx_L1_error)
         #else
-        __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 114, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_4);
         #endif
       } else {
         if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(0, 114, __pyx_L1_error)
         #else
-        __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 114, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_4);
         #endif
       }
@@ -2697,7 +2375,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
         PyObject* exc_type = PyErr_Occurred();
         if (exc_type) {
           if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else __PYX_ERR(0, 114, __pyx_L1_error)
         }
         break;
       }
@@ -2712,7 +2390,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
       __Pyx_INCREF(__pyx_kp_s__5);
       __pyx_t_4 = __pyx_kp_s__5;
     } else {
-      __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_0_2d, __pyx_n_s_format); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_0_2d, __pyx_n_s_format); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 114, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_7);
       __pyx_t_8 = NULL;
       if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_7))) {
@@ -2725,16 +2403,16 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
         }
       }
       if (!__pyx_t_8) {
-        __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_cur_scope->__pyx_v_v); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_cur_scope->__pyx_v_v); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_6);
       } else {
-        __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 114, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_9);
         __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
         __Pyx_INCREF(__pyx_cur_scope->__pyx_v_v);
         __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_v);
         PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_cur_scope->__pyx_v_v);
-        __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_6);
         __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
       }
@@ -2759,7 +2437,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
     __Pyx_XGOTREF(__pyx_t_1);
     __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
     __pyx_t_3 = __pyx_cur_scope->__pyx_t_2;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 114, __pyx_L1_error)
   }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
@@ -2782,13 +2460,6 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":107
- * 		self._rows[i][j] = cost
- * 
- * 	def __str__(self):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Return a representation of the matrix as a string.
- */
 
 static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) {
   struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ *__pyx_cur_scope;
@@ -2806,9 +2477,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
   PyObject *__pyx_t_7 = NULL;
   PyObject *(*__pyx_t_8)(PyObject *);
   int __pyx_t_9;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__str__", 0);
   __pyx_cur_scope = (struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ *)__pyx_tp_new_8cutadapt_6_align___pyx_scope_struct____str__(__pyx_ptype_8cutadapt_6_align___pyx_scope_struct____str__, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
@@ -2820,22 +2488,15 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
   __Pyx_INCREF(__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_self);
 
-  /* "cutadapt/_align.pyx":111
- * 		Return a representation of the matrix as a string.
- * 		"""
- * 		rows = ['     ' + ' '.join(c.rjust(2) for c in self.query)]             # <<<<<<<<<<<<<<
- * 		for c, row in zip(' ' + self.reference, self._rows):
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)
- */
-  __pyx_t_1 = __pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_PyString_Join(__pyx_kp_s__7, __pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyString_Join(__pyx_kp_s__7, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 112, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __pyx_t_1 = PyNumber_Add(__pyx_kp_s__6, __pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyNumber_Add(__pyx_kp_s__6, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 112, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_GIVEREF(__pyx_t_1);
   PyList_SET_ITEM(__pyx_t_2, 0, __pyx_t_1);
@@ -2843,21 +2504,14 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
   __pyx_v_rows = ((PyObject*)__pyx_t_2);
   __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":112
- * 		"""
- * 		rows = ['     ' + ' '.join(c.rjust(2) for c in self.query)]
- * 		for c, row in zip(' ' + self.reference, self._rows):             # <<<<<<<<<<<<<<
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)
- * 			rows.append(r)
- */
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_reference); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_reference); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_1 = PyNumber_Add(__pyx_kp_s__7, __pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyNumber_Add(__pyx_kp_s__7, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 113, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_rows); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_rows); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 113, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_GIVEREF(__pyx_t_1);
   PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
@@ -2865,16 +2519,16 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
   PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2);
   __pyx_t_1 = 0;
   __pyx_t_2 = 0;
-  __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_zip, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_zip, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) {
     __pyx_t_3 = __pyx_t_2; __Pyx_INCREF(__pyx_t_3); __pyx_t_4 = 0;
     __pyx_t_5 = NULL;
   } else {
-    __pyx_t_4 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 113, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_5 = Py_TYPE(__pyx_t_3)->tp_iternext; if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = Py_TYPE(__pyx_t_3)->tp_iternext; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 113, __pyx_L1_error)
   }
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   for (;;) {
@@ -2882,17 +2536,17 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
       if (likely(PyList_CheckExact(__pyx_t_3))) {
         if (__pyx_t_4 >= PyList_GET_SIZE(__pyx_t_3)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) __PYX_ERR(0, 113, __pyx_L1_error)
         #else
-        __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_2);
         #endif
       } else {
         if (__pyx_t_4 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) __PYX_ERR(0, 113, __pyx_L1_error)
         #else
-        __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_2);
         #endif
       }
@@ -2902,7 +2556,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
         PyObject* exc_type = PyErr_Occurred();
         if (exc_type) {
           if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else __PYX_ERR(0, 113, __pyx_L1_error)
         }
         break;
       }
@@ -2918,7 +2572,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
       if (unlikely(size != 2)) {
         if (size > 2) __Pyx_RaiseTooManyValuesError(2);
         else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
-        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __PYX_ERR(0, 113, __pyx_L1_error)
       }
       #if CYTHON_COMPILING_IN_CPYTHON
       if (likely(PyTuple_CheckExact(sequence))) {
@@ -2931,15 +2585,15 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
       __Pyx_INCREF(__pyx_t_1);
       __Pyx_INCREF(__pyx_t_6);
       #else
-      __pyx_t_1 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_1 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 113, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_1);
-      __pyx_t_6 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_6 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 113, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_6);
       #endif
       __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     } else {
       Py_ssize_t index = -1;
-      __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 113, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_7);
       __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
       __pyx_t_8 = Py_TYPE(__pyx_t_7)->tp_iternext;
@@ -2947,7 +2601,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
       __Pyx_GOTREF(__pyx_t_1);
       index = 1; __pyx_t_6 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_6)) goto __pyx_L5_unpacking_failed;
       __Pyx_GOTREF(__pyx_t_6);
-      if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) __PYX_ERR(0, 113, __pyx_L1_error)
       __pyx_t_8 = NULL;
       __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
       goto __pyx_L6_unpacking_done;
@@ -2955,7 +2609,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
       __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
       __pyx_t_8 = NULL;
       if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
-      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __PYX_ERR(0, 113, __pyx_L1_error)
       __pyx_L6_unpacking_done:;
     }
     __Pyx_XDECREF_SET(__pyx_v_c, __pyx_t_1);
@@ -2965,67 +2619,32 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
     __Pyx_GIVEREF(__pyx_t_6);
     __pyx_t_6 = 0;
 
-    /* "cutadapt/_align.pyx":113
- * 		rows = ['     ' + ' '.join(c.rjust(2) for c in self.query)]
- * 		for c, row in zip(' ' + self.reference, self._rows):
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)             # <<<<<<<<<<<<<<
- * 			rows.append(r)
- * 		return '\n'.join(rows)
- */
-    __pyx_t_2 = PyNumber_Add(__pyx_v_c, __pyx_kp_s__7); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = PyNumber_Add(__pyx_v_c, __pyx_kp_s__7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 114, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_6 = __pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___3genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_6 = __pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___3genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
-    __pyx_t_1 = __Pyx_PyString_Join(__pyx_kp_s__7, __pyx_t_6); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyString_Join(__pyx_kp_s__7, __pyx_t_6); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 114, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-    __pyx_t_6 = PyNumber_Add(__pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_6 = PyNumber_Add(__pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     __Pyx_XDECREF_SET(__pyx_v_r, __pyx_t_6);
     __pyx_t_6 = 0;
 
-    /* "cutadapt/_align.pyx":114
- * 		for c, row in zip(' ' + self.reference, self._rows):
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)
- * 			rows.append(r)             # <<<<<<<<<<<<<<
- * 		return '\n'.join(rows)
- * 
- */
-    __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_rows, __pyx_v_r); if (unlikely(__pyx_t_9 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 114; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_align.pyx":112
- * 		"""
- * 		rows = ['     ' + ' '.join(c.rjust(2) for c in self.query)]
- * 		for c, row in zip(' ' + self.reference, self._rows):             # <<<<<<<<<<<<<<
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)
- * 			rows.append(r)
- */
+    __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_rows, __pyx_v_r); if (unlikely(__pyx_t_9 == -1)) __PYX_ERR(0, 115, __pyx_L1_error)
+
   }
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
-  /* "cutadapt/_align.pyx":115
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)
- * 			rows.append(r)
- * 		return '\n'.join(rows)             # <<<<<<<<<<<<<<
- * 
- * 
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_3 = __Pyx_PyString_Join(__pyx_kp_s__8, __pyx_v_rows); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyString_Join(__pyx_kp_s__8, __pyx_v_rows); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 116, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __pyx_r = __pyx_t_3;
   __pyx_t_3 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_align.pyx":107
- * 		self._rows[i][j] = cost
- * 
- * 	def __str__(self):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Return a representation of the matrix as a string.
- */
 
   /* function exit code */
   __pyx_L1_error:;
@@ -3046,13 +2665,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":194
- * 	cdef str str_reference
- * 
- * 	def __cinit__(self, str reference, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False):             # <<<<<<<<<<<<<<
- * 		self.max_error_rate = max_error_rate
- * 		self.flags = flags
- */
 
 /* Python wrapper */
 static int __pyx_pw_8cutadapt_6_align_7Aligner_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
@@ -3062,9 +2674,6 @@ static int __pyx_pw_8cutadapt_6_align_7Aligner_1__cinit__(PyObject *__pyx_v_self
   int __pyx_v_flags;
   int __pyx_v_wildcard_ref;
   int __pyx_v_wildcard_query;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   int __pyx_r;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
@@ -3091,7 +2700,7 @@ static int __pyx_pw_8cutadapt_6_align_7Aligner_1__cinit__(PyObject *__pyx_v_self
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_max_error_rate)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 2, 5, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 2, 5, 1); __PYX_ERR(0, 195, __pyx_L3_error)
         }
         case  2:
         if (kw_args > 0) {
@@ -3110,7 +2719,7 @@ static int __pyx_pw_8cutadapt_6_align_7Aligner_1__cinit__(PyObject *__pyx_v_self
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) __PYX_ERR(0, 195, __pyx_L3_error)
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -3124,32 +2733,32 @@ static int __pyx_pw_8cutadapt_6_align_7Aligner_1__cinit__(PyObject *__pyx_v_self
       }
     }
     __pyx_v_reference = ((PyObject*)values[0]);
-    __pyx_v_max_error_rate = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_max_error_rate == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_max_error_rate = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_max_error_rate == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
     if (values[2]) {
-      __pyx_v_flags = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_flags == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_flags = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_flags == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
     } else {
       __pyx_v_flags = ((int)15);
     }
     if (values[3]) {
-      __pyx_v_wildcard_ref = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_wildcard_ref == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_wildcard_ref = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_wildcard_ref == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
     } else {
       __pyx_v_wildcard_ref = ((int)0);
     }
     if (values[4]) {
-      __pyx_v_wildcard_query = __Pyx_PyObject_IsTrue(values[4]); if (unlikely((__pyx_v_wildcard_query == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_wildcard_query = __Pyx_PyObject_IsTrue(values[4]); if (unlikely((__pyx_v_wildcard_query == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 195, __pyx_L3_error)
     } else {
       __pyx_v_wildcard_query = ((int)0);
     }
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 2, 5, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 2, 5, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 195, __pyx_L3_error)
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._align.Aligner.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return -1;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_reference), (&PyString_Type), 1, "reference", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 194; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_reference), (&PyString_Type), 1, "reference", 1))) __PYX_ERR(0, 195, __pyx_L1_error)
   __pyx_r = __pyx_pf_8cutadapt_6_align_7Aligner___cinit__(((struct __pyx_obj_8cutadapt_6_align_Aligner *)__pyx_v_self), __pyx_v_reference, __pyx_v_max_error_rate, __pyx_v_flags, __pyx_v_wildcard_ref, __pyx_v_wildcard_query);
 
   /* function exit code */
@@ -3164,125 +2773,38 @@ static int __pyx_pw_8cutadapt_6_align_7Aligner_1__cinit__(PyObject *__pyx_v_self
 static int __pyx_pf_8cutadapt_6_align_7Aligner___cinit__(struct __pyx_obj_8cutadapt_6_align_Aligner *__pyx_v_self, PyObject *__pyx_v_reference, double __pyx_v_max_error_rate, int __pyx_v_flags, int __pyx_v_wildcard_ref, int __pyx_v_wildcard_query) {
   int __pyx_r;
   __Pyx_RefNannyDeclarations
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__cinit__", 0);
 
-  /* "cutadapt/_align.pyx":195
- * 
- * 	def __cinit__(self, str reference, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False):
- * 		self.max_error_rate = max_error_rate             # <<<<<<<<<<<<<<
- * 		self.flags = flags
- * 		self.wildcard_ref = wildcard_ref
- */
   __pyx_v_self->max_error_rate = __pyx_v_max_error_rate;
 
-  /* "cutadapt/_align.pyx":196
- * 	def __cinit__(self, str reference, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False):
- * 		self.max_error_rate = max_error_rate
- * 		self.flags = flags             # <<<<<<<<<<<<<<
- * 		self.wildcard_ref = wildcard_ref
- * 		self.wildcard_query = wildcard_query
- */
   __pyx_v_self->flags = __pyx_v_flags;
 
-  /* "cutadapt/_align.pyx":197
- * 		self.max_error_rate = max_error_rate
- * 		self.flags = flags
- * 		self.wildcard_ref = wildcard_ref             # <<<<<<<<<<<<<<
- * 		self.wildcard_query = wildcard_query
- * 		self.str_reference = reference
- */
   __pyx_v_self->wildcard_ref = __pyx_v_wildcard_ref;
 
-  /* "cutadapt/_align.pyx":198
- * 		self.flags = flags
- * 		self.wildcard_ref = wildcard_ref
- * 		self.wildcard_query = wildcard_query             # <<<<<<<<<<<<<<
- * 		self.str_reference = reference
- * 		self.reference = reference
- */
   __pyx_v_self->wildcard_query = __pyx_v_wildcard_query;
 
-  /* "cutadapt/_align.pyx":199
- * 		self.wildcard_ref = wildcard_ref
- * 		self.wildcard_query = wildcard_query
- * 		self.str_reference = reference             # <<<<<<<<<<<<<<
- * 		self.reference = reference
- * 		self._min_overlap = 1
- */
   __Pyx_INCREF(__pyx_v_reference);
   __Pyx_GIVEREF(__pyx_v_reference);
   __Pyx_GOTREF(__pyx_v_self->str_reference);
   __Pyx_DECREF(__pyx_v_self->str_reference);
   __pyx_v_self->str_reference = __pyx_v_reference;
 
-  /* "cutadapt/_align.pyx":200
- * 		self.wildcard_query = wildcard_query
- * 		self.str_reference = reference
- * 		self.reference = reference             # <<<<<<<<<<<<<<
- * 		self._min_overlap = 1
- * 		self.debug = False
- */
-  if (__Pyx_PyObject_SetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_reference, __pyx_v_reference) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 200; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":201
- * 		self.str_reference = reference
- * 		self.reference = reference
- * 		self._min_overlap = 1             # <<<<<<<<<<<<<<
- * 		self.debug = False
- * 		self._dpmatrix = None
- */
+  if (__Pyx_PyObject_SetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_reference, __pyx_v_reference) < 0) __PYX_ERR(0, 201, __pyx_L1_error)
+
   __pyx_v_self->_min_overlap = 1;
 
-  /* "cutadapt/_align.pyx":202
- * 		self.reference = reference
- * 		self._min_overlap = 1
- * 		self.debug = False             # <<<<<<<<<<<<<<
- * 		self._dpmatrix = None
- * 		self._insertion_cost = 1
- */
   __pyx_v_self->debug = 0;
 
-  /* "cutadapt/_align.pyx":203
- * 		self._min_overlap = 1
- * 		self.debug = False
- * 		self._dpmatrix = None             # <<<<<<<<<<<<<<
- * 		self._insertion_cost = 1
- * 		self._deletion_cost = 1
- */
   __Pyx_INCREF(Py_None);
   __Pyx_GIVEREF(Py_None);
   __Pyx_GOTREF(__pyx_v_self->_dpmatrix);
   __Pyx_DECREF(__pyx_v_self->_dpmatrix);
   __pyx_v_self->_dpmatrix = Py_None;
 
-  /* "cutadapt/_align.pyx":204
- * 		self.debug = False
- * 		self._dpmatrix = None
- * 		self._insertion_cost = 1             # <<<<<<<<<<<<<<
- * 		self._deletion_cost = 1
- * 
- */
   __pyx_v_self->_insertion_cost = 1;
 
-  /* "cutadapt/_align.pyx":205
- * 		self._dpmatrix = None
- * 		self._insertion_cost = 1
- * 		self._deletion_cost = 1             # <<<<<<<<<<<<<<
- * 
- * 	property min_overlap:
- */
   __pyx_v_self->_deletion_cost = 1;
 
-  /* "cutadapt/_align.pyx":194
- * 	cdef str str_reference
- * 
- * 	def __cinit__(self, str reference, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False):             # <<<<<<<<<<<<<<
- * 		self.max_error_rate = max_error_rate
- * 		self.flags = flags
- */
 
   /* function exit code */
   __pyx_r = 0;
@@ -3295,13 +2817,6 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner___cinit__(struct __pyx_obj_8cutad
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":208
- * 
- * 	property min_overlap:
- * 		def __get__(self):             # <<<<<<<<<<<<<<
- * 			return self._min_overlap
- * 
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_7Aligner_11min_overlap_1__get__(PyObject *__pyx_v_self); /*proto*/
@@ -3320,32 +2835,15 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_11min_overlap___get__(struc
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "cutadapt/_align.pyx":209
- * 	property min_overlap:
- * 		def __get__(self):
- * 			return self._min_overlap             # <<<<<<<<<<<<<<
- * 
- * 		def __set__(self, int value):
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_self->_min_overlap); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 209; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_self->_min_overlap); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 210, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_align.pyx":208
- * 
- * 	property min_overlap:
- * 		def __get__(self):             # <<<<<<<<<<<<<<
- * 			return self._min_overlap
- * 
- */
 
   /* function exit code */
   __pyx_L1_error:;
@@ -3358,26 +2856,16 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_11min_overlap___get__(struc
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":211
- * 			return self._min_overlap
- * 
- * 		def __set__(self, int value):             # <<<<<<<<<<<<<<
- * 			if value < 1:
- * 				raise ValueError('Minimum overlap must be at least 1')
- */
 
 /* Python wrapper */
 static int __pyx_pw_8cutadapt_6_align_7Aligner_11min_overlap_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_arg_value); /*proto*/
 static int __pyx_pw_8cutadapt_6_align_7Aligner_11min_overlap_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_arg_value) {
   int __pyx_v_value;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   int __pyx_r;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
   assert(__pyx_arg_value); {
-    __pyx_v_value = __Pyx_PyInt_As_int(__pyx_arg_value); if (unlikely((__pyx_v_value == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 211; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_value = __Pyx_PyInt_As_int(__pyx_arg_value); if (unlikely((__pyx_v_value == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 212, __pyx_L3_error)
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -3397,59 +2885,21 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_11min_overlap_2__set__(struct __p
   __Pyx_RefNannyDeclarations
   int __pyx_t_1;
   PyObject *__pyx_t_2 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__set__", 0);
 
-  /* "cutadapt/_align.pyx":212
- * 
- * 		def __set__(self, int value):
- * 			if value < 1:             # <<<<<<<<<<<<<<
- * 				raise ValueError('Minimum overlap must be at least 1')
- * 			self._min_overlap = value
- */
   __pyx_t_1 = ((__pyx_v_value < 1) != 0);
   if (__pyx_t_1) {
 
-    /* "cutadapt/_align.pyx":213
- * 		def __set__(self, int value):
- * 			if value < 1:
- * 				raise ValueError('Minimum overlap must be at least 1')             # <<<<<<<<<<<<<<
- * 			self._min_overlap = value
- * 
- */
-    __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 213; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 214, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 213; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_align.pyx":212
- * 
- * 		def __set__(self, int value):
- * 			if value < 1:             # <<<<<<<<<<<<<<
- * 				raise ValueError('Minimum overlap must be at least 1')
- * 			self._min_overlap = value
- */
+    __PYX_ERR(0, 214, __pyx_L1_error)
+
   }
 
-  /* "cutadapt/_align.pyx":214
- * 			if value < 1:
- * 				raise ValueError('Minimum overlap must be at least 1')
- * 			self._min_overlap = value             # <<<<<<<<<<<<<<
- * 
- * 	property indel_cost:
- */
   __pyx_v_self->_min_overlap = __pyx_v_value;
 
-  /* "cutadapt/_align.pyx":211
- * 			return self._min_overlap
- * 
- * 		def __set__(self, int value):             # <<<<<<<<<<<<<<
- * 			if value < 1:
- * 				raise ValueError('Minimum overlap must be at least 1')
- */
 
   /* function exit code */
   __pyx_r = 0;
@@ -3463,13 +2913,6 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_11min_overlap_2__set__(struct __p
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":221
- * 		changed.
- * 		"""
- * 		def __set__(self, value):             # <<<<<<<<<<<<<<
- * 			if value < 1:
- * 				raise ValueError('Insertion/deletion cost must be at leat 1')
- */
 
 /* Python wrapper */
 static int __pyx_pw_8cutadapt_6_align_7Aligner_10indel_cost_1__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
@@ -3490,72 +2933,27 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_10indel_cost___set__(struct __pyx
   PyObject *__pyx_t_1 = NULL;
   int __pyx_t_2;
   int __pyx_t_3;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__set__", 0);
 
-  /* "cutadapt/_align.pyx":222
- * 		"""
- * 		def __set__(self, value):
- * 			if value < 1:             # <<<<<<<<<<<<<<
- * 				raise ValueError('Insertion/deletion cost must be at leat 1')
- * 			self._insertion_cost = value
- */
-  __pyx_t_1 = PyObject_RichCompare(__pyx_v_value, __pyx_int_1, Py_LT); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_RichCompare(__pyx_v_value, __pyx_int_1, Py_LT); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 223, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 223, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   if (__pyx_t_2) {
 
-    /* "cutadapt/_align.pyx":223
- * 		def __set__(self, value):
- * 			if value < 1:
- * 				raise ValueError('Insertion/deletion cost must be at leat 1')             # <<<<<<<<<<<<<<
- * 			self._insertion_cost = value
- * 			self._deletion_cost = value
- */
-    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 224, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_Raise(__pyx_t_1, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_align.pyx":222
- * 		"""
- * 		def __set__(self, value):
- * 			if value < 1:             # <<<<<<<<<<<<<<
- * 				raise ValueError('Insertion/deletion cost must be at leat 1')
- * 			self._insertion_cost = value
- */
+    __PYX_ERR(0, 224, __pyx_L1_error)
+
   }
 
-  /* "cutadapt/_align.pyx":224
- * 			if value < 1:
- * 				raise ValueError('Insertion/deletion cost must be at leat 1')
- * 			self._insertion_cost = value             # <<<<<<<<<<<<<<
- * 			self._deletion_cost = value
- * 
- */
-  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_v_value); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_v_value); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 225, __pyx_L1_error)
   __pyx_v_self->_insertion_cost = __pyx_t_3;
 
-  /* "cutadapt/_align.pyx":225
- * 				raise ValueError('Insertion/deletion cost must be at leat 1')
- * 			self._insertion_cost = value
- * 			self._deletion_cost = value             # <<<<<<<<<<<<<<
- * 
- * 	property reference:
- */
-  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_v_value); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 225; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_v_value); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 226, __pyx_L1_error)
   __pyx_v_self->_deletion_cost = __pyx_t_3;
 
-  /* "cutadapt/_align.pyx":221
- * 		changed.
- * 		"""
- * 		def __set__(self, value):             # <<<<<<<<<<<<<<
- * 			if value < 1:
- * 				raise ValueError('Insertion/deletion cost must be at leat 1')
- */
 
   /* function exit code */
   __pyx_r = 0;
@@ -3569,13 +2967,6 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_10indel_cost___set__(struct __pyx
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":228
- * 
- * 	property reference:
- * 		def __get__(self):             # <<<<<<<<<<<<<<
- * 			return self._reference
- * 
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_7Aligner_9reference_1__get__(PyObject *__pyx_v_self); /*proto*/
@@ -3595,25 +2986,11 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_9reference___get__(struct _
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "cutadapt/_align.pyx":229
- * 	property reference:
- * 		def __get__(self):
- * 			return self._reference             # <<<<<<<<<<<<<<
- * 
- * 		def __set__(self, str reference):
- */
   __Pyx_XDECREF(__pyx_r);
   __Pyx_INCREF(__pyx_v_self->_reference);
   __pyx_r = __pyx_v_self->_reference;
   goto __pyx_L0;
 
-  /* "cutadapt/_align.pyx":228
- * 
- * 	property reference:
- * 		def __get__(self):             # <<<<<<<<<<<<<<
- * 			return self._reference
- * 
- */
 
   /* function exit code */
   __pyx_L0:;
@@ -3622,24 +2999,14 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_9reference___get__(struct _
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":231
- * 			return self._reference
- * 
- * 		def __set__(self, str reference):             # <<<<<<<<<<<<<<
- * 			mem = <_Entry*> PyMem_Realloc(self.column, (len(reference) + 1) * sizeof(_Entry))
- * 			if not mem:
- */
 
 /* Python wrapper */
 static int __pyx_pw_8cutadapt_6_align_7Aligner_9reference_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_reference); /*proto*/
 static int __pyx_pw_8cutadapt_6_align_7Aligner_9reference_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_reference) {
-  CYTHON_UNUSED int __pyx_lineno = 0;
-  CYTHON_UNUSED const char *__pyx_filename = NULL;
-  CYTHON_UNUSED int __pyx_clineno = 0;
   int __pyx_r;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_reference), (&PyString_Type), 1, "reference", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 231; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_reference), (&PyString_Type), 1, "reference", 1))) __PYX_ERR(0, 232, __pyx_L1_error)
   __pyx_r = __pyx_pf_8cutadapt_6_align_7Aligner_9reference_2__set__(((struct __pyx_obj_8cutadapt_6_align_Aligner *)__pyx_v_self), ((PyObject*)__pyx_v_reference));
 
   /* function exit code */
@@ -3661,105 +3028,39 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_9reference_2__set__(struct __pyx_
   PyObject *__pyx_t_4 = NULL;
   PyObject *__pyx_t_5 = NULL;
   PyObject *__pyx_t_6 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__set__", 0);
 
-  /* "cutadapt/_align.pyx":232
- * 
- * 		def __set__(self, str reference):
- * 			mem = <_Entry*> PyMem_Realloc(self.column, (len(reference) + 1) * sizeof(_Entry))             # <<<<<<<<<<<<<<
- * 			if not mem:
- * 				raise MemoryError()
- */
-  __pyx_t_1 = PyObject_Length(__pyx_v_reference); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_reference); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 233, __pyx_L1_error)
   __pyx_v_mem = ((__pyx_t_8cutadapt_6_align__Entry *)PyMem_Realloc(__pyx_v_self->column, ((__pyx_t_1 + 1) * (sizeof(__pyx_t_8cutadapt_6_align__Entry)))));
 
-  /* "cutadapt/_align.pyx":233
- * 		def __set__(self, str reference):
- * 			mem = <_Entry*> PyMem_Realloc(self.column, (len(reference) + 1) * sizeof(_Entry))
- * 			if not mem:             # <<<<<<<<<<<<<<
- * 				raise MemoryError()
- * 			self.column = mem
- */
   __pyx_t_2 = ((!(__pyx_v_mem != 0)) != 0);
   if (__pyx_t_2) {
 
-    /* "cutadapt/_align.pyx":234
- * 			mem = <_Entry*> PyMem_Realloc(self.column, (len(reference) + 1) * sizeof(_Entry))
- * 			if not mem:
- * 				raise MemoryError()             # <<<<<<<<<<<<<<
- * 			self.column = mem
- * 			self._reference = reference.encode('ascii')
- */
-    PyErr_NoMemory(); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_align.pyx":233
- * 		def __set__(self, str reference):
- * 			mem = <_Entry*> PyMem_Realloc(self.column, (len(reference) + 1) * sizeof(_Entry))
- * 			if not mem:             # <<<<<<<<<<<<<<
- * 				raise MemoryError()
- * 			self.column = mem
- */
+    PyErr_NoMemory(); __PYX_ERR(0, 235, __pyx_L1_error)
+
   }
 
-  /* "cutadapt/_align.pyx":235
- * 			if not mem:
- * 				raise MemoryError()
- * 			self.column = mem             # <<<<<<<<<<<<<<
- * 			self._reference = reference.encode('ascii')
- * 			self.m = len(reference)
- */
   __pyx_v_self->column = __pyx_v_mem;
 
-  /* "cutadapt/_align.pyx":236
- * 				raise MemoryError()
- * 			self.column = mem
- * 			self._reference = reference.encode('ascii')             # <<<<<<<<<<<<<<
- * 			self.m = len(reference)
- * 			if self.wildcard_ref:
- */
-  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_reference, __pyx_n_s_encode); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_reference, __pyx_n_s_encode); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 237, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__11, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__11, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 237, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  if (!(likely(PyBytes_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_4)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyBytes_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_4)->tp_name), 0))) __PYX_ERR(0, 237, __pyx_L1_error)
   __Pyx_GIVEREF(__pyx_t_4);
   __Pyx_GOTREF(__pyx_v_self->_reference);
   __Pyx_DECREF(__pyx_v_self->_reference);
   __pyx_v_self->_reference = ((PyObject*)__pyx_t_4);
   __pyx_t_4 = 0;
 
-  /* "cutadapt/_align.pyx":237
- * 			self.column = mem
- * 			self._reference = reference.encode('ascii')
- * 			self.m = len(reference)             # <<<<<<<<<<<<<<
- * 			if self.wildcard_ref:
- * 				self._reference = self._reference.translate(IUPAC_TABLE)
- */
-  __pyx_t_1 = PyObject_Length(__pyx_v_reference); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_reference); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 238, __pyx_L1_error)
   __pyx_v_self->m = __pyx_t_1;
 
-  /* "cutadapt/_align.pyx":238
- * 			self._reference = reference.encode('ascii')
- * 			self.m = len(reference)
- * 			if self.wildcard_ref:             # <<<<<<<<<<<<<<
- * 				self._reference = self._reference.translate(IUPAC_TABLE)
- * 			elif self.wildcard_query:
- */
   __pyx_t_2 = (__pyx_v_self->wildcard_ref != 0);
   if (__pyx_t_2) {
 
-    /* "cutadapt/_align.pyx":239
- * 			self.m = len(reference)
- * 			if self.wildcard_ref:
- * 				self._reference = self._reference.translate(IUPAC_TABLE)             # <<<<<<<<<<<<<<
- * 			elif self.wildcard_query:
- * 				self._reference = self._reference.translate(ACGT_TABLE)
- */
-    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_reference, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_reference, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 240, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_5 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
@@ -3772,55 +3073,34 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_9reference_2__set__(struct __pyx_
       }
     }
     if (!__pyx_t_5) {
-      __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 240, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_4);
     } else {
-      __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 240, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_6);
       __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __pyx_t_5 = NULL;
       __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
       __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
       PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 240, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_4);
       __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    if (!(likely(PyBytes_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_4)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(PyBytes_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_4)->tp_name), 0))) __PYX_ERR(0, 240, __pyx_L1_error)
     __Pyx_GIVEREF(__pyx_t_4);
     __Pyx_GOTREF(__pyx_v_self->_reference);
     __Pyx_DECREF(__pyx_v_self->_reference);
     __pyx_v_self->_reference = ((PyObject*)__pyx_t_4);
     __pyx_t_4 = 0;
 
-    /* "cutadapt/_align.pyx":238
- * 			self._reference = reference.encode('ascii')
- * 			self.m = len(reference)
- * 			if self.wildcard_ref:             # <<<<<<<<<<<<<<
- * 				self._reference = self._reference.translate(IUPAC_TABLE)
- * 			elif self.wildcard_query:
- */
     goto __pyx_L4;
   }
 
-  /* "cutadapt/_align.pyx":240
- * 			if self.wildcard_ref:
- * 				self._reference = self._reference.translate(IUPAC_TABLE)
- * 			elif self.wildcard_query:             # <<<<<<<<<<<<<<
- * 				self._reference = self._reference.translate(ACGT_TABLE)
- * 			self.str_reference = reference
- */
   __pyx_t_2 = (__pyx_v_self->wildcard_query != 0);
   if (__pyx_t_2) {
 
-    /* "cutadapt/_align.pyx":241
- * 				self._reference = self._reference.translate(IUPAC_TABLE)
- * 			elif self.wildcard_query:
- * 				self._reference = self._reference.translate(ACGT_TABLE)             # <<<<<<<<<<<<<<
- * 			self.str_reference = reference
- * 
- */
-    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_reference, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_reference, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 242, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_6 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
@@ -3833,57 +3113,36 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_9reference_2__set__(struct __pyx_
       }
     }
     if (!__pyx_t_6) {
-      __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_4);
     } else {
-      __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 242, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_5);
       __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_6); __pyx_t_6 = NULL;
       __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
       __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
       PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_4);
       __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    if (!(likely(PyBytes_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_4)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(PyBytes_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_4)->tp_name), 0))) __PYX_ERR(0, 242, __pyx_L1_error)
     __Pyx_GIVEREF(__pyx_t_4);
     __Pyx_GOTREF(__pyx_v_self->_reference);
     __Pyx_DECREF(__pyx_v_self->_reference);
     __pyx_v_self->_reference = ((PyObject*)__pyx_t_4);
     __pyx_t_4 = 0;
 
-    /* "cutadapt/_align.pyx":240
- * 			if self.wildcard_ref:
- * 				self._reference = self._reference.translate(IUPAC_TABLE)
- * 			elif self.wildcard_query:             # <<<<<<<<<<<<<<
- * 				self._reference = self._reference.translate(ACGT_TABLE)
- * 			self.str_reference = reference
- */
   }
   __pyx_L4:;
 
-  /* "cutadapt/_align.pyx":242
- * 			elif self.wildcard_query:
- * 				self._reference = self._reference.translate(ACGT_TABLE)
- * 			self.str_reference = reference             # <<<<<<<<<<<<<<
- * 
- * 	property dpmatrix:
- */
   __Pyx_INCREF(__pyx_v_reference);
   __Pyx_GIVEREF(__pyx_v_reference);
   __Pyx_GOTREF(__pyx_v_self->str_reference);
   __Pyx_DECREF(__pyx_v_self->str_reference);
   __pyx_v_self->str_reference = __pyx_v_reference;
 
-  /* "cutadapt/_align.pyx":231
- * 			return self._reference
- * 
- * 		def __set__(self, str reference):             # <<<<<<<<<<<<<<
- * 			mem = <_Entry*> PyMem_Realloc(self.column, (len(reference) + 1) * sizeof(_Entry))
- * 			if not mem:
- */
 
   /* function exit code */
   __pyx_r = 0;
@@ -3900,13 +3159,6 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_9reference_2__set__(struct __pyx_
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":249
- * 		usually None, unless debugging has been enabled with enable_debug().
- * 		"""
- * 		def __get__(self):             # <<<<<<<<<<<<<<
- * 			return self._dpmatrix
- * 
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_7Aligner_8dpmatrix_1__get__(PyObject *__pyx_v_self); /*proto*/
@@ -3926,25 +3178,11 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_8dpmatrix___get__(struct __
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "cutadapt/_align.pyx":250
- * 		"""
- * 		def __get__(self):
- * 			return self._dpmatrix             # <<<<<<<<<<<<<<
- * 
- * 	def enable_debug(self):
- */
   __Pyx_XDECREF(__pyx_r);
   __Pyx_INCREF(__pyx_v_self->_dpmatrix);
   __pyx_r = __pyx_v_self->_dpmatrix;
   goto __pyx_L0;
 
-  /* "cutadapt/_align.pyx":249
- * 		usually None, unless debugging has been enabled with enable_debug().
- * 		"""
- * 		def __get__(self):             # <<<<<<<<<<<<<<
- * 			return self._dpmatrix
- * 
- */
 
   /* function exit code */
   __pyx_L0:;
@@ -3953,13 +3191,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_8dpmatrix___get__(struct __
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":252
- * 			return self._dpmatrix
- * 
- * 	def enable_debug(self):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Store the dynamic programming matrix while running the locate() method
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_7Aligner_3enable_debug(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
@@ -3980,22 +3211,8 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_2enable_debug(struct __pyx_
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("enable_debug", 0);
 
-  /* "cutadapt/_align.pyx":257
- * 		and make it available in the .dpmatrix attribute.
- * 		"""
- * 		self.debug = True             # <<<<<<<<<<<<<<
- * 
- * 	def locate(self, str query):
- */
   __pyx_v_self->debug = 1;
 
-  /* "cutadapt/_align.pyx":252
- * 			return self._dpmatrix
- * 
- * 	def enable_debug(self):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Store the dynamic programming matrix while running the locate() method
- */
 
   /* function exit code */
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
@@ -4004,25 +3221,15 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_2enable_debug(struct __pyx_
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":259
- * 		self.debug = True
- * 
- * 	def locate(self, str query):             # <<<<<<<<<<<<<<
- * 		"""
- * 		locate(query) -> (refstart, refstop, querystart, querystop, matches, errors)
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_7Aligner_5locate(PyObject *__pyx_v_self, PyObject *__pyx_v_query); /*proto*/
 static char __pyx_doc_8cutadapt_6_align_7Aligner_4locate[] = "\n\t\tlocate(query) -> (refstart, refstop, querystart, querystop, matches, errors)\n\n\t\tFind the query within the reference associated with this aligner. The\n\t\tintervals (querystart, querystop) and (refstart, refstop) give the\n\t\tlocation of the match.\n\n\t\tThat is, the substrings query[querystart:querystop] and\n\t\tself.reference[refstart:refstop] were found to align best to each other,\n\t\twith the given number of [...]
 static PyObject *__pyx_pw_8cutadapt_6_align_7Aligner_5locate(PyObject *__pyx_v_self, PyObject *__pyx_v_query) {
-  CYTHON_UNUSED int __pyx_lineno = 0;
-  CYTHON_UNUSED const char *__pyx_filename = NULL;
-  CYTHON_UNUSED int __pyx_clineno = 0;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("locate (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_query), (&PyString_Type), 1, "query", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 259; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_query), (&PyString_Type), 1, "query", 1))) __PYX_ERR(0, 260, __pyx_L1_error)
   __pyx_r = __pyx_pf_8cutadapt_6_align_7Aligner_4locate(((struct __pyx_obj_8cutadapt_6_align_Aligner *)__pyx_v_self), ((PyObject*)__pyx_v_query));
 
   /* function exit code */
@@ -4088,141 +3295,47 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
   PyObject *__pyx_t_18 = NULL;
   PyObject *__pyx_t_19 = NULL;
   PyObject *__pyx_t_20 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("locate", 0);
 
-  /* "cutadapt/_align.pyx":273
- * 		The alignment itself is not returned.
- * 		"""
- * 		cdef char* s1 = self._reference             # <<<<<<<<<<<<<<
- * 		cdef bytes query_bytes = query.encode('ascii')
- * 		cdef char* s2 = query_bytes
- */
-  __pyx_t_1 = __Pyx_PyObject_AsString(__pyx_v_self->_reference); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 273; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_AsString(__pyx_v_self->_reference); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) __PYX_ERR(0, 274, __pyx_L1_error)
   __pyx_v_s1 = __pyx_t_1;
 
-  /* "cutadapt/_align.pyx":274
- * 		"""
- * 		cdef char* s1 = self._reference
- * 		cdef bytes query_bytes = query.encode('ascii')             # <<<<<<<<<<<<<<
- * 		cdef char* s2 = query_bytes
- * 		cdef int m = self.m
- */
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query, __pyx_n_s_encode); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 274; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query, __pyx_n_s_encode); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 275, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__12, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 274; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__12, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 275, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 274; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(0, 275, __pyx_L1_error)
   __pyx_v_query_bytes = ((PyObject*)__pyx_t_3);
   __pyx_t_3 = 0;
 
-  /* "cutadapt/_align.pyx":275
- * 		cdef char* s1 = self._reference
- * 		cdef bytes query_bytes = query.encode('ascii')
- * 		cdef char* s2 = query_bytes             # <<<<<<<<<<<<<<
- * 		cdef int m = self.m
- * 		cdef int n = len(query)
- */
-  __pyx_t_1 = __Pyx_PyObject_AsString(__pyx_v_query_bytes); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 275; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_AsString(__pyx_v_query_bytes); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) __PYX_ERR(0, 276, __pyx_L1_error)
   __pyx_v_s2 = __pyx_t_1;
 
-  /* "cutadapt/_align.pyx":276
- * 		cdef bytes query_bytes = query.encode('ascii')
- * 		cdef char* s2 = query_bytes
- * 		cdef int m = self.m             # <<<<<<<<<<<<<<
- * 		cdef int n = len(query)
- * 		cdef _Entry* column = self.column
- */
   __pyx_t_4 = __pyx_v_self->m;
   __pyx_v_m = __pyx_t_4;
 
-  /* "cutadapt/_align.pyx":277
- * 		cdef char* s2 = query_bytes
- * 		cdef int m = self.m
- * 		cdef int n = len(query)             # <<<<<<<<<<<<<<
- * 		cdef _Entry* column = self.column
- * 		cdef double max_error_rate = self.max_error_rate
- */
-  __pyx_t_5 = PyObject_Length(__pyx_v_query); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 277; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_5 = PyObject_Length(__pyx_v_query); if (unlikely(__pyx_t_5 == -1)) __PYX_ERR(0, 278, __pyx_L1_error)
   __pyx_v_n = __pyx_t_5;
 
-  /* "cutadapt/_align.pyx":278
- * 		cdef int m = self.m
- * 		cdef int n = len(query)
- * 		cdef _Entry* column = self.column             # <<<<<<<<<<<<<<
- * 		cdef double max_error_rate = self.max_error_rate
- * 		cdef bint start_in_ref = self.flags & START_WITHIN_SEQ1
- */
   __pyx_t_6 = __pyx_v_self->column;
   __pyx_v_column = __pyx_t_6;
 
-  /* "cutadapt/_align.pyx":279
- * 		cdef int n = len(query)
- * 		cdef _Entry* column = self.column
- * 		cdef double max_error_rate = self.max_error_rate             # <<<<<<<<<<<<<<
- * 		cdef bint start_in_ref = self.flags & START_WITHIN_SEQ1
- * 		cdef bint start_in_query = self.flags & START_WITHIN_SEQ2
- */
   __pyx_t_7 = __pyx_v_self->max_error_rate;
   __pyx_v_max_error_rate = __pyx_t_7;
 
-  /* "cutadapt/_align.pyx":280
- * 		cdef _Entry* column = self.column
- * 		cdef double max_error_rate = self.max_error_rate
- * 		cdef bint start_in_ref = self.flags & START_WITHIN_SEQ1             # <<<<<<<<<<<<<<
- * 		cdef bint start_in_query = self.flags & START_WITHIN_SEQ2
- * 		cdef bint stop_in_ref = self.flags & STOP_WITHIN_SEQ1
- */
   __pyx_v_start_in_ref = (__pyx_v_self->flags & 1);
 
-  /* "cutadapt/_align.pyx":281
- * 		cdef double max_error_rate = self.max_error_rate
- * 		cdef bint start_in_ref = self.flags & START_WITHIN_SEQ1
- * 		cdef bint start_in_query = self.flags & START_WITHIN_SEQ2             # <<<<<<<<<<<<<<
- * 		cdef bint stop_in_ref = self.flags & STOP_WITHIN_SEQ1
- * 		cdef bint stop_in_query = self.flags & STOP_WITHIN_SEQ2
- */
   __pyx_v_start_in_query = (__pyx_v_self->flags & 2);
 
-  /* "cutadapt/_align.pyx":282
- * 		cdef bint start_in_ref = self.flags & START_WITHIN_SEQ1
- * 		cdef bint start_in_query = self.flags & START_WITHIN_SEQ2
- * 		cdef bint stop_in_ref = self.flags & STOP_WITHIN_SEQ1             # <<<<<<<<<<<<<<
- * 		cdef bint stop_in_query = self.flags & STOP_WITHIN_SEQ2
- * 
- */
   __pyx_v_stop_in_ref = (__pyx_v_self->flags & 4);
 
-  /* "cutadapt/_align.pyx":283
- * 		cdef bint start_in_query = self.flags & START_WITHIN_SEQ2
- * 		cdef bint stop_in_ref = self.flags & STOP_WITHIN_SEQ1
- * 		cdef bint stop_in_query = self.flags & STOP_WITHIN_SEQ2             # <<<<<<<<<<<<<<
- * 
- * 		if self.wildcard_query:
- */
   __pyx_v_stop_in_query = (__pyx_v_self->flags & 8);
 
-  /* "cutadapt/_align.pyx":285
- * 		cdef bint stop_in_query = self.flags & STOP_WITHIN_SEQ2
- * 
- * 		if self.wildcard_query:             # <<<<<<<<<<<<<<
- * 			query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 			s2 = query_bytes
- */
   __pyx_t_8 = (__pyx_v_self->wildcard_query != 0);
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":286
- * 
- * 		if self.wildcard_query:
- * 			query_bytes = query_bytes.translate(IUPAC_TABLE)             # <<<<<<<<<<<<<<
- * 			s2 = query_bytes
- * 		elif self.wildcard_ref:
- */
-    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 287, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_9 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
@@ -4235,62 +3348,34 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       }
     }
     if (!__pyx_t_9) {
-      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 287, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_3);
     } else {
-      __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 287, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_10);
       __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL;
       __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
       __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
       PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 287, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_3);
       __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
     }
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(0, 287, __pyx_L1_error)
     __Pyx_DECREF_SET(__pyx_v_query_bytes, ((PyObject*)__pyx_t_3));
     __pyx_t_3 = 0;
 
-    /* "cutadapt/_align.pyx":287
- * 		if self.wildcard_query:
- * 			query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 			s2 = query_bytes             # <<<<<<<<<<<<<<
- * 		elif self.wildcard_ref:
- * 			query_bytes = query_bytes.translate(ACGT_TABLE)
- */
-    __pyx_t_1 = __Pyx_PyObject_AsString(__pyx_v_query_bytes); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 287; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyObject_AsString(__pyx_v_query_bytes); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) __PYX_ERR(0, 288, __pyx_L1_error)
     __pyx_v_s2 = __pyx_t_1;
 
-    /* "cutadapt/_align.pyx":285
- * 		cdef bint stop_in_query = self.flags & STOP_WITHIN_SEQ2
- * 
- * 		if self.wildcard_query:             # <<<<<<<<<<<<<<
- * 			query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 			s2 = query_bytes
- */
     goto __pyx_L3;
   }
 
-  /* "cutadapt/_align.pyx":288
- * 			query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 			s2 = query_bytes
- * 		elif self.wildcard_ref:             # <<<<<<<<<<<<<<
- * 			query_bytes = query_bytes.translate(ACGT_TABLE)
- * 			s2 = query_bytes
- */
   __pyx_t_8 = (__pyx_v_self->wildcard_ref != 0);
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":289
- * 			s2 = query_bytes
- * 		elif self.wildcard_ref:
- * 			query_bytes = query_bytes.translate(ACGT_TABLE)             # <<<<<<<<<<<<<<
- * 			s2 = query_bytes
- * 		cdef bint compare_ascii = not (self.wildcard_query or self.wildcard_ref)
- */
-    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 289; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 290, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_10 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
@@ -4303,51 +3388,30 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       }
     }
     if (!__pyx_t_10) {
-      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 289; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 290, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_3);
     } else {
-      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 289; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 290, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_9);
       __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_10); __pyx_t_10 = NULL;
       __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
       __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
       PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 289; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 290, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_3);
       __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
     }
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 289; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(0, 290, __pyx_L1_error)
     __Pyx_DECREF_SET(__pyx_v_query_bytes, ((PyObject*)__pyx_t_3));
     __pyx_t_3 = 0;
 
-    /* "cutadapt/_align.pyx":290
- * 		elif self.wildcard_ref:
- * 			query_bytes = query_bytes.translate(ACGT_TABLE)
- * 			s2 = query_bytes             # <<<<<<<<<<<<<<
- * 		cdef bint compare_ascii = not (self.wildcard_query or self.wildcard_ref)
- * 		"""
- */
-    __pyx_t_1 = __Pyx_PyObject_AsString(__pyx_v_query_bytes); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 290; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyObject_AsString(__pyx_v_query_bytes); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) __PYX_ERR(0, 291, __pyx_L1_error)
     __pyx_v_s2 = __pyx_t_1;
 
-    /* "cutadapt/_align.pyx":288
- * 			query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 			s2 = query_bytes
- * 		elif self.wildcard_ref:             # <<<<<<<<<<<<<<
- * 			query_bytes = query_bytes.translate(ACGT_TABLE)
- * 			s2 = query_bytes
- */
   }
   __pyx_L3:;
 
-  /* "cutadapt/_align.pyx":291
- * 			query_bytes = query_bytes.translate(ACGT_TABLE)
- * 			s2 = query_bytes
- * 		cdef bint compare_ascii = not (self.wildcard_query or self.wildcard_ref)             # <<<<<<<<<<<<<<
- * 		"""
- * 		DP Matrix:
- */
   __pyx_t_11 = (__pyx_v_self->wildcard_query != 0);
   if (!__pyx_t_11) {
   } else {
@@ -4359,50 +3423,15 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
   __pyx_L4_bool_binop_done:;
   __pyx_v_compare_ascii = (!__pyx_t_8);
 
-  /* "cutadapt/_align.pyx":305
- * 
- * 		# maximum no. of errors
- * 		cdef int k = <int> (max_error_rate * m)             # <<<<<<<<<<<<<<
- * 
- * 		# Determine largest and smallest column we need to compute
- */
   __pyx_v_k = ((int)(__pyx_v_max_error_rate * __pyx_v_m));
 
-  /* "cutadapt/_align.pyx":308
- * 
- * 		# Determine largest and smallest column we need to compute
- * 		cdef int max_n = n             # <<<<<<<<<<<<<<
- * 		cdef int min_n = 0
- * 		if not start_in_query:
- */
   __pyx_v_max_n = __pyx_v_n;
 
-  /* "cutadapt/_align.pyx":309
- * 		# Determine largest and smallest column we need to compute
- * 		cdef int max_n = n
- * 		cdef int min_n = 0             # <<<<<<<<<<<<<<
- * 		if not start_in_query:
- * 			# costs can only get worse after column m
- */
   __pyx_v_min_n = 0;
 
-  /* "cutadapt/_align.pyx":310
- * 		cdef int max_n = n
- * 		cdef int min_n = 0
- * 		if not start_in_query:             # <<<<<<<<<<<<<<
- * 			# costs can only get worse after column m
- * 			max_n = min(n, m + k)
- */
   __pyx_t_8 = ((!(__pyx_v_start_in_query != 0)) != 0);
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":312
- * 		if not start_in_query:
- * 			# costs can only get worse after column m
- * 			max_n = min(n, m + k)             # <<<<<<<<<<<<<<
- * 		if not stop_in_query:
- * 			min_n = max(0, n - m - k)
- */
     __pyx_t_4 = (__pyx_v_m + __pyx_v_k);
     __pyx_t_12 = __pyx_v_n;
     if (((__pyx_t_4 < __pyx_t_12) != 0)) {
@@ -4412,32 +3441,11 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
     }
     __pyx_v_max_n = __pyx_t_13;
 
-    /* "cutadapt/_align.pyx":310
- * 		cdef int max_n = n
- * 		cdef int min_n = 0
- * 		if not start_in_query:             # <<<<<<<<<<<<<<
- * 			# costs can only get worse after column m
- * 			max_n = min(n, m + k)
- */
   }
 
-  /* "cutadapt/_align.pyx":313
- * 			# costs can only get worse after column m
- * 			max_n = min(n, m + k)
- * 		if not stop_in_query:             # <<<<<<<<<<<<<<
- * 			min_n = max(0, n - m - k)
- * 
- */
   __pyx_t_8 = ((!(__pyx_v_stop_in_query != 0)) != 0);
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":314
- * 			max_n = min(n, m + k)
- * 		if not stop_in_query:
- * 			min_n = max(0, n - m - k)             # <<<<<<<<<<<<<<
- * 
- * 		# Fill column min_n.
- */
     __pyx_t_13 = ((__pyx_v_n - __pyx_v_m) - __pyx_v_k);
     __pyx_t_14 = 0;
     if (((__pyx_t_13 > __pyx_t_14) != 0)) {
@@ -4447,22 +3455,8 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
     }
     __pyx_v_min_n = __pyx_t_15;
 
-    /* "cutadapt/_align.pyx":313
- * 			# costs can only get worse after column m
- * 			max_n = min(n, m + k)
- * 		if not stop_in_query:             # <<<<<<<<<<<<<<
- * 			min_n = max(0, n - m - k)
- * 
- */
   }
 
-  /* "cutadapt/_align.pyx":326
- * 		# TODO (later)
- * 		# fill out columns only until 'last'
- * 		if not start_in_ref and not start_in_query:             # <<<<<<<<<<<<<<
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- */
   __pyx_t_11 = ((!(__pyx_v_start_in_ref != 0)) != 0);
   if (__pyx_t_11) {
   } else {
@@ -4474,33 +3468,12 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
   __pyx_L9_bool_binop_done:;
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":327
- * 		# fill out columns only until 'last'
- * 		if not start_in_ref and not start_in_query:
- * 			for i in range(m + 1):             # <<<<<<<<<<<<<<
- * 				column[i].matches = 0
- * 				column[i].cost = max(i, min_n) * self._insertion_cost
- */
     __pyx_t_15 = (__pyx_v_m + 1);
     for (__pyx_t_13 = 0; __pyx_t_13 < __pyx_t_15; __pyx_t_13+=1) {
       __pyx_v_i = __pyx_t_13;
 
-      /* "cutadapt/_align.pyx":328
- * 		if not start_in_ref and not start_in_query:
- * 			for i in range(m + 1):
- * 				column[i].matches = 0             # <<<<<<<<<<<<<<
- * 				column[i].cost = max(i, min_n) * self._insertion_cost
- * 				column[i].origin = 0
- */
       (__pyx_v_column[__pyx_v_i]).matches = 0;
 
-      /* "cutadapt/_align.pyx":329
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- * 				column[i].cost = max(i, min_n) * self._insertion_cost             # <<<<<<<<<<<<<<
- * 				column[i].origin = 0
- * 		elif start_in_ref and not start_in_query:
- */
       __pyx_t_4 = __pyx_v_min_n;
       __pyx_t_12 = __pyx_v_i;
       if (((__pyx_t_4 > __pyx_t_12) != 0)) {
@@ -4510,33 +3483,12 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       }
       (__pyx_v_column[__pyx_v_i]).cost = (__pyx_t_16 * __pyx_v_self->_insertion_cost);
 
-      /* "cutadapt/_align.pyx":330
- * 				column[i].matches = 0
- * 				column[i].cost = max(i, min_n) * self._insertion_cost
- * 				column[i].origin = 0             # <<<<<<<<<<<<<<
- * 		elif start_in_ref and not start_in_query:
- * 			for i in range(m + 1):
- */
       (__pyx_v_column[__pyx_v_i]).origin = 0;
     }
 
-    /* "cutadapt/_align.pyx":326
- * 		# TODO (later)
- * 		# fill out columns only until 'last'
- * 		if not start_in_ref and not start_in_query:             # <<<<<<<<<<<<<<
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- */
     goto __pyx_L8;
   }
 
-  /* "cutadapt/_align.pyx":331
- * 				column[i].cost = max(i, min_n) * self._insertion_cost
- * 				column[i].origin = 0
- * 		elif start_in_ref and not start_in_query:             # <<<<<<<<<<<<<<
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- */
   __pyx_t_11 = (__pyx_v_start_in_ref != 0);
   if (__pyx_t_11) {
   } else {
@@ -4548,42 +3500,14 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
   __pyx_L13_bool_binop_done:;
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":332
- * 				column[i].origin = 0
- * 		elif start_in_ref and not start_in_query:
- * 			for i in range(m + 1):             # <<<<<<<<<<<<<<
- * 				column[i].matches = 0
- * 				column[i].cost = min_n * self._insertion_cost
- */
     __pyx_t_15 = (__pyx_v_m + 1);
     for (__pyx_t_13 = 0; __pyx_t_13 < __pyx_t_15; __pyx_t_13+=1) {
       __pyx_v_i = __pyx_t_13;
 
-      /* "cutadapt/_align.pyx":333
- * 		elif start_in_ref and not start_in_query:
- * 			for i in range(m + 1):
- * 				column[i].matches = 0             # <<<<<<<<<<<<<<
- * 				column[i].cost = min_n * self._insertion_cost
- * 				column[i].origin = min(0, min_n - i)
- */
       (__pyx_v_column[__pyx_v_i]).matches = 0;
 
-      /* "cutadapt/_align.pyx":334
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- * 				column[i].cost = min_n * self._insertion_cost             # <<<<<<<<<<<<<<
- * 				column[i].origin = min(0, min_n - i)
- * 		elif not start_in_ref and start_in_query:
- */
       (__pyx_v_column[__pyx_v_i]).cost = (__pyx_v_min_n * __pyx_v_self->_insertion_cost);
 
-      /* "cutadapt/_align.pyx":335
- * 				column[i].matches = 0
- * 				column[i].cost = min_n * self._insertion_cost
- * 				column[i].origin = min(0, min_n - i)             # <<<<<<<<<<<<<<
- * 		elif not start_in_ref and start_in_query:
- * 			for i in range(m + 1):
- */
       __pyx_t_16 = (__pyx_v_min_n - __pyx_v_i);
       __pyx_t_14 = 0;
       if (((__pyx_t_16 < __pyx_t_14) != 0)) {
@@ -4594,23 +3518,9 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       (__pyx_v_column[__pyx_v_i]).origin = __pyx_t_17;
     }
 
-    /* "cutadapt/_align.pyx":331
- * 				column[i].cost = max(i, min_n) * self._insertion_cost
- * 				column[i].origin = 0
- * 		elif start_in_ref and not start_in_query:             # <<<<<<<<<<<<<<
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- */
     goto __pyx_L8;
   }
 
-  /* "cutadapt/_align.pyx":336
- * 				column[i].cost = min_n * self._insertion_cost
- * 				column[i].origin = min(0, min_n - i)
- * 		elif not start_in_ref and start_in_query:             # <<<<<<<<<<<<<<
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- */
   __pyx_t_11 = ((!(__pyx_v_start_in_ref != 0)) != 0);
   if (__pyx_t_11) {
   } else {
@@ -4622,42 +3532,14 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
   __pyx_L17_bool_binop_done:;
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":337
- * 				column[i].origin = min(0, min_n - i)
- * 		elif not start_in_ref and start_in_query:
- * 			for i in range(m + 1):             # <<<<<<<<<<<<<<
- * 				column[i].matches = 0
- * 				column[i].cost = i * self._insertion_cost
- */
     __pyx_t_15 = (__pyx_v_m + 1);
     for (__pyx_t_13 = 0; __pyx_t_13 < __pyx_t_15; __pyx_t_13+=1) {
       __pyx_v_i = __pyx_t_13;
 
-      /* "cutadapt/_align.pyx":338
- * 		elif not start_in_ref and start_in_query:
- * 			for i in range(m + 1):
- * 				column[i].matches = 0             # <<<<<<<<<<<<<<
- * 				column[i].cost = i * self._insertion_cost
- * 				column[i].origin = max(0, min_n - i)
- */
       (__pyx_v_column[__pyx_v_i]).matches = 0;
 
-      /* "cutadapt/_align.pyx":339
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- * 				column[i].cost = i * self._insertion_cost             # <<<<<<<<<<<<<<
- * 				column[i].origin = max(0, min_n - i)
- * 		else:
- */
       (__pyx_v_column[__pyx_v_i]).cost = (__pyx_v_i * __pyx_v_self->_insertion_cost);
 
-      /* "cutadapt/_align.pyx":340
- * 				column[i].matches = 0
- * 				column[i].cost = i * self._insertion_cost
- * 				column[i].origin = max(0, min_n - i)             # <<<<<<<<<<<<<<
- * 		else:
- * 			for i in range(m + 1):
- */
       __pyx_t_16 = (__pyx_v_min_n - __pyx_v_i);
       __pyx_t_17 = 0;
       if (((__pyx_t_16 > __pyx_t_17) != 0)) {
@@ -4668,44 +3550,16 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       (__pyx_v_column[__pyx_v_i]).origin = __pyx_t_14;
     }
 
-    /* "cutadapt/_align.pyx":336
- * 				column[i].cost = min_n * self._insertion_cost
- * 				column[i].origin = min(0, min_n - i)
- * 		elif not start_in_ref and start_in_query:             # <<<<<<<<<<<<<<
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- */
     goto __pyx_L8;
   }
 
-  /* "cutadapt/_align.pyx":342
- * 				column[i].origin = max(0, min_n - i)
- * 		else:
- * 			for i in range(m + 1):             # <<<<<<<<<<<<<<
- * 				column[i].matches = 0
- * 				column[i].cost = min(i, min_n) * self._insertion_cost
- */
   /*else*/ {
     __pyx_t_15 = (__pyx_v_m + 1);
     for (__pyx_t_13 = 0; __pyx_t_13 < __pyx_t_15; __pyx_t_13+=1) {
       __pyx_v_i = __pyx_t_13;
 
-      /* "cutadapt/_align.pyx":343
- * 		else:
- * 			for i in range(m + 1):
- * 				column[i].matches = 0             # <<<<<<<<<<<<<<
- * 				column[i].cost = min(i, min_n) * self._insertion_cost
- * 				column[i].origin = min_n - i
- */
       (__pyx_v_column[__pyx_v_i]).matches = 0;
 
-      /* "cutadapt/_align.pyx":344
- * 			for i in range(m + 1):
- * 				column[i].matches = 0
- * 				column[i].cost = min(i, min_n) * self._insertion_cost             # <<<<<<<<<<<<<<
- * 				column[i].origin = min_n - i
- * 
- */
       __pyx_t_16 = __pyx_v_min_n;
       __pyx_t_4 = __pyx_v_i;
       if (((__pyx_t_16 < __pyx_t_4) != 0)) {
@@ -4715,36 +3569,15 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       }
       (__pyx_v_column[__pyx_v_i]).cost = (__pyx_t_12 * __pyx_v_self->_insertion_cost);
 
-      /* "cutadapt/_align.pyx":345
- * 				column[i].matches = 0
- * 				column[i].cost = min(i, min_n) * self._insertion_cost
- * 				column[i].origin = min_n - i             # <<<<<<<<<<<<<<
- * 
- * 		if self.debug:
- */
       (__pyx_v_column[__pyx_v_i]).origin = (__pyx_v_min_n - __pyx_v_i);
     }
   }
   __pyx_L8:;
 
-  /* "cutadapt/_align.pyx":347
- * 				column[i].origin = min_n - i
- * 
- * 		if self.debug:             # <<<<<<<<<<<<<<
- * 			self._dpmatrix = DPMatrix(self.str_reference, query)
- * 			for i in range(m + 1):
- */
   __pyx_t_8 = (__pyx_v_self->debug != 0);
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":348
- * 
- * 		if self.debug:
- * 			self._dpmatrix = DPMatrix(self.str_reference, query)             # <<<<<<<<<<<<<<
- * 			for i in range(m + 1):
- * 				self._dpmatrix.set_entry(i, min_n, column[i].cost)
- */
-    __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_DPMatrix); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 348; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_DPMatrix); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 349, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_9 = NULL;
     __pyx_t_5 = 0;
@@ -4758,7 +3591,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
         __pyx_t_5 = 1;
       }
     }
-    __pyx_t_10 = PyTuple_New(2+__pyx_t_5); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 348; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_10 = PyTuple_New(2+__pyx_t_5); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 349, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_10);
     if (__pyx_t_9) {
       __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL;
@@ -4769,7 +3602,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
     __Pyx_INCREF(__pyx_v_query);
     __Pyx_GIVEREF(__pyx_v_query);
     PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_5, __pyx_v_query);
-    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 348; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 349, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -4779,31 +3612,17 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
     __pyx_v_self->_dpmatrix = __pyx_t_3;
     __pyx_t_3 = 0;
 
-    /* "cutadapt/_align.pyx":349
- * 		if self.debug:
- * 			self._dpmatrix = DPMatrix(self.str_reference, query)
- * 			for i in range(m + 1):             # <<<<<<<<<<<<<<
- * 				self._dpmatrix.set_entry(i, min_n, column[i].cost)
- * 		cdef _Match best
- */
     __pyx_t_15 = (__pyx_v_m + 1);
     for (__pyx_t_13 = 0; __pyx_t_13 < __pyx_t_15; __pyx_t_13+=1) {
       __pyx_v_i = __pyx_t_13;
 
-      /* "cutadapt/_align.pyx":350
- * 			self._dpmatrix = DPMatrix(self.str_reference, query)
- * 			for i in range(m + 1):
- * 				self._dpmatrix.set_entry(i, min_n, column[i].cost)             # <<<<<<<<<<<<<<
- * 		cdef _Match best
- * 		best.ref_stop = m
- */
-      __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_dpmatrix, __pyx_n_s_set_entry); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 350; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_dpmatrix, __pyx_n_s_set_entry); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 351, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
-      __pyx_t_10 = __Pyx_PyInt_From_int(__pyx_v_i); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 350; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_10 = __Pyx_PyInt_From_int(__pyx_v_i); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 351, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_10);
-      __pyx_t_9 = __Pyx_PyInt_From_int(__pyx_v_min_n); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 350; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_9 = __Pyx_PyInt_From_int(__pyx_v_min_n); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 351, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_9);
-      __pyx_t_18 = __Pyx_PyInt_From_int((__pyx_v_column[__pyx_v_i]).cost); if (unlikely(!__pyx_t_18)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 350; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_18 = __Pyx_PyInt_From_int((__pyx_v_column[__pyx_v_i]).cost); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 351, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_18);
       __pyx_t_19 = NULL;
       __pyx_t_5 = 0;
@@ -4817,7 +3636,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
           __pyx_t_5 = 1;
         }
       }
-      __pyx_t_20 = PyTuple_New(3+__pyx_t_5); if (unlikely(!__pyx_t_20)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 350; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_20 = PyTuple_New(3+__pyx_t_5); if (unlikely(!__pyx_t_20)) __PYX_ERR(0, 351, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_20);
       if (__pyx_t_19) {
         __Pyx_GIVEREF(__pyx_t_19); PyTuple_SET_ITEM(__pyx_t_20, 0, __pyx_t_19); __pyx_t_19 = NULL;
@@ -4831,74 +3650,25 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       __pyx_t_10 = 0;
       __pyx_t_9 = 0;
       __pyx_t_18 = 0;
-      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_20, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 350; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_20, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 351, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_3);
       __Pyx_DECREF(__pyx_t_20); __pyx_t_20 = 0;
       __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
       __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     }
 
-    /* "cutadapt/_align.pyx":347
- * 				column[i].origin = min_n - i
- * 
- * 		if self.debug:             # <<<<<<<<<<<<<<
- * 			self._dpmatrix = DPMatrix(self.str_reference, query)
- * 			for i in range(m + 1):
- */
   }
 
-  /* "cutadapt/_align.pyx":352
- * 				self._dpmatrix.set_entry(i, min_n, column[i].cost)
- * 		cdef _Match best
- * 		best.ref_stop = m             # <<<<<<<<<<<<<<
- * 		best.query_stop = n
- * 		best.cost = m + n
- */
   __pyx_v_best.ref_stop = __pyx_v_m;
 
-  /* "cutadapt/_align.pyx":353
- * 		cdef _Match best
- * 		best.ref_stop = m
- * 		best.query_stop = n             # <<<<<<<<<<<<<<
- * 		best.cost = m + n
- * 		best.origin = 0
- */
   __pyx_v_best.query_stop = __pyx_v_n;
 
-  /* "cutadapt/_align.pyx":354
- * 		best.ref_stop = m
- * 		best.query_stop = n
- * 		best.cost = m + n             # <<<<<<<<<<<<<<
- * 		best.origin = 0
- * 		best.matches = 0
- */
   __pyx_v_best.cost = (__pyx_v_m + __pyx_v_n);
 
-  /* "cutadapt/_align.pyx":355
- * 		best.query_stop = n
- * 		best.cost = m + n
- * 		best.origin = 0             # <<<<<<<<<<<<<<
- * 		best.matches = 0
- * 
- */
   __pyx_v_best.origin = 0;
 
-  /* "cutadapt/_align.pyx":356
- * 		best.cost = m + n
- * 		best.origin = 0
- * 		best.matches = 0             # <<<<<<<<<<<<<<
- * 
- * 		# Ukkonen's trick: index of the last cell that is less than k.
- */
   __pyx_v_best.matches = 0;
 
-  /* "cutadapt/_align.pyx":359
- * 
- * 		# Ukkonen's trick: index of the last cell that is less than k.
- * 		cdef int last = min(m, k + 1)             # <<<<<<<<<<<<<<
- * 		if start_in_ref:
- * 			last = m
- */
   __pyx_t_15 = (__pyx_v_k + 1);
   __pyx_t_13 = __pyx_v_m;
   if (((__pyx_t_15 < __pyx_t_13) != 0)) {
@@ -4908,41 +3678,13 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
   }
   __pyx_v_last = __pyx_t_14;
 
-  /* "cutadapt/_align.pyx":360
- * 		# Ukkonen's trick: index of the last cell that is less than k.
- * 		cdef int last = min(m, k + 1)
- * 		if start_in_ref:             # <<<<<<<<<<<<<<
- * 			last = m
- * 
- */
   __pyx_t_8 = (__pyx_v_start_in_ref != 0);
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":361
- * 		cdef int last = min(m, k + 1)
- * 		if start_in_ref:
- * 			last = m             # <<<<<<<<<<<<<<
- * 
- * 		cdef int cost_diag
- */
     __pyx_v_last = __pyx_v_m;
 
-    /* "cutadapt/_align.pyx":360
- * 		# Ukkonen's trick: index of the last cell that is less than k.
- * 		cdef int last = min(m, k + 1)
- * 		if start_in_ref:             # <<<<<<<<<<<<<<
- * 			last = m
- * 
- */
   }
 
-  /* "cutadapt/_align.pyx":371
- * 		cdef _Entry tmp_entry
- * 
- * 		with nogil:             # <<<<<<<<<<<<<<
- * 			# iterate over columns
- * 			for j in range(min_n + 1, max_n + 1):
- */
   {
       #ifdef WITH_THREAD
       PyThreadState *_save;
@@ -4950,203 +3692,63 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       #endif
       /*try:*/ {
 
-        /* "cutadapt/_align.pyx":373
- * 		with nogil:
- * 			# iterate over columns
- * 			for j in range(min_n + 1, max_n + 1):             # <<<<<<<<<<<<<<
- * 				# remember first entry
- * 				tmp_entry = column[0]
- */
         __pyx_t_14 = (__pyx_v_max_n + 1);
         for (__pyx_t_13 = (__pyx_v_min_n + 1); __pyx_t_13 < __pyx_t_14; __pyx_t_13+=1) {
           __pyx_v_j = __pyx_t_13;
 
-          /* "cutadapt/_align.pyx":375
- * 			for j in range(min_n + 1, max_n + 1):
- * 				# remember first entry
- * 				tmp_entry = column[0]             # <<<<<<<<<<<<<<
- * 
- * 				# fill in first entry in this column
- */
           __pyx_v_tmp_entry = (__pyx_v_column[0]);
 
-          /* "cutadapt/_align.pyx":378
- * 
- * 				# fill in first entry in this column
- * 				if start_in_query:             # <<<<<<<<<<<<<<
- * 					column[0].origin = j
- * 				else:
- */
           __pyx_t_8 = (__pyx_v_start_in_query != 0);
           if (__pyx_t_8) {
 
-            /* "cutadapt/_align.pyx":379
- * 				# fill in first entry in this column
- * 				if start_in_query:
- * 					column[0].origin = j             # <<<<<<<<<<<<<<
- * 				else:
- * 					column[0].cost = j * self._insertion_cost
- */
             (__pyx_v_column[0]).origin = __pyx_v_j;
 
-            /* "cutadapt/_align.pyx":378
- * 
- * 				# fill in first entry in this column
- * 				if start_in_query:             # <<<<<<<<<<<<<<
- * 					column[0].origin = j
- * 				else:
- */
             goto __pyx_L32;
           }
 
-          /* "cutadapt/_align.pyx":381
- * 					column[0].origin = j
- * 				else:
- * 					column[0].cost = j * self._insertion_cost             # <<<<<<<<<<<<<<
- * 				for i in range(1, last + 1):
- * 					if compare_ascii:
- */
           /*else*/ {
             (__pyx_v_column[0]).cost = (__pyx_v_j * __pyx_v_self->_insertion_cost);
           }
           __pyx_L32:;
 
-          /* "cutadapt/_align.pyx":382
- * 				else:
- * 					column[0].cost = j * self._insertion_cost
- * 				for i in range(1, last + 1):             # <<<<<<<<<<<<<<
- * 					if compare_ascii:
- * 						characters_equal = (s1[i-1] == s2[j-1])
- */
           __pyx_t_15 = (__pyx_v_last + 1);
           for (__pyx_t_12 = 1; __pyx_t_12 < __pyx_t_15; __pyx_t_12+=1) {
             __pyx_v_i = __pyx_t_12;
 
-            /* "cutadapt/_align.pyx":383
- * 					column[0].cost = j * self._insertion_cost
- * 				for i in range(1, last + 1):
- * 					if compare_ascii:             # <<<<<<<<<<<<<<
- * 						characters_equal = (s1[i-1] == s2[j-1])
- * 					else:
- */
             __pyx_t_8 = (__pyx_v_compare_ascii != 0);
             if (__pyx_t_8) {
 
-              /* "cutadapt/_align.pyx":384
- * 				for i in range(1, last + 1):
- * 					if compare_ascii:
- * 						characters_equal = (s1[i-1] == s2[j-1])             # <<<<<<<<<<<<<<
- * 					else:
- * 						characters_equal = (s1[i-1] & s2[j-1]) != 0
- */
               __pyx_v_characters_equal = ((__pyx_v_s1[(__pyx_v_i - 1)]) == (__pyx_v_s2[(__pyx_v_j - 1)]));
 
-              /* "cutadapt/_align.pyx":383
- * 					column[0].cost = j * self._insertion_cost
- * 				for i in range(1, last + 1):
- * 					if compare_ascii:             # <<<<<<<<<<<<<<
- * 						characters_equal = (s1[i-1] == s2[j-1])
- * 					else:
- */
               goto __pyx_L35;
             }
 
-            /* "cutadapt/_align.pyx":386
- * 						characters_equal = (s1[i-1] == s2[j-1])
- * 					else:
- * 						characters_equal = (s1[i-1] & s2[j-1]) != 0             # <<<<<<<<<<<<<<
- * 					if characters_equal:
- * 						# Characters match: This cannot be an indel.
- */
             /*else*/ {
               __pyx_v_characters_equal = (((__pyx_v_s1[(__pyx_v_i - 1)]) & (__pyx_v_s2[(__pyx_v_j - 1)])) != 0);
             }
             __pyx_L35:;
 
-            /* "cutadapt/_align.pyx":387
- * 					else:
- * 						characters_equal = (s1[i-1] & s2[j-1]) != 0
- * 					if characters_equal:             # <<<<<<<<<<<<<<
- * 						# Characters match: This cannot be an indel.
- * 						cost = tmp_entry.cost
- */
             __pyx_t_8 = (__pyx_v_characters_equal != 0);
             if (__pyx_t_8) {
 
-              /* "cutadapt/_align.pyx":389
- * 					if characters_equal:
- * 						# Characters match: This cannot be an indel.
- * 						cost = tmp_entry.cost             # <<<<<<<<<<<<<<
- * 						origin = tmp_entry.origin
- * 						matches = tmp_entry.matches + 1
- */
               __pyx_t_16 = __pyx_v_tmp_entry.cost;
               __pyx_v_cost = __pyx_t_16;
 
-              /* "cutadapt/_align.pyx":390
- * 						# Characters match: This cannot be an indel.
- * 						cost = tmp_entry.cost
- * 						origin = tmp_entry.origin             # <<<<<<<<<<<<<<
- * 						matches = tmp_entry.matches + 1
- * 					else:
- */
               __pyx_t_16 = __pyx_v_tmp_entry.origin;
               __pyx_v_origin = __pyx_t_16;
 
-              /* "cutadapt/_align.pyx":391
- * 						cost = tmp_entry.cost
- * 						origin = tmp_entry.origin
- * 						matches = tmp_entry.matches + 1             # <<<<<<<<<<<<<<
- * 					else:
- * 						# Characters do not match.
- */
               __pyx_v_matches = (__pyx_v_tmp_entry.matches + 1);
 
-              /* "cutadapt/_align.pyx":387
- * 					else:
- * 						characters_equal = (s1[i-1] & s2[j-1]) != 0
- * 					if characters_equal:             # <<<<<<<<<<<<<<
- * 						# Characters match: This cannot be an indel.
- * 						cost = tmp_entry.cost
- */
               goto __pyx_L36;
             }
 
-            /* "cutadapt/_align.pyx":394
- * 					else:
- * 						# Characters do not match.
- * 						cost_diag = tmp_entry.cost + 1             # <<<<<<<<<<<<<<
- * 						cost_deletion = column[i].cost + self._deletion_cost
- * 						cost_insertion = column[i-1].cost + self._insertion_cost
- */
             /*else*/ {
               __pyx_v_cost_diag = (__pyx_v_tmp_entry.cost + 1);
 
-              /* "cutadapt/_align.pyx":395
- * 						# Characters do not match.
- * 						cost_diag = tmp_entry.cost + 1
- * 						cost_deletion = column[i].cost + self._deletion_cost             # <<<<<<<<<<<<<<
- * 						cost_insertion = column[i-1].cost + self._insertion_cost
- * 
- */
               __pyx_v_cost_deletion = ((__pyx_v_column[__pyx_v_i]).cost + __pyx_v_self->_deletion_cost);
 
-              /* "cutadapt/_align.pyx":396
- * 						cost_diag = tmp_entry.cost + 1
- * 						cost_deletion = column[i].cost + self._deletion_cost
- * 						cost_insertion = column[i-1].cost + self._insertion_cost             # <<<<<<<<<<<<<<
- * 
- * 						if cost_diag <= cost_deletion and cost_diag <= cost_insertion:
- */
               __pyx_v_cost_insertion = ((__pyx_v_column[(__pyx_v_i - 1)]).cost + __pyx_v_self->_insertion_cost);
 
-              /* "cutadapt/_align.pyx":398
- * 						cost_insertion = column[i-1].cost + self._insertion_cost
- * 
- * 						if cost_diag <= cost_deletion and cost_diag <= cost_insertion:             # <<<<<<<<<<<<<<
- * 							# MISMATCH
- * 							cost = cost_diag
- */
               __pyx_t_11 = ((__pyx_v_cost_diag <= __pyx_v_cost_deletion) != 0);
               if (__pyx_t_11) {
               } else {
@@ -5158,121 +3760,37 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
               __pyx_L38_bool_binop_done:;
               if (__pyx_t_8) {
 
-                /* "cutadapt/_align.pyx":400
- * 						if cost_diag <= cost_deletion and cost_diag <= cost_insertion:
- * 							# MISMATCH
- * 							cost = cost_diag             # <<<<<<<<<<<<<<
- * 							origin = tmp_entry.origin
- * 							matches = tmp_entry.matches
- */
                 __pyx_v_cost = __pyx_v_cost_diag;
 
-                /* "cutadapt/_align.pyx":401
- * 							# MISMATCH
- * 							cost = cost_diag
- * 							origin = tmp_entry.origin             # <<<<<<<<<<<<<<
- * 							matches = tmp_entry.matches
- * 						elif cost_insertion <= cost_deletion:
- */
                 __pyx_t_16 = __pyx_v_tmp_entry.origin;
                 __pyx_v_origin = __pyx_t_16;
 
-                /* "cutadapt/_align.pyx":402
- * 							cost = cost_diag
- * 							origin = tmp_entry.origin
- * 							matches = tmp_entry.matches             # <<<<<<<<<<<<<<
- * 						elif cost_insertion <= cost_deletion:
- * 							# INSERTION
- */
                 __pyx_t_16 = __pyx_v_tmp_entry.matches;
                 __pyx_v_matches = __pyx_t_16;
 
-                /* "cutadapt/_align.pyx":398
- * 						cost_insertion = column[i-1].cost + self._insertion_cost
- * 
- * 						if cost_diag <= cost_deletion and cost_diag <= cost_insertion:             # <<<<<<<<<<<<<<
- * 							# MISMATCH
- * 							cost = cost_diag
- */
                 goto __pyx_L37;
               }
 
-              /* "cutadapt/_align.pyx":403
- * 							origin = tmp_entry.origin
- * 							matches = tmp_entry.matches
- * 						elif cost_insertion <= cost_deletion:             # <<<<<<<<<<<<<<
- * 							# INSERTION
- * 							cost = cost_insertion
- */
               __pyx_t_8 = ((__pyx_v_cost_insertion <= __pyx_v_cost_deletion) != 0);
               if (__pyx_t_8) {
 
-                /* "cutadapt/_align.pyx":405
- * 						elif cost_insertion <= cost_deletion:
- * 							# INSERTION
- * 							cost = cost_insertion             # <<<<<<<<<<<<<<
- * 							origin = column[i-1].origin
- * 							matches = column[i-1].matches
- */
                 __pyx_v_cost = __pyx_v_cost_insertion;
 
-                /* "cutadapt/_align.pyx":406
- * 							# INSERTION
- * 							cost = cost_insertion
- * 							origin = column[i-1].origin             # <<<<<<<<<<<<<<
- * 							matches = column[i-1].matches
- * 						else:
- */
                 __pyx_t_16 = (__pyx_v_column[(__pyx_v_i - 1)]).origin;
                 __pyx_v_origin = __pyx_t_16;
 
-                /* "cutadapt/_align.pyx":407
- * 							cost = cost_insertion
- * 							origin = column[i-1].origin
- * 							matches = column[i-1].matches             # <<<<<<<<<<<<<<
- * 						else:
- * 							# DELETION
- */
                 __pyx_t_16 = (__pyx_v_column[(__pyx_v_i - 1)]).matches;
                 __pyx_v_matches = __pyx_t_16;
 
-                /* "cutadapt/_align.pyx":403
- * 							origin = tmp_entry.origin
- * 							matches = tmp_entry.matches
- * 						elif cost_insertion <= cost_deletion:             # <<<<<<<<<<<<<<
- * 							# INSERTION
- * 							cost = cost_insertion
- */
                 goto __pyx_L37;
               }
 
-              /* "cutadapt/_align.pyx":410
- * 						else:
- * 							# DELETION
- * 							cost = cost_deletion             # <<<<<<<<<<<<<<
- * 							origin = column[i].origin
- * 							matches = column[i].matches
- */
               /*else*/ {
                 __pyx_v_cost = __pyx_v_cost_deletion;
 
-                /* "cutadapt/_align.pyx":411
- * 							# DELETION
- * 							cost = cost_deletion
- * 							origin = column[i].origin             # <<<<<<<<<<<<<<
- * 							matches = column[i].matches
- * 
- */
                 __pyx_t_16 = (__pyx_v_column[__pyx_v_i]).origin;
                 __pyx_v_origin = __pyx_t_16;
 
-                /* "cutadapt/_align.pyx":412
- * 							cost = cost_deletion
- * 							origin = column[i].origin
- * 							matches = column[i].matches             # <<<<<<<<<<<<<<
- * 
- * 					# remember current cell for next iteration
- */
                 __pyx_t_16 = (__pyx_v_column[__pyx_v_i]).matches;
                 __pyx_v_matches = __pyx_t_16;
               }
@@ -5280,91 +3798,35 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
             }
             __pyx_L36:;
 
-            /* "cutadapt/_align.pyx":415
- * 
- * 					# remember current cell for next iteration
- * 					tmp_entry = column[i]             # <<<<<<<<<<<<<<
- * 
- * 					column[i].cost = cost
- */
             __pyx_v_tmp_entry = (__pyx_v_column[__pyx_v_i]);
 
-            /* "cutadapt/_align.pyx":417
- * 					tmp_entry = column[i]
- * 
- * 					column[i].cost = cost             # <<<<<<<<<<<<<<
- * 					column[i].origin = origin
- * 					column[i].matches = matches
- */
             (__pyx_v_column[__pyx_v_i]).cost = __pyx_v_cost;
 
-            /* "cutadapt/_align.pyx":418
- * 
- * 					column[i].cost = cost
- * 					column[i].origin = origin             # <<<<<<<<<<<<<<
- * 					column[i].matches = matches
- * 				if self.debug:
- */
             (__pyx_v_column[__pyx_v_i]).origin = __pyx_v_origin;
 
-            /* "cutadapt/_align.pyx":419
- * 					column[i].cost = cost
- * 					column[i].origin = origin
- * 					column[i].matches = matches             # <<<<<<<<<<<<<<
- * 				if self.debug:
- * 					with gil:
- */
             (__pyx_v_column[__pyx_v_i]).matches = __pyx_v_matches;
           }
 
-          /* "cutadapt/_align.pyx":420
- * 					column[i].origin = origin
- * 					column[i].matches = matches
- * 				if self.debug:             # <<<<<<<<<<<<<<
- * 					with gil:
- * 						for i in range(last + 1):
- */
           __pyx_t_8 = (__pyx_v_self->debug != 0);
           if (__pyx_t_8) {
 
-            /* "cutadapt/_align.pyx":421
- * 					column[i].matches = matches
- * 				if self.debug:
- * 					with gil:             # <<<<<<<<<<<<<<
- * 						for i in range(last + 1):
- * 							self._dpmatrix.set_entry(i, j, column[i].cost)
- */
             {
                 #ifdef WITH_THREAD
                 PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();
                 #endif
                 /*try:*/ {
 
-                  /* "cutadapt/_align.pyx":422
- * 				if self.debug:
- * 					with gil:
- * 						for i in range(last + 1):             # <<<<<<<<<<<<<<
- * 							self._dpmatrix.set_entry(i, j, column[i].cost)
- * 				while last >= 0 and column[last].cost > k:
- */
                   __pyx_t_15 = (__pyx_v_last + 1);
                   for (__pyx_t_12 = 0; __pyx_t_12 < __pyx_t_15; __pyx_t_12+=1) {
                     __pyx_v_i = __pyx_t_12;
 
-                    /* "cutadapt/_align.pyx":423
- * 					with gil:
- * 						for i in range(last + 1):
- * 							self._dpmatrix.set_entry(i, j, column[i].cost)             # <<<<<<<<<<<<<<
- * 				while last >= 0 and column[last].cost > k:
- * 					last -= 1
- */
-                    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_dpmatrix, __pyx_n_s_set_entry); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L44_error;}
+                    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_dpmatrix, __pyx_n_s_set_entry); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 424, __pyx_L44_error)
                     __Pyx_GOTREF(__pyx_t_2);
-                    __pyx_t_20 = __Pyx_PyInt_From_int(__pyx_v_i); if (unlikely(!__pyx_t_20)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L44_error;}
+                    __pyx_t_20 = __Pyx_PyInt_From_int(__pyx_v_i); if (unlikely(!__pyx_t_20)) __PYX_ERR(0, 424, __pyx_L44_error)
                     __Pyx_GOTREF(__pyx_t_20);
-                    __pyx_t_18 = __Pyx_PyInt_From_int(__pyx_v_j); if (unlikely(!__pyx_t_18)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L44_error;}
+                    __pyx_t_18 = __Pyx_PyInt_From_int(__pyx_v_j); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 424, __pyx_L44_error)
                     __Pyx_GOTREF(__pyx_t_18);
-                    __pyx_t_9 = __Pyx_PyInt_From_int((__pyx_v_column[__pyx_v_i]).cost); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L44_error;}
+                    __pyx_t_9 = __Pyx_PyInt_From_int((__pyx_v_column[__pyx_v_i]).cost); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 424, __pyx_L44_error)
                     __Pyx_GOTREF(__pyx_t_9);
                     __pyx_t_10 = NULL;
                     __pyx_t_5 = 0;
@@ -5378,7 +3840,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
                         __pyx_t_5 = 1;
                       }
                     }
-                    __pyx_t_19 = PyTuple_New(3+__pyx_t_5); if (unlikely(!__pyx_t_19)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L44_error;}
+                    __pyx_t_19 = PyTuple_New(3+__pyx_t_5); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 424, __pyx_L44_error)
                     __Pyx_GOTREF(__pyx_t_19);
                     if (__pyx_t_10) {
                       __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_19, 0, __pyx_t_10); __pyx_t_10 = NULL;
@@ -5392,7 +3854,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
                     __pyx_t_20 = 0;
                     __pyx_t_18 = 0;
                     __pyx_t_9 = 0;
-                    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_19, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L44_error;}
+                    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_19, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 424, __pyx_L44_error)
                     __Pyx_GOTREF(__pyx_t_3);
                     __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0;
                     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -5400,13 +3862,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
                   }
                 }
 
-                /* "cutadapt/_align.pyx":421
- * 					column[i].matches = matches
- * 				if self.debug:
- * 					with gil:             # <<<<<<<<<<<<<<
- * 						for i in range(last + 1):
- * 							self._dpmatrix.set_entry(i, j, column[i].cost)
- */
                 /*finally:*/ {
                   /*normal exit:*/{
                     #ifdef WITH_THREAD
@@ -5424,22 +3879,8 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
                 }
             }
 
-            /* "cutadapt/_align.pyx":420
- * 					column[i].origin = origin
- * 					column[i].matches = matches
- * 				if self.debug:             # <<<<<<<<<<<<<<
- * 					with gil:
- * 						for i in range(last + 1):
- */
           }
 
-          /* "cutadapt/_align.pyx":424
- * 						for i in range(last + 1):
- * 							self._dpmatrix.set_entry(i, j, column[i].cost)
- * 				while last >= 0 and column[last].cost > k:             # <<<<<<<<<<<<<<
- * 					last -= 1
- * 				# last can be -1 here, but will be incremented next.
- */
           while (1) {
             __pyx_t_11 = ((__pyx_v_last >= 0) != 0);
             if (__pyx_t_11) {
@@ -5452,62 +3893,20 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
             __pyx_L50_bool_binop_done:;
             if (!__pyx_t_8) break;
 
-            /* "cutadapt/_align.pyx":425
- * 							self._dpmatrix.set_entry(i, j, column[i].cost)
- * 				while last >= 0 and column[last].cost > k:
- * 					last -= 1             # <<<<<<<<<<<<<<
- * 				# last can be -1 here, but will be incremented next.
- * 				# TODO if last is -1, can we stop searching?
- */
             __pyx_v_last = (__pyx_v_last - 1);
           }
 
-          /* "cutadapt/_align.pyx":428
- * 				# last can be -1 here, but will be incremented next.
- * 				# TODO if last is -1, can we stop searching?
- * 				if last < m:             # <<<<<<<<<<<<<<
- * 					last += 1
- * 				elif stop_in_query:
- */
           __pyx_t_8 = ((__pyx_v_last < __pyx_v_m) != 0);
           if (__pyx_t_8) {
 
-            /* "cutadapt/_align.pyx":429
- * 				# TODO if last is -1, can we stop searching?
- * 				if last < m:
- * 					last += 1             # <<<<<<<<<<<<<<
- * 				elif stop_in_query:
- * 					# Found a match. If requested, find best match in last row.
- */
             __pyx_v_last = (__pyx_v_last + 1);
 
-            /* "cutadapt/_align.pyx":428
- * 				# last can be -1 here, but will be incremented next.
- * 				# TODO if last is -1, can we stop searching?
- * 				if last < m:             # <<<<<<<<<<<<<<
- * 					last += 1
- * 				elif stop_in_query:
- */
             goto __pyx_L52;
           }
 
-          /* "cutadapt/_align.pyx":430
- * 				if last < m:
- * 					last += 1
- * 				elif stop_in_query:             # <<<<<<<<<<<<<<
- * 					# Found a match. If requested, find best match in last row.
- * 					# length of the aligned part of the reference
- */
           __pyx_t_8 = (__pyx_v_stop_in_query != 0);
           if (__pyx_t_8) {
 
-            /* "cutadapt/_align.pyx":433
- * 					# Found a match. If requested, find best match in last row.
- * 					# length of the aligned part of the reference
- * 					length = m + min(column[m].origin, 0)             # <<<<<<<<<<<<<<
- * 					cost = column[m].cost
- * 					matches = column[m].matches
- */
             __pyx_t_15 = 0;
             __pyx_t_12 = (__pyx_v_column[__pyx_v_m]).origin;
             if (((__pyx_t_15 < __pyx_t_12) != 0)) {
@@ -5517,33 +3916,12 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
             }
             __pyx_v_length = (__pyx_v_m + __pyx_t_17);
 
-            /* "cutadapt/_align.pyx":434
- * 					# length of the aligned part of the reference
- * 					length = m + min(column[m].origin, 0)
- * 					cost = column[m].cost             # <<<<<<<<<<<<<<
- * 					matches = column[m].matches
- * 					if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):
- */
             __pyx_t_12 = (__pyx_v_column[__pyx_v_m]).cost;
             __pyx_v_cost = __pyx_t_12;
 
-            /* "cutadapt/_align.pyx":435
- * 					length = m + min(column[m].origin, 0)
- * 					cost = column[m].cost
- * 					matches = column[m].matches             # <<<<<<<<<<<<<<
- * 					if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):
- * 						# update
- */
             __pyx_t_12 = (__pyx_v_column[__pyx_v_m]).matches;
             __pyx_v_matches = __pyx_t_12;
 
-            /* "cutadapt/_align.pyx":436
- * 					cost = column[m].cost
- * 					matches = column[m].matches
- * 					if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):             # <<<<<<<<<<<<<<
- * 						# update
- * 						best.matches = matches
- */
             __pyx_t_11 = ((__pyx_v_length >= __pyx_v_self->_min_overlap) != 0);
             if (__pyx_t_11) {
             } else {
@@ -5573,59 +3951,17 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
             __pyx_L54_bool_binop_done:;
             if (__pyx_t_8) {
 
-              /* "cutadapt/_align.pyx":438
- * 					if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):
- * 						# update
- * 						best.matches = matches             # <<<<<<<<<<<<<<
- * 						best.cost = cost
- * 						best.origin = column[m].origin
- */
               __pyx_v_best.matches = __pyx_v_matches;
 
-              /* "cutadapt/_align.pyx":439
- * 						# update
- * 						best.matches = matches
- * 						best.cost = cost             # <<<<<<<<<<<<<<
- * 						best.origin = column[m].origin
- * 						best.ref_stop = m
- */
               __pyx_v_best.cost = __pyx_v_cost;
 
-              /* "cutadapt/_align.pyx":440
- * 						best.matches = matches
- * 						best.cost = cost
- * 						best.origin = column[m].origin             # <<<<<<<<<<<<<<
- * 						best.ref_stop = m
- * 						best.query_stop = j
- */
               __pyx_t_12 = (__pyx_v_column[__pyx_v_m]).origin;
               __pyx_v_best.origin = __pyx_t_12;
 
-              /* "cutadapt/_align.pyx":441
- * 						best.cost = cost
- * 						best.origin = column[m].origin
- * 						best.ref_stop = m             # <<<<<<<<<<<<<<
- * 						best.query_stop = j
- * 						if cost == 0 and matches == m:
- */
               __pyx_v_best.ref_stop = __pyx_v_m;
 
-              /* "cutadapt/_align.pyx":442
- * 						best.origin = column[m].origin
- * 						best.ref_stop = m
- * 						best.query_stop = j             # <<<<<<<<<<<<<<
- * 						if cost == 0 and matches == m:
- * 							# exact match, stop early
- */
               __pyx_v_best.query_stop = __pyx_v_j;
 
-              /* "cutadapt/_align.pyx":443
- * 						best.ref_stop = m
- * 						best.query_stop = j
- * 						if cost == 0 and matches == m:             # <<<<<<<<<<<<<<
- * 							# exact match, stop early
- * 							break
- */
               __pyx_t_11 = ((__pyx_v_cost == 0) != 0);
               if (__pyx_t_11) {
               } else {
@@ -5637,53 +3973,18 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
               __pyx_L60_bool_binop_done:;
               if (__pyx_t_8) {
 
-                /* "cutadapt/_align.pyx":445
- * 						if cost == 0 and matches == m:
- * 							# exact match, stop early
- * 							break             # <<<<<<<<<<<<<<
- * 				# column finished
- * 
- */
                 goto __pyx_L31_break;
 
-                /* "cutadapt/_align.pyx":443
- * 						best.ref_stop = m
- * 						best.query_stop = j
- * 						if cost == 0 and matches == m:             # <<<<<<<<<<<<<<
- * 							# exact match, stop early
- * 							break
- */
               }
 
-              /* "cutadapt/_align.pyx":436
- * 					cost = column[m].cost
- * 					matches = column[m].matches
- * 					if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):             # <<<<<<<<<<<<<<
- * 						# update
- * 						best.matches = matches
- */
             }
 
-            /* "cutadapt/_align.pyx":430
- * 				if last < m:
- * 					last += 1
- * 				elif stop_in_query:             # <<<<<<<<<<<<<<
- * 					# Found a match. If requested, find best match in last row.
- * 					# length of the aligned part of the reference
- */
           }
           __pyx_L52:;
         }
         __pyx_L31_break:;
       }
 
-      /* "cutadapt/_align.pyx":371
- * 		cdef _Entry tmp_entry
- * 
- * 		with nogil:             # <<<<<<<<<<<<<<
- * 			# iterate over columns
- * 			for j in range(min_n + 1, max_n + 1):
- */
       /*finally:*/ {
         /*normal exit:*/{
           #ifdef WITH_THREAD
@@ -5701,23 +4002,9 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       }
   }
 
-  /* "cutadapt/_align.pyx":448
- * 				# column finished
- * 
- * 		if max_n == n:             # <<<<<<<<<<<<<<
- * 			first_i = 0 if stop_in_ref else m
- * 			# search in last column # TODO last?
- */
   __pyx_t_8 = ((__pyx_v_max_n == __pyx_v_n) != 0);
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":449
- * 
- * 		if max_n == n:
- * 			first_i = 0 if stop_in_ref else m             # <<<<<<<<<<<<<<
- * 			# search in last column # TODO last?
- * 			for i in range(first_i, m+1):
- */
     if ((__pyx_v_stop_in_ref != 0)) {
       __pyx_t_14 = 0;
     } else {
@@ -5725,24 +4012,10 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
     }
     __pyx_v_first_i = __pyx_t_14;
 
-    /* "cutadapt/_align.pyx":451
- * 			first_i = 0 if stop_in_ref else m
- * 			# search in last column # TODO last?
- * 			for i in range(first_i, m+1):             # <<<<<<<<<<<<<<
- * 				length = i + min(column[i].origin, 0)
- * 				cost = column[i].cost
- */
     __pyx_t_14 = (__pyx_v_m + 1);
     for (__pyx_t_13 = __pyx_v_first_i; __pyx_t_13 < __pyx_t_14; __pyx_t_13+=1) {
       __pyx_v_i = __pyx_t_13;
 
-      /* "cutadapt/_align.pyx":452
- * 			# search in last column # TODO last?
- * 			for i in range(first_i, m+1):
- * 				length = i + min(column[i].origin, 0)             # <<<<<<<<<<<<<<
- * 				cost = column[i].cost
- * 				matches = column[i].matches
- */
       __pyx_t_17 = 0;
       __pyx_t_12 = (__pyx_v_column[__pyx_v_i]).origin;
       if (((__pyx_t_17 < __pyx_t_12) != 0)) {
@@ -5752,33 +4025,12 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       }
       __pyx_v_length = (__pyx_v_i + __pyx_t_15);
 
-      /* "cutadapt/_align.pyx":453
- * 			for i in range(first_i, m+1):
- * 				length = i + min(column[i].origin, 0)
- * 				cost = column[i].cost             # <<<<<<<<<<<<<<
- * 				matches = column[i].matches
- * 				if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):
- */
       __pyx_t_12 = (__pyx_v_column[__pyx_v_i]).cost;
       __pyx_v_cost = __pyx_t_12;
 
-      /* "cutadapt/_align.pyx":454
- * 				length = i + min(column[i].origin, 0)
- * 				cost = column[i].cost
- * 				matches = column[i].matches             # <<<<<<<<<<<<<<
- * 				if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):
- * 					# update best
- */
       __pyx_t_12 = (__pyx_v_column[__pyx_v_i]).matches;
       __pyx_v_matches = __pyx_t_12;
 
-      /* "cutadapt/_align.pyx":455
- * 				cost = column[i].cost
- * 				matches = column[i].matches
- * 				if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):             # <<<<<<<<<<<<<<
- * 					# update best
- * 					best.matches = matches
- */
       __pyx_t_11 = ((__pyx_v_length >= __pyx_v_self->_min_overlap) != 0);
       if (__pyx_t_11) {
       } else {
@@ -5808,199 +4060,73 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       __pyx_L66_bool_binop_done:;
       if (__pyx_t_8) {
 
-        /* "cutadapt/_align.pyx":457
- * 				if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):
- * 					# update best
- * 					best.matches = matches             # <<<<<<<<<<<<<<
- * 					best.cost = cost
- * 					best.origin = column[i].origin
- */
         __pyx_v_best.matches = __pyx_v_matches;
 
-        /* "cutadapt/_align.pyx":458
- * 					# update best
- * 					best.matches = matches
- * 					best.cost = cost             # <<<<<<<<<<<<<<
- * 					best.origin = column[i].origin
- * 					best.ref_stop = i
- */
         __pyx_v_best.cost = __pyx_v_cost;
 
-        /* "cutadapt/_align.pyx":459
- * 					best.matches = matches
- * 					best.cost = cost
- * 					best.origin = column[i].origin             # <<<<<<<<<<<<<<
- * 					best.ref_stop = i
- * 					best.query_stop = n
- */
         __pyx_t_12 = (__pyx_v_column[__pyx_v_i]).origin;
         __pyx_v_best.origin = __pyx_t_12;
 
-        /* "cutadapt/_align.pyx":460
- * 					best.cost = cost
- * 					best.origin = column[i].origin
- * 					best.ref_stop = i             # <<<<<<<<<<<<<<
- * 					best.query_stop = n
- * 		if best.cost == m + n:
- */
         __pyx_v_best.ref_stop = __pyx_v_i;
 
-        /* "cutadapt/_align.pyx":461
- * 					best.origin = column[i].origin
- * 					best.ref_stop = i
- * 					best.query_stop = n             # <<<<<<<<<<<<<<
- * 		if best.cost == m + n:
- * 			# best.cost was initialized with this value.
- */
         __pyx_v_best.query_stop = __pyx_v_n;
 
-        /* "cutadapt/_align.pyx":455
- * 				cost = column[i].cost
- * 				matches = column[i].matches
- * 				if length >= self._min_overlap and cost <= length * max_error_rate and (matches > best.matches or (matches == best.matches and cost < best.cost)):             # <<<<<<<<<<<<<<
- * 					# update best
- * 					best.matches = matches
- */
       }
     }
 
-    /* "cutadapt/_align.pyx":448
- * 				# column finished
- * 
- * 		if max_n == n:             # <<<<<<<<<<<<<<
- * 			first_i = 0 if stop_in_ref else m
- * 			# search in last column # TODO last?
- */
   }
 
-  /* "cutadapt/_align.pyx":462
- * 					best.ref_stop = i
- * 					best.query_stop = n
- * 		if best.cost == m + n:             # <<<<<<<<<<<<<<
- * 			# best.cost was initialized with this value.
- * 			# If it is unchanged, no alignment was found that has
- */
   __pyx_t_8 = ((__pyx_v_best.cost == (__pyx_v_m + __pyx_v_n)) != 0);
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":466
- * 			# If it is unchanged, no alignment was found that has
- * 			# an error rate within the allowed range.
- * 			return None             # <<<<<<<<<<<<<<
- * 
- * 		cdef int start1, start2
- */
     __Pyx_XDECREF(__pyx_r);
     __Pyx_INCREF(Py_None);
     __pyx_r = Py_None;
     goto __pyx_L0;
 
-    /* "cutadapt/_align.pyx":462
- * 					best.ref_stop = i
- * 					best.query_stop = n
- * 		if best.cost == m + n:             # <<<<<<<<<<<<<<
- * 			# best.cost was initialized with this value.
- * 			# If it is unchanged, no alignment was found that has
- */
   }
 
-  /* "cutadapt/_align.pyx":469
- * 
- * 		cdef int start1, start2
- * 		if best.origin >= 0:             # <<<<<<<<<<<<<<
- * 			start1 = 0
- * 			start2 = best.origin
- */
   __pyx_t_8 = ((__pyx_v_best.origin >= 0) != 0);
   if (__pyx_t_8) {
 
-    /* "cutadapt/_align.pyx":470
- * 		cdef int start1, start2
- * 		if best.origin >= 0:
- * 			start1 = 0             # <<<<<<<<<<<<<<
- * 			start2 = best.origin
- * 		else:
- */
     __pyx_v_start1 = 0;
 
-    /* "cutadapt/_align.pyx":471
- * 		if best.origin >= 0:
- * 			start1 = 0
- * 			start2 = best.origin             # <<<<<<<<<<<<<<
- * 		else:
- * 			start1 = -best.origin
- */
     __pyx_t_13 = __pyx_v_best.origin;
     __pyx_v_start2 = __pyx_t_13;
 
-    /* "cutadapt/_align.pyx":469
- * 
- * 		cdef int start1, start2
- * 		if best.origin >= 0:             # <<<<<<<<<<<<<<
- * 			start1 = 0
- * 			start2 = best.origin
- */
     goto __pyx_L72;
   }
 
-  /* "cutadapt/_align.pyx":473
- * 			start2 = best.origin
- * 		else:
- * 			start1 = -best.origin             # <<<<<<<<<<<<<<
- * 			start2 = 0
- * 
- */
   /*else*/ {
     __pyx_v_start1 = (-__pyx_v_best.origin);
 
-    /* "cutadapt/_align.pyx":474
- * 		else:
- * 			start1 = -best.origin
- * 			start2 = 0             # <<<<<<<<<<<<<<
- * 
- * 		assert best.ref_stop - start1 > 0  # Do not return empty alignments.
- */
     __pyx_v_start2 = 0;
   }
   __pyx_L72:;
 
-  /* "cutadapt/_align.pyx":476
- * 			start2 = 0
- * 
- * 		assert best.ref_stop - start1 > 0  # Do not return empty alignments.             # <<<<<<<<<<<<<<
- * 		return (start1, best.ref_stop, start2, best.query_stop, best.matches, best.cost)
- * 
- */
   #ifndef CYTHON_WITHOUT_ASSERTIONS
   if (unlikely(!Py_OptimizeFlag)) {
     if (unlikely(!(((__pyx_v_best.ref_stop - __pyx_v_start1) > 0) != 0))) {
       PyErr_SetNone(PyExc_AssertionError);
-      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 476; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __PYX_ERR(0, 477, __pyx_L1_error)
     }
   }
   #endif
 
-  /* "cutadapt/_align.pyx":477
- * 
- * 		assert best.ref_stop - start1 > 0  # Do not return empty alignments.
- * 		return (start1, best.ref_stop, start2, best.query_stop, best.matches, best.cost)             # <<<<<<<<<<<<<<
- * 
- * 	def __dealloc__(self):
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_start1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 477; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_start1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 478, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_best.ref_stop); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 477; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_best.ref_stop); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 478, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_19 = __Pyx_PyInt_From_int(__pyx_v_start2); if (unlikely(!__pyx_t_19)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 477; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_19 = __Pyx_PyInt_From_int(__pyx_v_start2); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 478, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_19);
-  __pyx_t_9 = __Pyx_PyInt_From_int(__pyx_v_best.query_stop); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 477; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_9 = __Pyx_PyInt_From_int(__pyx_v_best.query_stop); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 478, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_9);
-  __pyx_t_18 = __Pyx_PyInt_From_int(__pyx_v_best.matches); if (unlikely(!__pyx_t_18)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 477; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_18 = __Pyx_PyInt_From_int(__pyx_v_best.matches); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 478, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_18);
-  __pyx_t_20 = __Pyx_PyInt_From_int(__pyx_v_best.cost); if (unlikely(!__pyx_t_20)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 477; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_20 = __Pyx_PyInt_From_int(__pyx_v_best.cost); if (unlikely(!__pyx_t_20)) __PYX_ERR(0, 478, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_20);
-  __pyx_t_10 = PyTuple_New(6); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 477; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_10 = PyTuple_New(6); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 478, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_10);
   __Pyx_GIVEREF(__pyx_t_3);
   PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_3);
@@ -6024,13 +4150,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
   __pyx_t_10 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_align.pyx":259
- * 		self.debug = True
- * 
- * 	def locate(self, str query):             # <<<<<<<<<<<<<<
- * 		"""
- * 		locate(query) -> (refstart, refstop, querystart, querystop, matches, errors)
- */
 
   /* function exit code */
   __pyx_L1_error:;
@@ -6050,13 +4169,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":479
- * 		return (start1, best.ref_stop, start2, best.query_stop, best.matches, best.cost)
- * 
- * 	def __dealloc__(self):             # <<<<<<<<<<<<<<
- * 		PyMem_Free(self.column)
- * 
- */
 
 /* Python wrapper */
 static void __pyx_pw_8cutadapt_6_align_7Aligner_7__dealloc__(PyObject *__pyx_v_self); /*proto*/
@@ -6073,34 +4185,13 @@ static void __pyx_pf_8cutadapt_6_align_7Aligner_6__dealloc__(struct __pyx_obj_8c
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-  /* "cutadapt/_align.pyx":480
- * 
- * 	def __dealloc__(self):
- * 		PyMem_Free(self.column)             # <<<<<<<<<<<<<<
- * 
- * 
- */
   PyMem_Free(__pyx_v_self->column);
 
-  /* "cutadapt/_align.pyx":479
- * 		return (start1, best.ref_stop, start2, best.query_stop, best.matches, best.cost)
- * 
- * 	def __dealloc__(self):             # <<<<<<<<<<<<<<
- * 		PyMem_Free(self.column)
- * 
- */
 
   /* function exit code */
   __Pyx_RefNannyFinishContext();
 }
 
-/* "cutadapt/_align.pyx":483
- * 
- * 
- * def locate(str reference, str query, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False, int min_overlap=1):             # <<<<<<<<<<<<<<
- * 	aligner = Aligner(reference, max_error_rate, flags, wildcard_ref, wildcard_query)
- * 	aligner.min_overlap = min_overlap
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_5locate(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
@@ -6113,9 +4204,6 @@ static PyObject *__pyx_pw_8cutadapt_6_align_5locate(PyObject *__pyx_self, PyObje
   int __pyx_v_wildcard_ref;
   int __pyx_v_wildcard_query;
   int __pyx_v_min_overlap;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("locate (wrapper)", 0);
@@ -6144,12 +4232,12 @@ static PyObject *__pyx_pw_8cutadapt_6_align_5locate(PyObject *__pyx_self, PyObje
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_query)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("locate", 0, 3, 7, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("locate", 0, 3, 7, 1); __PYX_ERR(0, 484, __pyx_L3_error)
         }
         case  2:
         if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_max_error_rate)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("locate", 0, 3, 7, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("locate", 0, 3, 7, 2); __PYX_ERR(0, 484, __pyx_L3_error)
         }
         case  3:
         if (kw_args > 0) {
@@ -6173,7 +4261,7 @@ static PyObject *__pyx_pw_8cutadapt_6_align_5locate(PyObject *__pyx_self, PyObje
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "locate") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "locate") < 0)) __PYX_ERR(0, 484, __pyx_L3_error)
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -6190,38 +4278,38 @@ static PyObject *__pyx_pw_8cutadapt_6_align_5locate(PyObject *__pyx_self, PyObje
     }
     __pyx_v_reference = ((PyObject*)values[0]);
     __pyx_v_query = ((PyObject*)values[1]);
-    __pyx_v_max_error_rate = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_max_error_rate == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_max_error_rate = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_max_error_rate == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 484, __pyx_L3_error)
     if (values[3]) {
-      __pyx_v_flags = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_flags == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_flags = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_flags == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 484, __pyx_L3_error)
     } else {
       __pyx_v_flags = ((int)15);
     }
     if (values[4]) {
-      __pyx_v_wildcard_ref = __Pyx_PyObject_IsTrue(values[4]); if (unlikely((__pyx_v_wildcard_ref == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_wildcard_ref = __Pyx_PyObject_IsTrue(values[4]); if (unlikely((__pyx_v_wildcard_ref == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 484, __pyx_L3_error)
     } else {
       __pyx_v_wildcard_ref = ((int)0);
     }
     if (values[5]) {
-      __pyx_v_wildcard_query = __Pyx_PyObject_IsTrue(values[5]); if (unlikely((__pyx_v_wildcard_query == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_wildcard_query = __Pyx_PyObject_IsTrue(values[5]); if (unlikely((__pyx_v_wildcard_query == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 484, __pyx_L3_error)
     } else {
       __pyx_v_wildcard_query = ((int)0);
     }
     if (values[6]) {
-      __pyx_v_min_overlap = __Pyx_PyInt_As_int(values[6]); if (unlikely((__pyx_v_min_overlap == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_min_overlap = __Pyx_PyInt_As_int(values[6]); if (unlikely((__pyx_v_min_overlap == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 484, __pyx_L3_error)
     } else {
       __pyx_v_min_overlap = ((int)1);
     }
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("locate", 0, 3, 7, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("locate", 0, 3, 7, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 484, __pyx_L3_error)
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._align.locate", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_reference), (&PyString_Type), 1, "reference", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_query), (&PyString_Type), 1, "query", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_reference), (&PyString_Type), 1, "reference", 1))) __PYX_ERR(0, 484, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_query), (&PyString_Type), 1, "query", 1))) __PYX_ERR(0, 484, __pyx_L1_error)
   __pyx_r = __pyx_pf_8cutadapt_6_align_4locate(__pyx_self, __pyx_v_reference, __pyx_v_query, __pyx_v_max_error_rate, __pyx_v_flags, __pyx_v_wildcard_ref, __pyx_v_wildcard_query, __pyx_v_min_overlap);
 
   /* function exit code */
@@ -6242,27 +4330,17 @@ static PyObject *__pyx_pf_8cutadapt_6_align_4locate(CYTHON_UNUSED PyObject *__py
   PyObject *__pyx_t_3 = NULL;
   PyObject *__pyx_t_4 = NULL;
   PyObject *__pyx_t_5 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("locate", 0);
 
-  /* "cutadapt/_align.pyx":484
- * 
- * def locate(str reference, str query, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False, int min_overlap=1):
- * 	aligner = Aligner(reference, max_error_rate, flags, wildcard_ref, wildcard_query)             # <<<<<<<<<<<<<<
- * 	aligner.min_overlap = min_overlap
- * 	return aligner.locate(query)
- */
-  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_max_error_rate); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 484; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_max_error_rate); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 485, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_flags); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 484; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_flags); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 485, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_v_wildcard_ref); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 484; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_v_wildcard_ref); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 485, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_4 = __Pyx_PyBool_FromLong(__pyx_v_wildcard_query); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 484; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_PyBool_FromLong(__pyx_v_wildcard_query); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 485, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  __pyx_t_5 = PyTuple_New(5); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 484; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_5 = PyTuple_New(5); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 485, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_5);
   __Pyx_INCREF(__pyx_v_reference);
   __Pyx_GIVEREF(__pyx_v_reference);
@@ -6279,33 +4357,19 @@ static PyObject *__pyx_pf_8cutadapt_6_align_4locate(CYTHON_UNUSED PyObject *__py
   __pyx_t_2 = 0;
   __pyx_t_3 = 0;
   __pyx_t_4 = 0;
-  __pyx_t_4 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_8cutadapt_6_align_Aligner), __pyx_t_5, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 484; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_8cutadapt_6_align_Aligner), __pyx_t_5, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 485, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
   __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
   __pyx_v_aligner = ((struct __pyx_obj_8cutadapt_6_align_Aligner *)__pyx_t_4);
   __pyx_t_4 = 0;
 
-  /* "cutadapt/_align.pyx":485
- * def locate(str reference, str query, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False, int min_overlap=1):
- * 	aligner = Aligner(reference, max_error_rate, flags, wildcard_ref, wildcard_query)
- * 	aligner.min_overlap = min_overlap             # <<<<<<<<<<<<<<
- * 	return aligner.locate(query)
- * 
- */
-  __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_min_overlap); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 485; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_min_overlap); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 486, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  if (__Pyx_PyObject_SetAttrStr(((PyObject *)__pyx_v_aligner), __pyx_n_s_min_overlap, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 485; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_PyObject_SetAttrStr(((PyObject *)__pyx_v_aligner), __pyx_n_s_min_overlap, __pyx_t_4) < 0) __PYX_ERR(0, 486, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "cutadapt/_align.pyx":486
- * 	aligner = Aligner(reference, max_error_rate, flags, wildcard_ref, wildcard_query)
- * 	aligner.min_overlap = min_overlap
- * 	return aligner.locate(query)             # <<<<<<<<<<<<<<
- * 
- * 
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_aligner), __pyx_n_s_locate); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 486; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_aligner), __pyx_n_s_locate); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 487, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_5);
   __pyx_t_3 = NULL;
   if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_5))) {
@@ -6318,16 +4382,16 @@ static PyObject *__pyx_pf_8cutadapt_6_align_4locate(CYTHON_UNUSED PyObject *__py
     }
   }
   if (!__pyx_t_3) {
-    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_query); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 486; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_query); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 487, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_4);
   } else {
-    __pyx_t_2 = PyTuple_New(1+1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 486; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = PyTuple_New(1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 487, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); __pyx_t_3 = NULL;
     __Pyx_INCREF(__pyx_v_query);
     __Pyx_GIVEREF(__pyx_v_query);
     PyTuple_SET_ITEM(__pyx_t_2, 0+1, __pyx_v_query);
-    __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_2, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 486; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_2, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 487, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_4);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   }
@@ -6336,13 +4400,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_4locate(CYTHON_UNUSED PyObject *__py
   __pyx_t_4 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_align.pyx":483
- * 
- * 
- * def locate(str reference, str query, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False, int min_overlap=1):             # <<<<<<<<<<<<<<
- * 	aligner = Aligner(reference, max_error_rate, flags, wildcard_ref, wildcard_query)
- * 	aligner.min_overlap = min_overlap
- */
 
   /* function exit code */
   __pyx_L1_error:;
@@ -6360,13 +4417,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_4locate(CYTHON_UNUSED PyObject *__py
   return __pyx_r;
 }
 
-/* "cutadapt/_align.pyx":489
- * 
- * 
- * def compare_prefixes(str ref, str query, bint wildcard_ref=False, bint wildcard_query=False):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Find out whether one string is the prefix of the other one, allowing
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_6_align_7compare_prefixes(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
@@ -6377,9 +4427,6 @@ static PyObject *__pyx_pw_8cutadapt_6_align_7compare_prefixes(PyObject *__pyx_se
   PyObject *__pyx_v_query = 0;
   int __pyx_v_wildcard_ref;
   int __pyx_v_wildcard_query;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("compare_prefixes (wrapper)", 0);
@@ -6405,7 +4452,7 @@ static PyObject *__pyx_pw_8cutadapt_6_align_7compare_prefixes(PyObject *__pyx_se
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_query)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("compare_prefixes", 0, 2, 4, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("compare_prefixes", 0, 2, 4, 1); __PYX_ERR(0, 490, __pyx_L3_error)
         }
         case  2:
         if (kw_args > 0) {
@@ -6419,7 +4466,7 @@ static PyObject *__pyx_pw_8cutadapt_6_align_7compare_prefixes(PyObject *__pyx_se
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "compare_prefixes") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "compare_prefixes") < 0)) __PYX_ERR(0, 490, __pyx_L3_error)
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -6434,26 +4481,26 @@ static PyObject *__pyx_pw_8cutadapt_6_align_7compare_prefixes(PyObject *__pyx_se
     __pyx_v_ref = ((PyObject*)values[0]);
     __pyx_v_query = ((PyObject*)values[1]);
     if (values[2]) {
-      __pyx_v_wildcard_ref = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_wildcard_ref == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_wildcard_ref = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_wildcard_ref == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 490, __pyx_L3_error)
     } else {
       __pyx_v_wildcard_ref = ((int)0);
     }
     if (values[3]) {
-      __pyx_v_wildcard_query = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_wildcard_query == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_wildcard_query = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_wildcard_query == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 490, __pyx_L3_error)
     } else {
       __pyx_v_wildcard_query = ((int)0);
     }
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("compare_prefixes", 0, 2, 4, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("compare_prefixes", 0, 2, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 490, __pyx_L3_error)
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._align.compare_prefixes", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_ref), (&PyString_Type), 1, "ref", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_query), (&PyString_Type), 1, "query", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_ref), (&PyString_Type), 1, "ref", 1))) __PYX_ERR(0, 490, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_query), (&PyString_Type), 1, "query", 1))) __PYX_ERR(0, 490, __pyx_L1_error)
   __pyx_r = __pyx_pf_8cutadapt_6_align_6compare_prefixes(__pyx_self, __pyx_v_ref, __pyx_v_query, __pyx_v_wildcard_ref, __pyx_v_wildcard_query);
 
   /* function exit code */
@@ -6489,70 +4536,32 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
   PyObject *__pyx_t_9 = NULL;
   char *__pyx_t_10;
   PyObject *__pyx_t_11 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("compare_prefixes", 0);
 
-  /* "cutadapt/_align.pyx":499
- * 	This function returns a tuple compatible with what Aligner.locate outputs.
- * 	"""
- * 	cdef int m = len(ref)             # <<<<<<<<<<<<<<
- * 	cdef int n = len(query)
- * 	cdef bytes query_bytes = query.encode('ascii')
- */
-  __pyx_t_1 = PyObject_Length(__pyx_v_ref); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 499; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_ref); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 500, __pyx_L1_error)
   __pyx_v_m = __pyx_t_1;
 
-  /* "cutadapt/_align.pyx":500
- * 	"""
- * 	cdef int m = len(ref)
- * 	cdef int n = len(query)             # <<<<<<<<<<<<<<
- * 	cdef bytes query_bytes = query.encode('ascii')
- * 	cdef bytes ref_bytes = ref.encode('ascii')
- */
-  __pyx_t_1 = PyObject_Length(__pyx_v_query); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 500; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_query); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 501, __pyx_L1_error)
   __pyx_v_n = __pyx_t_1;
 
-  /* "cutadapt/_align.pyx":501
- * 	cdef int m = len(ref)
- * 	cdef int n = len(query)
- * 	cdef bytes query_bytes = query.encode('ascii')             # <<<<<<<<<<<<<<
- * 	cdef bytes ref_bytes = ref.encode('ascii')
- * 	cdef char* r_ptr
- */
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query, __pyx_n_s_encode); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 501; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query, __pyx_n_s_encode); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 502, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__13, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 501; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__13, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 502, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 501; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(0, 502, __pyx_L1_error)
   __pyx_v_query_bytes = ((PyObject*)__pyx_t_3);
   __pyx_t_3 = 0;
 
-  /* "cutadapt/_align.pyx":502
- * 	cdef int n = len(query)
- * 	cdef bytes query_bytes = query.encode('ascii')
- * 	cdef bytes ref_bytes = ref.encode('ascii')             # <<<<<<<<<<<<<<
- * 	cdef char* r_ptr
- * 	cdef char* q_ptr
- */
-  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_ref, __pyx_n_s_encode); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 502; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_ref, __pyx_n_s_encode); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 503, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__14, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 502; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__14, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 503, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 502; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 503, __pyx_L1_error)
   __pyx_v_ref_bytes = ((PyObject*)__pyx_t_2);
   __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":505
- * 	cdef char* r_ptr
- * 	cdef char* q_ptr
- * 	cdef int length = min(m, n)             # <<<<<<<<<<<<<<
- * 	cdef int i, matches = 0
- * 	cdef bint compare_ascii = False
- */
   __pyx_t_4 = __pyx_v_n;
   __pyx_t_5 = __pyx_v_m;
   if (((__pyx_t_4 < __pyx_t_5) != 0)) {
@@ -6562,42 +4571,14 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
   }
   __pyx_v_length = __pyx_t_6;
 
-  /* "cutadapt/_align.pyx":506
- * 	cdef char* q_ptr
- * 	cdef int length = min(m, n)
- * 	cdef int i, matches = 0             # <<<<<<<<<<<<<<
- * 	cdef bint compare_ascii = False
- * 
- */
   __pyx_v_matches = 0;
 
-  /* "cutadapt/_align.pyx":507
- * 	cdef int length = min(m, n)
- * 	cdef int i, matches = 0
- * 	cdef bint compare_ascii = False             # <<<<<<<<<<<<<<
- * 
- * 	if wildcard_ref:
- */
   __pyx_v_compare_ascii = 0;
 
-  /* "cutadapt/_align.pyx":509
- * 	cdef bint compare_ascii = False
- * 
- * 	if wildcard_ref:             # <<<<<<<<<<<<<<
- * 		ref_bytes = ref_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_query:
- */
   __pyx_t_7 = (__pyx_v_wildcard_ref != 0);
   if (__pyx_t_7) {
 
-    /* "cutadapt/_align.pyx":510
- * 
- * 	if wildcard_ref:
- * 		ref_bytes = ref_bytes.translate(IUPAC_TABLE)             # <<<<<<<<<<<<<<
- * 	elif wildcard_query:
- * 		ref_bytes = ref_bytes.translate(ACGT_TABLE)
- */
-    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_ref_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 510; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_ref_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 511, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_8 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
@@ -6610,52 +4591,31 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
       }
     }
     if (!__pyx_t_8) {
-      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 510; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 511, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 510; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 511, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_9);
       __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
       __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
       __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
       PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 510; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 511, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
       __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 510; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 511, __pyx_L1_error)
     __Pyx_DECREF_SET(__pyx_v_ref_bytes, ((PyObject*)__pyx_t_2));
     __pyx_t_2 = 0;
 
-    /* "cutadapt/_align.pyx":509
- * 	cdef bint compare_ascii = False
- * 
- * 	if wildcard_ref:             # <<<<<<<<<<<<<<
- * 		ref_bytes = ref_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_query:
- */
     goto __pyx_L3;
   }
 
-  /* "cutadapt/_align.pyx":511
- * 	if wildcard_ref:
- * 		ref_bytes = ref_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_query:             # <<<<<<<<<<<<<<
- * 		ref_bytes = ref_bytes.translate(ACGT_TABLE)
- * 	else:
- */
   __pyx_t_7 = (__pyx_v_wildcard_query != 0);
   if (__pyx_t_7) {
 
-    /* "cutadapt/_align.pyx":512
- * 		ref_bytes = ref_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_query:
- * 		ref_bytes = ref_bytes.translate(ACGT_TABLE)             # <<<<<<<<<<<<<<
- * 	else:
- * 		compare_ascii = True
- */
-    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_ref_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_ref_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 513, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_9 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
@@ -6668,64 +4628,36 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
       }
     }
     if (!__pyx_t_9) {
-      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 513, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 513, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_8);
       __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_9); __pyx_t_9 = NULL;
       __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
       __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
       PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 513, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
       __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 513, __pyx_L1_error)
     __Pyx_DECREF_SET(__pyx_v_ref_bytes, ((PyObject*)__pyx_t_2));
     __pyx_t_2 = 0;
 
-    /* "cutadapt/_align.pyx":511
- * 	if wildcard_ref:
- * 		ref_bytes = ref_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_query:             # <<<<<<<<<<<<<<
- * 		ref_bytes = ref_bytes.translate(ACGT_TABLE)
- * 	else:
- */
     goto __pyx_L3;
   }
 
-  /* "cutadapt/_align.pyx":514
- * 		ref_bytes = ref_bytes.translate(ACGT_TABLE)
- * 	else:
- * 		compare_ascii = True             # <<<<<<<<<<<<<<
- * 	if wildcard_query:
- * 		query_bytes = query_bytes.translate(IUPAC_TABLE)
- */
   /*else*/ {
     __pyx_v_compare_ascii = 1;
   }
   __pyx_L3:;
 
-  /* "cutadapt/_align.pyx":515
- * 	else:
- * 		compare_ascii = True
- * 	if wildcard_query:             # <<<<<<<<<<<<<<
- * 		query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_ref:
- */
   __pyx_t_7 = (__pyx_v_wildcard_query != 0);
   if (__pyx_t_7) {
 
-    /* "cutadapt/_align.pyx":516
- * 		compare_ascii = True
- * 	if wildcard_query:
- * 		query_bytes = query_bytes.translate(IUPAC_TABLE)             # <<<<<<<<<<<<<<
- * 	elif wildcard_ref:
- * 		query_bytes = query_bytes.translate(ACGT_TABLE)
- */
-    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 516; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 517, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_8 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
@@ -6738,52 +4670,31 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
       }
     }
     if (!__pyx_t_8) {
-      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 516; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 517, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 516; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 517, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_9);
       __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
       __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
       __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
       PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 516; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 517, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
       __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 516; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 517, __pyx_L1_error)
     __Pyx_DECREF_SET(__pyx_v_query_bytes, ((PyObject*)__pyx_t_2));
     __pyx_t_2 = 0;
 
-    /* "cutadapt/_align.pyx":515
- * 	else:
- * 		compare_ascii = True
- * 	if wildcard_query:             # <<<<<<<<<<<<<<
- * 		query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_ref:
- */
     goto __pyx_L4;
   }
 
-  /* "cutadapt/_align.pyx":517
- * 	if wildcard_query:
- * 		query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_ref:             # <<<<<<<<<<<<<<
- * 		query_bytes = query_bytes.translate(ACGT_TABLE)
- * 
- */
   __pyx_t_7 = (__pyx_v_wildcard_ref != 0);
   if (__pyx_t_7) {
 
-    /* "cutadapt/_align.pyx":518
- * 		query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_ref:
- * 		query_bytes = query_bytes.translate(ACGT_TABLE)             # <<<<<<<<<<<<<<
- * 
- * 	if compare_ascii:
- */
-    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 518; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 519, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_9 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
@@ -6796,180 +4707,84 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
       }
     }
     if (!__pyx_t_9) {
-      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 518; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 519, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 518; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 519, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_8);
       __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_9); __pyx_t_9 = NULL;
       __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
       __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
       PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 518; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 519, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
       __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 518; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 519, __pyx_L1_error)
     __Pyx_DECREF_SET(__pyx_v_query_bytes, ((PyObject*)__pyx_t_2));
     __pyx_t_2 = 0;
 
-    /* "cutadapt/_align.pyx":517
- * 	if wildcard_query:
- * 		query_bytes = query_bytes.translate(IUPAC_TABLE)
- * 	elif wildcard_ref:             # <<<<<<<<<<<<<<
- * 		query_bytes = query_bytes.translate(ACGT_TABLE)
- * 
- */
   }
   __pyx_L4:;
 
-  /* "cutadapt/_align.pyx":520
- * 		query_bytes = query_bytes.translate(ACGT_TABLE)
- * 
- * 	if compare_ascii:             # <<<<<<<<<<<<<<
- * 		for i in range(length):
- * 			if ref[i] == query[i]:
- */
   __pyx_t_7 = (__pyx_v_compare_ascii != 0);
   if (__pyx_t_7) {
 
-    /* "cutadapt/_align.pyx":521
- * 
- * 	if compare_ascii:
- * 		for i in range(length):             # <<<<<<<<<<<<<<
- * 			if ref[i] == query[i]:
- * 				matches += 1
- */
     __pyx_t_6 = __pyx_v_length;
     for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_6; __pyx_t_4+=1) {
       __pyx_v_i = __pyx_t_4;
 
-      /* "cutadapt/_align.pyx":522
- * 	if compare_ascii:
- * 		for i in range(length):
- * 			if ref[i] == query[i]:             # <<<<<<<<<<<<<<
- * 				matches += 1
- * 	else:
- */
-      __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_ref, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_2 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 522; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+      __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_ref, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 523, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
-      __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_query, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 522; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+      __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_query, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 523, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_3);
-      __pyx_t_8 = PyObject_RichCompare(__pyx_t_2, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_8); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 522; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_8 = PyObject_RichCompare(__pyx_t_2, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_8); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 523, __pyx_L1_error)
       __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
       __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-      __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely(__pyx_t_7 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 522; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely(__pyx_t_7 < 0)) __PYX_ERR(0, 523, __pyx_L1_error)
       __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
       if (__pyx_t_7) {
 
-        /* "cutadapt/_align.pyx":523
- * 		for i in range(length):
- * 			if ref[i] == query[i]:
- * 				matches += 1             # <<<<<<<<<<<<<<
- * 	else:
- * 		r_ptr = ref_bytes
- */
         __pyx_v_matches = (__pyx_v_matches + 1);
 
-        /* "cutadapt/_align.pyx":522
- * 	if compare_ascii:
- * 		for i in range(length):
- * 			if ref[i] == query[i]:             # <<<<<<<<<<<<<<
- * 				matches += 1
- * 	else:
- */
       }
     }
 
-    /* "cutadapt/_align.pyx":520
- * 		query_bytes = query_bytes.translate(ACGT_TABLE)
- * 
- * 	if compare_ascii:             # <<<<<<<<<<<<<<
- * 		for i in range(length):
- * 			if ref[i] == query[i]:
- */
     goto __pyx_L5;
   }
 
-  /* "cutadapt/_align.pyx":525
- * 				matches += 1
- * 	else:
- * 		r_ptr = ref_bytes             # <<<<<<<<<<<<<<
- * 		q_ptr = query_bytes
- * 		for i in range(length):
- */
   /*else*/ {
-    __pyx_t_10 = __Pyx_PyObject_AsString(__pyx_v_ref_bytes); if (unlikely((!__pyx_t_10) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 525; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_10 = __Pyx_PyObject_AsString(__pyx_v_ref_bytes); if (unlikely((!__pyx_t_10) && PyErr_Occurred())) __PYX_ERR(0, 526, __pyx_L1_error)
     __pyx_v_r_ptr = __pyx_t_10;
 
-    /* "cutadapt/_align.pyx":526
- * 	else:
- * 		r_ptr = ref_bytes
- * 		q_ptr = query_bytes             # <<<<<<<<<<<<<<
- * 		for i in range(length):
- * 			if (r_ptr[i] & q_ptr[i]) != 0:
- */
-    __pyx_t_10 = __Pyx_PyObject_AsString(__pyx_v_query_bytes); if (unlikely((!__pyx_t_10) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 526; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_10 = __Pyx_PyObject_AsString(__pyx_v_query_bytes); if (unlikely((!__pyx_t_10) && PyErr_Occurred())) __PYX_ERR(0, 527, __pyx_L1_error)
     __pyx_v_q_ptr = __pyx_t_10;
 
-    /* "cutadapt/_align.pyx":527
- * 		r_ptr = ref_bytes
- * 		q_ptr = query_bytes
- * 		for i in range(length):             # <<<<<<<<<<<<<<
- * 			if (r_ptr[i] & q_ptr[i]) != 0:
- * 				matches += 1
- */
     __pyx_t_6 = __pyx_v_length;
     for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_6; __pyx_t_4+=1) {
       __pyx_v_i = __pyx_t_4;
 
-      /* "cutadapt/_align.pyx":528
- * 		q_ptr = query_bytes
- * 		for i in range(length):
- * 			if (r_ptr[i] & q_ptr[i]) != 0:             # <<<<<<<<<<<<<<
- * 				matches += 1
- * 
- */
       __pyx_t_7 = ((((__pyx_v_r_ptr[__pyx_v_i]) & (__pyx_v_q_ptr[__pyx_v_i])) != 0) != 0);
       if (__pyx_t_7) {
 
-        /* "cutadapt/_align.pyx":529
- * 		for i in range(length):
- * 			if (r_ptr[i] & q_ptr[i]) != 0:
- * 				matches += 1             # <<<<<<<<<<<<<<
- * 
- * 	# length - matches = no. of errors
- */
         __pyx_v_matches = (__pyx_v_matches + 1);
 
-        /* "cutadapt/_align.pyx":528
- * 		q_ptr = query_bytes
- * 		for i in range(length):
- * 			if (r_ptr[i] & q_ptr[i]) != 0:             # <<<<<<<<<<<<<<
- * 				matches += 1
- * 
- */
       }
     }
   }
   __pyx_L5:;
 
-  /* "cutadapt/_align.pyx":532
- * 
- * 	# length - matches = no. of errors
- * 	return (0, length, 0, length, matches, length - matches)             # <<<<<<<<<<<<<<
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_8 = __Pyx_PyInt_From_int(__pyx_v_length); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_8 = __Pyx_PyInt_From_int(__pyx_v_length); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 533, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_8);
-  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_length); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_length); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 533, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_matches); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_matches); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 533, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_9 = __Pyx_PyInt_From_int((__pyx_v_length - __pyx_v_matches)); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_9 = __Pyx_PyInt_From_int((__pyx_v_length - __pyx_v_matches)); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 533, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_9);
-  __pyx_t_11 = PyTuple_New(6); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_11 = PyTuple_New(6); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 533, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_11);
   __Pyx_INCREF(__pyx_int_0);
   __Pyx_GIVEREF(__pyx_int_0);
@@ -6993,13 +4808,6 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
   __pyx_t_11 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_align.pyx":489
- * 
- * 
- * def compare_prefixes(str ref, str query, bint wildcard_ref=False, bint wildcard_query=False):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Find out whether one string is the prefix of the other one, allowing
- */
 
   /* function exit code */
   __pyx_L1_error:;
@@ -7126,10 +4934,10 @@ static PyMethodDef __pyx_methods_8cutadapt_6_align_Aligner[] = {
 };
 
 static struct PyGetSetDef __pyx_getsets_8cutadapt_6_align_Aligner[] = {
-  {(char *)"min_overlap", __pyx_getprop_8cutadapt_6_align_7Aligner_min_overlap, __pyx_setprop_8cutadapt_6_align_7Aligner_min_overlap, 0, 0},
-  {(char *)"indel_cost", 0, __pyx_setprop_8cutadapt_6_align_7Aligner_indel_cost, __pyx_k_Matches_cost_0_mismatches_cost, 0},
-  {(char *)"reference", __pyx_getprop_8cutadapt_6_align_7Aligner_reference, __pyx_setprop_8cutadapt_6_align_7Aligner_reference, 0, 0},
-  {(char *)"dpmatrix", __pyx_getprop_8cutadapt_6_align_7Aligner_dpmatrix, 0, __pyx_k_The_dynamic_programming_matrix, 0},
+  {(char *)"min_overlap", __pyx_getprop_8cutadapt_6_align_7Aligner_min_overlap, __pyx_setprop_8cutadapt_6_align_7Aligner_min_overlap, (char *)0, 0},
+  {(char *)"indel_cost", 0, __pyx_setprop_8cutadapt_6_align_7Aligner_indel_cost, (char *)"\n\t\tMatches cost 0, mismatches cost 1. Only insertion/deletion costs can be\n\t\tchanged.\n\t\t", 0},
+  {(char *)"reference", __pyx_getprop_8cutadapt_6_align_7Aligner_reference, __pyx_setprop_8cutadapt_6_align_7Aligner_reference, (char *)0, 0},
+  {(char *)"dpmatrix", __pyx_getprop_8cutadapt_6_align_7Aligner_dpmatrix, 0, (char *)"\n\t\tThe dynamic programming matrix as a DPMatrix object. This attribute is\n\t\tusually None, unless debugging has been enabled with enable_debug().\n\t\t", 0},
   {0, 0, 0, 0, 0}
 };
 
@@ -7159,7 +4967,7 @@ static PyTypeObject __pyx_type_8cutadapt_6_align_Aligner = {
   0, /*tp_setattro*/
   0, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
-  "\n\tTODO documentation still uses s1 (reference) and s2 (query).\n\n\tLocate one string within another by computing an optimal semiglobal\n\talignment between string1 and string2.\n\n\tThe alignment uses unit costs, which means that mismatches, insertions and deletions are\n\tcounted as one error.\n\n\tflags is a bitwise 'or' of the allowed flags.\n\tTo allow skipping of a prefix of string1 at no cost, set the\n\tSTART_WITHIN_SEQ1 flag.\n\tTo allow skipping of a prefix of string2 at n [...]
+  "\n\tTODO documentation still uses s1 (reference) and s2 (query).\n\n\tLocate one string within another by computing an optimal semiglobal\n\talignment between string1 and string2.\n\n\tThe alignment uses unit costs, which means that mismatches, insertions and deletions are\n\tcounted as one error.\n\n\tflags is a bitwise 'or' of the allowed flags.\n\tTo allow skipping of a prefix of string1 at no cost, set the\n\tSTART_WITHIN_SEQ1 flag.\n\tTo allow skipping of a prefix of string2 at n [...]
   __pyx_tp_traverse_8cutadapt_6_align_Aligner, /*tp_traverse*/
   __pyx_tp_clear_8cutadapt_6_align_Aligner, /*tp_clear*/
   0, /*tp_richcompare*/
@@ -7659,10 +5467,10 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {0, 0, 0, 0, 0, 0, 0}
 };
 static int __Pyx_InitCachedBuiltins(void) {
-  __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_zip = __Pyx_GetBuiltinName(__pyx_n_s_zip); if (!__pyx_builtin_zip) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 213; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_MemoryError = __Pyx_GetBuiltinName(__pyx_n_s_MemoryError); if (!__pyx_builtin_MemoryError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 98, __pyx_L1_error)
+  __pyx_builtin_zip = __Pyx_GetBuiltinName(__pyx_n_s_zip); if (!__pyx_builtin_zip) __PYX_ERR(0, 113, __pyx_L1_error)
+  __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 214, __pyx_L1_error)
+  __pyx_builtin_MemoryError = __Pyx_GetBuiltinName(__pyx_n_s_MemoryError); if (!__pyx_builtin_MemoryError) __PYX_ERR(0, 235, __pyx_L1_error)
   return 0;
   __pyx_L1_error:;
   return -1;
@@ -7672,188 +5480,76 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0);
 
-  /* "cutadapt/_align.pyx":33
- * 	"""
- * 	d = dict(A=1, C=2, G=4, T=8, U=8)
- * 	t = bytearray(b'\0') * 256             # <<<<<<<<<<<<<<
- * 	for c, v in d.items():
- * 		t[ord(c)] = v
- */
-  __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_b_); if (unlikely(!__pyx_tuple__2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_b_); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 34, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__2);
   __Pyx_GIVEREF(__pyx_tuple__2);
 
-  /* "cutadapt/_align.pyx":73
- * 		N=A|C|G|T
- * 	)
- * 	t = bytearray(b'\0') * 256             # <<<<<<<<<<<<<<
- * 	for c, v in d.items():
- * 		t[ord(c)] = v
- */
-  __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_b_); if (unlikely(!__pyx_tuple__3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_b_); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 74, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__3);
   __Pyx_GIVEREF(__pyx_tuple__3);
 
-  /* "cutadapt/_align.pyx":111
- * 		Return a representation of the matrix as a string.
- * 		"""
- * 		rows = ['     ' + ' '.join(c.rjust(2) for c in self.query)]             # <<<<<<<<<<<<<<
- * 		for c, row in zip(' ' + self.reference, self._rows):
- * 			r = c + ' ' + ' '.join('  ' if v is None else '{0:2d}'.format(v) for v in row)
- */
-  __pyx_tuple__4 = PyTuple_Pack(1, __pyx_int_2); if (unlikely(!__pyx_tuple__4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__4 = PyTuple_Pack(1, __pyx_int_2); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(0, 112, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__4);
   __Pyx_GIVEREF(__pyx_tuple__4);
 
-  /* "cutadapt/_align.pyx":213
- * 		def __set__(self, int value):
- * 			if value < 1:
- * 				raise ValueError('Minimum overlap must be at least 1')             # <<<<<<<<<<<<<<
- * 			self._min_overlap = value
- * 
- */
-  __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_Minimum_overlap_must_be_at_least); if (unlikely(!__pyx_tuple__9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 213; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_Minimum_overlap_must_be_at_least); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 214, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__9);
   __Pyx_GIVEREF(__pyx_tuple__9);
 
-  /* "cutadapt/_align.pyx":223
- * 		def __set__(self, value):
- * 			if value < 1:
- * 				raise ValueError('Insertion/deletion cost must be at leat 1')             # <<<<<<<<<<<<<<
- * 			self._insertion_cost = value
- * 			self._deletion_cost = value
- */
-  __pyx_tuple__10 = PyTuple_Pack(1, __pyx_kp_s_Insertion_deletion_cost_must_be); if (unlikely(!__pyx_tuple__10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__10 = PyTuple_Pack(1, __pyx_kp_s_Insertion_deletion_cost_must_be); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 224, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__10);
   __Pyx_GIVEREF(__pyx_tuple__10);
 
-  /* "cutadapt/_align.pyx":236
- * 				raise MemoryError()
- * 			self.column = mem
- * 			self._reference = reference.encode('ascii')             # <<<<<<<<<<<<<<
- * 			self.m = len(reference)
- * 			if self.wildcard_ref:
- */
-  __pyx_tuple__11 = PyTuple_Pack(1, __pyx_n_s_ascii); if (unlikely(!__pyx_tuple__11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__11 = PyTuple_Pack(1, __pyx_n_s_ascii); if (unlikely(!__pyx_tuple__11)) __PYX_ERR(0, 237, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__11);
   __Pyx_GIVEREF(__pyx_tuple__11);
 
-  /* "cutadapt/_align.pyx":274
- * 		"""
- * 		cdef char* s1 = self._reference
- * 		cdef bytes query_bytes = query.encode('ascii')             # <<<<<<<<<<<<<<
- * 		cdef char* s2 = query_bytes
- * 		cdef int m = self.m
- */
-  __pyx_tuple__12 = PyTuple_Pack(1, __pyx_n_s_ascii); if (unlikely(!__pyx_tuple__12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 274; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__12 = PyTuple_Pack(1, __pyx_n_s_ascii); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(0, 275, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__12);
   __Pyx_GIVEREF(__pyx_tuple__12);
 
-  /* "cutadapt/_align.pyx":501
- * 	cdef int m = len(ref)
- * 	cdef int n = len(query)
- * 	cdef bytes query_bytes = query.encode('ascii')             # <<<<<<<<<<<<<<
- * 	cdef bytes ref_bytes = ref.encode('ascii')
- * 	cdef char* r_ptr
- */
-  __pyx_tuple__13 = PyTuple_Pack(1, __pyx_n_s_ascii); if (unlikely(!__pyx_tuple__13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 501; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__13 = PyTuple_Pack(1, __pyx_n_s_ascii); if (unlikely(!__pyx_tuple__13)) __PYX_ERR(0, 502, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__13);
   __Pyx_GIVEREF(__pyx_tuple__13);
 
-  /* "cutadapt/_align.pyx":502
- * 	cdef int n = len(query)
- * 	cdef bytes query_bytes = query.encode('ascii')
- * 	cdef bytes ref_bytes = ref.encode('ascii')             # <<<<<<<<<<<<<<
- * 	cdef char* r_ptr
- * 	cdef char* q_ptr
- */
-  __pyx_tuple__14 = PyTuple_Pack(1, __pyx_n_s_ascii); if (unlikely(!__pyx_tuple__14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 502; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__14 = PyTuple_Pack(1, __pyx_n_s_ascii); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 503, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__14);
   __Pyx_GIVEREF(__pyx_tuple__14);
 
-  /* "cutadapt/_align.pyx":24
- * 
- * 
- * def _acgt_table():             # <<<<<<<<<<<<<<
- * 	"""
- * 	Return a translation table that maps A, C, G, T characters to the lower
- */
-  __pyx_tuple__15 = PyTuple_Pack(4, __pyx_n_s_d, __pyx_n_s_t, __pyx_n_s_c, __pyx_n_s_v); if (unlikely(!__pyx_tuple__15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__15 = PyTuple_Pack(4, __pyx_n_s_d, __pyx_n_s_t, __pyx_n_s_c, __pyx_n_s_v); if (unlikely(!__pyx_tuple__15)) __PYX_ERR(0, 25, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__15);
   __Pyx_GIVEREF(__pyx_tuple__15);
-  __pyx_codeobj__16 = (PyObject*)__Pyx_PyCode_New(0, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__15, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_acgt_table, 24, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":40
- * 
- * 
- * def _iupac_table():             # <<<<<<<<<<<<<<
- * 	"""
- * 	Return a translation table for IUPAC characters.
- */
-  __pyx_tuple__17 = PyTuple_Pack(8, __pyx_n_s_A, __pyx_n_s_C, __pyx_n_s_G, __pyx_n_s_T, __pyx_n_s_d, __pyx_n_s_t, __pyx_n_s_c, __pyx_n_s_v); if (unlikely(!__pyx_tuple__17)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__16 = (PyObject*)__Pyx_PyCode_New(0, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__15, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_acgt_table, 25, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__16)) __PYX_ERR(0, 25, __pyx_L1_error)
+
+  __pyx_tuple__17 = PyTuple_Pack(8, __pyx_n_s_A, __pyx_n_s_C, __pyx_n_s_G, __pyx_n_s_T, __pyx_n_s_d, __pyx_n_s_t, __pyx_n_s_c, __pyx_n_s_v); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(0, 41, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__17);
   __Pyx_GIVEREF(__pyx_tuple__17);
-  __pyx_codeobj__18 = (PyObject*)__Pyx_PyCode_New(0, 0, 8, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__17, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_iupac_table, 40, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__18)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":94
- * 	computed.
- * 	"""
- * 	def __init__(self, reference, query):             # <<<<<<<<<<<<<<
- * 		m = len(reference)
- * 		n = len(query)
- */
-  __pyx_tuple__20 = PyTuple_Pack(6, __pyx_n_s_self, __pyx_n_s_reference, __pyx_n_s_query, __pyx_n_s_m, __pyx_n_s_n, __pyx_n_s__19); if (unlikely(!__pyx_tuple__20)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__18 = (PyObject*)__Pyx_PyCode_New(0, 0, 8, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__17, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_iupac_table, 41, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__18)) __PYX_ERR(0, 41, __pyx_L1_error)
+
+  __pyx_tuple__20 = PyTuple_Pack(6, __pyx_n_s_self, __pyx_n_s_reference, __pyx_n_s_query, __pyx_n_s_m, __pyx_n_s_n, __pyx_n_s__19); if (unlikely(!__pyx_tuple__20)) __PYX_ERR(0, 95, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__20);
   __Pyx_GIVEREF(__pyx_tuple__20);
-  __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(3, 0, 6, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__20, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_init, 94, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":101
- * 		self.query = query
- * 
- * 	def set_entry(self, int i, int j, cost):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Set an entry in the dynamic programming matrix.
- */
-  __pyx_tuple__22 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_i, __pyx_n_s_j, __pyx_n_s_cost); if (unlikely(!__pyx_tuple__22)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(3, 0, 6, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__20, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_init, 95, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) __PYX_ERR(0, 95, __pyx_L1_error)
+
+  __pyx_tuple__22 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_i, __pyx_n_s_j, __pyx_n_s_cost); if (unlikely(!__pyx_tuple__22)) __PYX_ERR(0, 102, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__22);
   __Pyx_GIVEREF(__pyx_tuple__22);
-  __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(4, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__22, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_set_entry, 101, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":107
- * 		self._rows[i][j] = cost
- * 
- * 	def __str__(self):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Return a representation of the matrix as a string.
- */
-  __pyx_tuple__24 = PyTuple_Pack(8, __pyx_n_s_self, __pyx_n_s_rows_2, __pyx_n_s_c, __pyx_n_s_row, __pyx_n_s_r, __pyx_n_s_genexpr, __pyx_n_s_genexpr, __pyx_n_s_genexpr); if (unlikely(!__pyx_tuple__24)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(4, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__22, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_set_entry, 102, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) __PYX_ERR(0, 102, __pyx_L1_error)
+
+  __pyx_tuple__24 = PyTuple_Pack(8, __pyx_n_s_self, __pyx_n_s_rows_2, __pyx_n_s_c, __pyx_n_s_row, __pyx_n_s_r, __pyx_n_s_genexpr, __pyx_n_s_genexpr, __pyx_n_s_genexpr); if (unlikely(!__pyx_tuple__24)) __PYX_ERR(0, 108, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__24);
   __Pyx_GIVEREF(__pyx_tuple__24);
-  __pyx_codeobj__25 = (PyObject*)__Pyx_PyCode_New(1, 0, 8, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__24, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_str, 107, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__25)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":483
- * 
- * 
- * def locate(str reference, str query, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False, int min_overlap=1):             # <<<<<<<<<<<<<<
- * 	aligner = Aligner(reference, max_error_rate, flags, wildcard_ref, wildcard_query)
- * 	aligner.min_overlap = min_overlap
- */
-  __pyx_tuple__26 = PyTuple_Pack(8, __pyx_n_s_reference, __pyx_n_s_query, __pyx_n_s_max_error_rate, __pyx_n_s_flags, __pyx_n_s_wildcard_ref, __pyx_n_s_wildcard_query, __pyx_n_s_min_overlap, __pyx_n_s_aligner); if (unlikely(!__pyx_tuple__26)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__25 = (PyObject*)__Pyx_PyCode_New(1, 0, 8, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__24, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_str, 108, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__25)) __PYX_ERR(0, 108, __pyx_L1_error)
+
+  __pyx_tuple__26 = PyTuple_Pack(8, __pyx_n_s_reference, __pyx_n_s_query, __pyx_n_s_max_error_rate, __pyx_n_s_flags, __pyx_n_s_wildcard_ref, __pyx_n_s_wildcard_query, __pyx_n_s_min_overlap, __pyx_n_s_aligner); if (unlikely(!__pyx_tuple__26)) __PYX_ERR(0, 484, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__26);
   __Pyx_GIVEREF(__pyx_tuple__26);
-  __pyx_codeobj__27 = (PyObject*)__Pyx_PyCode_New(7, 0, 8, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__26, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_locate, 483, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__27)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_align.pyx":489
- * 
- * 
- * def compare_prefixes(str ref, str query, bint wildcard_ref=False, bint wildcard_query=False):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Find out whether one string is the prefix of the other one, allowing
- */
-  __pyx_tuple__28 = PyTuple_Pack(14, __pyx_n_s_ref, __pyx_n_s_query, __pyx_n_s_wildcard_ref, __pyx_n_s_wildcard_query, __pyx_n_s_m, __pyx_n_s_n, __pyx_n_s_query_bytes, __pyx_n_s_ref_bytes, __pyx_n_s_r_ptr, __pyx_n_s_q_ptr, __pyx_n_s_length, __pyx_n_s_i, __pyx_n_s_matches, __pyx_n_s_compare_ascii); if (unlikely(!__pyx_tuple__28)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__27 = (PyObject*)__Pyx_PyCode_New(7, 0, 8, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__26, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_locate, 484, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__27)) __PYX_ERR(0, 484, __pyx_L1_error)
+
+  __pyx_tuple__28 = PyTuple_Pack(14, __pyx_n_s_ref, __pyx_n_s_query, __pyx_n_s_wildcard_ref, __pyx_n_s_wildcard_query, __pyx_n_s_m, __pyx_n_s_n, __pyx_n_s_query_bytes, __pyx_n_s_ref_bytes, __pyx_n_s_r_ptr, __pyx_n_s_q_ptr, __pyx_n_s_length, __pyx_n_s_i, __pyx_n_s_matches, __pyx_n_s_compare_ascii); if (unlikely(!__pyx_tuple__28)) __PYX_ERR(0, 490, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__28);
   __Pyx_GIVEREF(__pyx_tuple__28);
-  __pyx_codeobj__29 = (PyObject*)__Pyx_PyCode_New(4, 0, 14, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__28, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_compare_prefixes, 489, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__29)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__29 = (PyObject*)__Pyx_PyCode_New(4, 0, 14, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__28, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_compare_prefixes, 490, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__29)) __PYX_ERR(0, 490, __pyx_L1_error)
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -7863,13 +5559,13 @@ static int __Pyx_InitCachedConstants(void) {
 
 static int __Pyx_InitGlobals(void) {
   __pyx_umethod_PyDict_Type_items.type = (PyObject*)&PyDict_Type;
-  if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
-  __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_int_2 = PyInt_FromLong(2); if (unlikely(!__pyx_int_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_int_4 = PyInt_FromLong(4); if (unlikely(!__pyx_int_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_int_8 = PyInt_FromLong(8); if (unlikely(!__pyx_int_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_int_256 = PyInt_FromLong(256); if (unlikely(!__pyx_int_256)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error);
+  __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_int_2 = PyInt_FromLong(2); if (unlikely(!__pyx_int_2)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_int_4 = PyInt_FromLong(4); if (unlikely(!__pyx_int_4)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_int_8 = PyInt_FromLong(8); if (unlikely(!__pyx_int_8)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_int_256 = PyInt_FromLong(256); if (unlikely(!__pyx_int_256)) __PYX_ERR(0, 1, __pyx_L1_error)
   return 0;
   __pyx_L1_error:;
   return -1;
@@ -7886,9 +5582,6 @@ PyMODINIT_FUNC PyInit__align(void)
   PyObject *__pyx_t_1 = NULL;
   PyObject *__pyx_t_2 = NULL;
   PyObject *__pyx_t_3 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannyDeclarations
   #if CYTHON_REFNANNY
   __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny");
@@ -7900,23 +5593,24 @@ PyMODINIT_FUNC PyInit__align(void)
   }
   #endif
   __Pyx_RefNannySetupContext("PyMODINIT_FUNC PyInit__align(void)", 0);
-  if (__Pyx_check_binary_version() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error)
   #ifdef __Pyx_CyFunction_USED
-  if (__pyx_CyFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_CyFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   #ifdef __Pyx_FusedFunction_USED
-  if (__pyx_FusedFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_FusedFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   #ifdef __Pyx_Coroutine_USED
-  if (__pyx_Coroutine_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_Coroutine_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   #ifdef __Pyx_Generator_USED
-  if (__pyx_Generator_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_Generator_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   #ifdef __Pyx_StopAsyncIteration_USED
-  if (__pyx_StopAsyncIteration_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_StopAsyncIteration_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   /*--- Library function declarations ---*/
   /*--- Threads initialization code ---*/
@@ -7931,51 +5625,51 @@ PyMODINIT_FUNC PyInit__align(void)
   #else
   __pyx_m = PyModule_Create(&__pyx_moduledef);
   #endif
-  if (unlikely(!__pyx_m)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error)
   Py_INCREF(__pyx_d);
-  __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error)
   #if CYTHON_COMPILING_IN_PYPY
   Py_INCREF(__pyx_b);
   #endif
-  if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error);
   /*--- Initialize various global constants etc. ---*/
-  if (__Pyx_InitGlobals() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT)
-  if (__Pyx_init_sys_getdefaultencoding_params() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   if (__pyx_module_is_main_cutadapt___align) {
-    if (PyObject_SetAttrString(__pyx_m, "__name__", __pyx_n_s_main) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (PyObject_SetAttrString(__pyx_m, "__name__", __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   }
   #if PY_MAJOR_VERSION >= 3
   {
-    PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error)
     if (!PyDict_GetItemString(modules, "cutadapt._align")) {
-      if (unlikely(PyDict_SetItemString(modules, "cutadapt._align", __pyx_m) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      if (unlikely(PyDict_SetItemString(modules, "cutadapt._align", __pyx_m) < 0)) __PYX_ERR(0, 1, __pyx_L1_error)
     }
   }
   #endif
   /*--- Builtin init code ---*/
-  if (__Pyx_InitCachedBuiltins() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   /*--- Constants init code ---*/
-  if (__Pyx_InitCachedConstants() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   /*--- Global init code ---*/
   __pyx_v_8cutadapt_6_align_ACGT_TABLE = ((PyObject*)Py_None); Py_INCREF(Py_None);
   __pyx_v_8cutadapt_6_align_IUPAC_TABLE = ((PyObject*)Py_None); Py_INCREF(Py_None);
   /*--- Variable export code ---*/
   /*--- Function export code ---*/
   /*--- Type init code ---*/
-  if (PyType_Ready(&__pyx_type_8cutadapt_6_align_Aligner) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_8cutadapt_6_align_Aligner) < 0) __PYX_ERR(0, 119, __pyx_L1_error)
   __pyx_type_8cutadapt_6_align_Aligner.tp_print = 0;
-  if (PyObject_SetAttrString(__pyx_m, "Aligner", (PyObject *)&__pyx_type_8cutadapt_6_align_Aligner) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetAttrString(__pyx_m, "Aligner", (PyObject *)&__pyx_type_8cutadapt_6_align_Aligner) < 0) __PYX_ERR(0, 119, __pyx_L1_error)
   __pyx_ptype_8cutadapt_6_align_Aligner = &__pyx_type_8cutadapt_6_align_Aligner;
-  if (PyType_Ready(&__pyx_type_8cutadapt_6_align___pyx_scope_struct____str__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_8cutadapt_6_align___pyx_scope_struct____str__) < 0) __PYX_ERR(0, 108, __pyx_L1_error)
   __pyx_type_8cutadapt_6_align___pyx_scope_struct____str__.tp_print = 0;
   __pyx_ptype_8cutadapt_6_align___pyx_scope_struct____str__ = &__pyx_type_8cutadapt_6_align___pyx_scope_struct____str__;
-  if (PyType_Ready(&__pyx_type_8cutadapt_6_align___pyx_scope_struct_1_genexpr) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_8cutadapt_6_align___pyx_scope_struct_1_genexpr) < 0) __PYX_ERR(0, 112, __pyx_L1_error)
   __pyx_type_8cutadapt_6_align___pyx_scope_struct_1_genexpr.tp_print = 0;
   __pyx_ptype_8cutadapt_6_align___pyx_scope_struct_1_genexpr = &__pyx_type_8cutadapt_6_align___pyx_scope_struct_1_genexpr;
-  if (PyType_Ready(&__pyx_type_8cutadapt_6_align___pyx_scope_struct_2_genexpr) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_8cutadapt_6_align___pyx_scope_struct_2_genexpr) < 0) __PYX_ERR(0, 114, __pyx_L1_error)
   __pyx_type_8cutadapt_6_align___pyx_scope_struct_2_genexpr.tp_print = 0;
   __pyx_ptype_8cutadapt_6_align___pyx_scope_struct_2_genexpr = &__pyx_type_8cutadapt_6_align___pyx_scope_struct_2_genexpr;
   /*--- Type import code ---*/
@@ -7983,41 +5677,20 @@ PyMODINIT_FUNC PyInit__align(void)
   /*--- Function import code ---*/
   /*--- Execution code ---*/
   #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
-  if (__Pyx_patch_abc() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
 
-  /* "cutadapt/_align.pyx":24
- * 
- * 
- * def _acgt_table():             # <<<<<<<<<<<<<<
- * 	"""
- * 	Return a translation table that maps A, C, G, T characters to the lower
- */
-  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_1_acgt_table, NULL, __pyx_n_s_cutadapt__align); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_1_acgt_table, NULL, __pyx_n_s_cutadapt__align); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 25, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_acgt_table, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_acgt_table, __pyx_t_1) < 0) __PYX_ERR(0, 25, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":40
- * 
- * 
- * def _iupac_table():             # <<<<<<<<<<<<<<
- * 	"""
- * 	Return a translation table for IUPAC characters.
- */
-  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_3_iupac_table, NULL, __pyx_n_s_cutadapt__align); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_3_iupac_table, NULL, __pyx_n_s_cutadapt__align); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 41, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_iupac_table, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_iupac_table, __pyx_t_1) < 0) __PYX_ERR(0, 41, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":80
- * 
- * 
- * cdef bytes ACGT_TABLE = _acgt_table()             # <<<<<<<<<<<<<<
- * cdef bytes IUPAC_TABLE = _iupac_table()
- * 
- */
-  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_acgt_table); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 80; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_acgt_table); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 81, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __pyx_t_3 = NULL;
   if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_2))) {
@@ -8030,27 +5703,20 @@ PyMODINIT_FUNC PyInit__align(void)
     }
   }
   if (__pyx_t_3) {
-    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 80; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 81, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   } else {
-    __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 80; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 81, __pyx_L1_error)
   }
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  if (!(likely(PyBytes_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 80; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyBytes_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(0, 81, __pyx_L1_error)
   __Pyx_XGOTREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
   __Pyx_DECREF_SET(__pyx_v_8cutadapt_6_align_ACGT_TABLE, ((PyObject*)__pyx_t_1));
   __Pyx_GIVEREF(__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":81
- * 
- * cdef bytes ACGT_TABLE = _acgt_table()
- * cdef bytes IUPAC_TABLE = _iupac_table()             # <<<<<<<<<<<<<<
- * 
- * 
- */
-  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_iupac_table); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 81; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_iupac_table); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 82, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __pyx_t_3 = NULL;
   if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_2))) {
@@ -8063,110 +5729,56 @@ PyMODINIT_FUNC PyInit__align(void)
     }
   }
   if (__pyx_t_3) {
-    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 81; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   } else {
-    __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 81; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error)
   }
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  if (!(likely(PyBytes_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 81; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyBytes_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(0, 82, __pyx_L1_error)
   __Pyx_XGOTREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
   __Pyx_DECREF_SET(__pyx_v_8cutadapt_6_align_IUPAC_TABLE, ((PyObject*)__pyx_t_1));
   __Pyx_GIVEREF(__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":84
- * 
- * 
- * class DPMatrix:             # <<<<<<<<<<<<<<
- * 	"""
- * 	Representation of the dynamic-programming matrix.
- */
-  __pyx_t_1 = __Pyx_Py3MetaclassPrepare((PyObject *) NULL, __pyx_empty_tuple, __pyx_n_s_DPMatrix, __pyx_n_s_DPMatrix, (PyObject *) NULL, __pyx_n_s_cutadapt__align, __pyx_kp_s_Representation_of_the_dynamic_p); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_Py3MetaclassPrepare((PyObject *) NULL, __pyx_empty_tuple, __pyx_n_s_DPMatrix, __pyx_n_s_DPMatrix, (PyObject *) NULL, __pyx_n_s_cutadapt__align, __pyx_kp_s_Representation_of_the_dynamic_p); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 85, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
 
-  /* "cutadapt/_align.pyx":94
- * 	computed.
- * 	"""
- * 	def __init__(self, reference, query):             # <<<<<<<<<<<<<<
- * 		m = len(reference)
- * 		n = len(query)
- */
-  __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_8DPMatrix_1__init__, 0, __pyx_n_s_DPMatrix___init, NULL, __pyx_n_s_cutadapt__align, __pyx_d, ((PyObject *)__pyx_codeobj__21)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_8DPMatrix_1__init__, 0, __pyx_n_s_DPMatrix___init, NULL, __pyx_n_s_cutadapt__align, __pyx_d, ((PyObject *)__pyx_codeobj__21)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 95, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyObject_SetItem(__pyx_t_1, __pyx_n_s_init, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetItem(__pyx_t_1, __pyx_n_s_init, __pyx_t_2) < 0) __PYX_ERR(0, 95, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":101
- * 		self.query = query
- * 
- * 	def set_entry(self, int i, int j, cost):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Set an entry in the dynamic programming matrix.
- */
-  __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_8DPMatrix_3set_entry, 0, __pyx_n_s_DPMatrix_set_entry, NULL, __pyx_n_s_cutadapt__align, __pyx_d, ((PyObject *)__pyx_codeobj__23)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_8DPMatrix_3set_entry, 0, __pyx_n_s_DPMatrix_set_entry, NULL, __pyx_n_s_cutadapt__align, __pyx_d, ((PyObject *)__pyx_codeobj__23)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 102, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyObject_SetItem(__pyx_t_1, __pyx_n_s_set_entry, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetItem(__pyx_t_1, __pyx_n_s_set_entry, __pyx_t_2) < 0) __PYX_ERR(0, 102, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":107
- * 		self._rows[i][j] = cost
- * 
- * 	def __str__(self):             # <<<<<<<<<<<<<<
- * 		"""
- * 		Return a representation of the matrix as a string.
- */
-  __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_8DPMatrix_5__str__, 0, __pyx_n_s_DPMatrix___str, NULL, __pyx_n_s_cutadapt__align, __pyx_d, ((PyObject *)__pyx_codeobj__25)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_8DPMatrix_5__str__, 0, __pyx_n_s_DPMatrix___str, NULL, __pyx_n_s_cutadapt__align, __pyx_d, ((PyObject *)__pyx_codeobj__25)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 108, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyObject_SetItem(__pyx_t_1, __pyx_n_s_str, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetItem(__pyx_t_1, __pyx_n_s_str, __pyx_t_2) < 0) __PYX_ERR(0, 108, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_align.pyx":84
- * 
- * 
- * class DPMatrix:             # <<<<<<<<<<<<<<
- * 	"""
- * 	Representation of the dynamic-programming matrix.
- */
-  __pyx_t_2 = __Pyx_Py3ClassCreate(((PyObject*)&__Pyx_DefaultClassType), __pyx_n_s_DPMatrix, __pyx_empty_tuple, __pyx_t_1, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_Py3ClassCreate(((PyObject*)&__Pyx_DefaultClassType), __pyx_n_s_DPMatrix, __pyx_empty_tuple, __pyx_t_1, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 85, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_DPMatrix, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_DPMatrix, __pyx_t_2) < 0) __PYX_ERR(0, 85, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":483
- * 
- * 
- * def locate(str reference, str query, double max_error_rate, int flags=SEMIGLOBAL, bint wildcard_ref=False, bint wildcard_query=False, int min_overlap=1):             # <<<<<<<<<<<<<<
- * 	aligner = Aligner(reference, max_error_rate, flags, wildcard_ref, wildcard_query)
- * 	aligner.min_overlap = min_overlap
- */
-  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_5locate, NULL, __pyx_n_s_cutadapt__align); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_5locate, NULL, __pyx_n_s_cutadapt__align); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 484, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_locate, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 483; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_locate, __pyx_t_1) < 0) __PYX_ERR(0, 484, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":489
- * 
- * 
- * def compare_prefixes(str ref, str query, bint wildcard_ref=False, bint wildcard_query=False):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Find out whether one string is the prefix of the other one, allowing
- */
-  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_7compare_prefixes, NULL, __pyx_n_s_cutadapt__align); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_6_align_7compare_prefixes, NULL, __pyx_n_s_cutadapt__align); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 490, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_compare_prefixes, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 489; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_compare_prefixes, __pyx_t_1) < 0) __PYX_ERR(0, 490, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_align.pyx":1
- * from cpython.mem cimport PyMem_Malloc, PyMem_Free, PyMem_Realloc             # <<<<<<<<<<<<<<
- * 
- * DEF START_WITHIN_SEQ1 = 1
- */
-  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
   /*--- Wrapped vars code ---*/
@@ -8194,6 +5806,7 @@ PyMODINIT_FUNC PyInit__align(void)
 }
 
 /* --- Runtime support code --- */
+/* Refnanny */
 #if CYTHON_REFNANNY
 static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) {
     PyObject *m = NULL, *p = NULL;
@@ -8210,6 +5823,7 @@ end:
 }
 #endif
 
+/* GetBuiltinName */
 static PyObject *__Pyx_GetBuiltinName(PyObject *name) {
     PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name);
     if (unlikely(!result)) {
@@ -8223,6 +5837,7 @@ static PyObject *__Pyx_GetBuiltinName(PyObject *name) {
     return result;
 }
 
+/* PyObjectCall */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) {
     PyObject *result;
@@ -8242,6 +5857,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg
 }
 #endif
 
+/* UnpackUnboundCMethod */
 static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) {
     PyObject *method;
     method = __Pyx_PyObject_GetAttrStr(target->type, *target->method_name);
@@ -8261,6 +5877,7 @@ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) {
     return 0;
 }
 
+/* CallUnboundCMethod0 */
 static PyObject* __Pyx__CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObject* self) {
     PyObject *args, *result = NULL;
     if (unlikely(!cfunc->method) && unlikely(__Pyx_TryUnpackUnboundCMethod(cfunc) < 0)) return NULL;
@@ -8279,6 +5896,7 @@ bad:
     return result;
 }
 
+/* py_dict_items */
 static CYTHON_INLINE PyObject* __Pyx_PyDict_Items(PyObject* d) {
     if (PY_MAJOR_VERSION >= 3)
         return __Pyx_CallUnboundCMethod0(&__pyx_umethod_PyDict_Type_items, d);
@@ -8286,17 +5904,20 @@ static CYTHON_INLINE PyObject* __Pyx_PyDict_Items(PyObject* d) {
         return PyDict_Items(d);
 }
 
+/* RaiseTooManyValuesToUnpack */
 static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) {
     PyErr_Format(PyExc_ValueError,
                  "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected);
 }
 
+/* RaiseNeedMoreValuesToUnpack */
 static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
     PyErr_Format(PyExc_ValueError,
                  "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack",
                  index, (index == 1) ? "" : "s");
 }
 
+/* IterFinish */
 static CYTHON_INLINE int __Pyx_IterFinish(void) {
 #if CYTHON_COMPILING_IN_CPYTHON
     PyThreadState *tstate = PyThreadState_GET();
@@ -8331,6 +5952,7 @@ static CYTHON_INLINE int __Pyx_IterFinish(void) {
 #endif
 }
 
+/* UnpackItemEndCheck */
 static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {
     if (unlikely(retval)) {
         Py_DECREF(retval);
@@ -8342,6 +5964,7 @@ static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {
     return 0;
 }
 
+/* UnicodeAsUCS4 */
 static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject* x) {
    Py_ssize_t length;
    #if CYTHON_PEP393_ENABLED
@@ -8372,6 +5995,7 @@ static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject* x) {
    return (Py_UCS4)-1;
 }
 
+/* object_ord */
 static long __Pyx__PyObject_Ord(PyObject* c) {
     Py_ssize_t size;
     if (PyBytes_Check(c)) {
@@ -8400,6 +6024,7 @@ static long __Pyx__PyObject_Ord(PyObject* c) {
     return (long)(Py_UCS4)-1;
 }
 
+/* SetItemIntByteArray */
 static CYTHON_INLINE int __Pyx_SetItemInt_ByteArray_Fast(PyObject* string, Py_ssize_t i, unsigned char v,
                                                          int wraparound, int boundscheck) {
     Py_ssize_t length;
@@ -8419,6 +6044,7 @@ static CYTHON_INLINE int __Pyx_SetItemInt_ByteArray_Fast(PyObject* string, Py_ss
     }
 }
 
+/* PyObjectCallMethO */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) {
     PyObject *self, *result;
@@ -8438,6 +6064,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject
 }
 #endif
 
+/* PyObjectCallOneArg */
 #if CYTHON_COMPILING_IN_CPYTHON
 static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) {
     PyObject *result;
@@ -8472,7 +6099,8 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
 }
 #endif
 
-#if CYTHON_COMPILING_IN_CPYTHON
+/* PyObjectCallNoArg */
+  #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
 #ifdef __Pyx_CyFunction_USED
     if (likely(PyCFunction_Check(func) || PyObject_TypeCheck(func, __pyx_CyFunctionType))) {
@@ -8487,7 +6115,8 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
 }
 #endif
 
-static void __Pyx_RaiseArgtupleInvalid(
+/* RaiseArgTupleInvalid */
+    static void __Pyx_RaiseArgtupleInvalid(
     const char* func_name,
     int exact,
     Py_ssize_t num_min,
@@ -8512,7 +6141,8 @@ static void __Pyx_RaiseArgtupleInvalid(
                  (num_expected == 1) ? "" : "s", num_found);
 }
 
-static void __Pyx_RaiseDoubleKeywordsError(
+/* RaiseDoubleKeywords */
+    static void __Pyx_RaiseDoubleKeywordsError(
     const char* func_name,
     PyObject* kw_name)
 {
@@ -8525,7 +6155,8 @@ static void __Pyx_RaiseDoubleKeywordsError(
         #endif
 }
 
-static int __Pyx_ParseOptionalKeywords(
+/* ParseKeywords */
+    static int __Pyx_ParseOptionalKeywords(
     PyObject *kwds,
     PyObject **argnames[],
     PyObject *kwds2,
@@ -8626,11 +6257,8 @@ bad:
     return -1;
 }
 
-#if CYTHON_USE_PYLONG_INTERNALS
-  #include "longintrepr.h"
-#endif
-
-#if CYTHON_COMPILING_IN_CPYTHON
+/* PyIntBinop */
+    #if CYTHON_COMPILING_IN_CPYTHON
 static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) {
     #if PY_MAJOR_VERSION < 3
     if (likely(PyInt_CheckExact(op1))) {
@@ -8727,7 +6355,8 @@ static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED
 }
 #endif
 
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
+/* GetItemInt */
+    static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
     PyObject *r;
     if (!j) return NULL;
     r = PyObject_GetItem(o, j);
@@ -8791,10 +6420,9 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
                 if (likely(l >= 0)) {
                     i += l;
                 } else {
-                    if (PyErr_ExceptionMatches(PyExc_OverflowError))
-                        PyErr_Clear();
-                    else
+                    if (!PyErr_ExceptionMatches(PyExc_OverflowError))
                         return NULL;
+                    PyErr_Clear();
                 }
             }
             return m->sq_item(o, i);
@@ -8808,7 +6436,8 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
     return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
 }
 
-static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
+/* SetItemInt */
+    static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
     int r;
     if (!j) return -1;
     r = PyObject_SetItem(o, j, v);
@@ -8835,10 +6464,9 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
                 if (likely(l >= 0)) {
                     i += l;
                 } else {
-                    if (PyErr_ExceptionMatches(PyExc_OverflowError))
-                        PyErr_Clear();
-                    else
+                    if (!PyErr_ExceptionMatches(PyExc_OverflowError))
                         return -1;
+                    PyErr_Clear();
                 }
             }
             return m->sq_ass_item(o, i, v);
@@ -8856,17 +6484,20 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
     return __Pyx_SetItemInt_Generic(o, PyInt_FromSsize_t(i), v);
 }
 
-static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname) {
+/* None */
+      static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname) {
     PyErr_Format(PyExc_NameError, "free variable '%s' referenced before assignment in enclosing scope", varname);
 }
 
-#if !CYTHON_COMPILING_IN_CPYTHON
+/* StringJoin */
+      #if !CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyBytes_Join(PyObject* sep, PyObject* values) {
     return PyObject_CallMethodObjArgs(sep, __pyx_n_s_join, values, NULL);
 }
 #endif
 
-static void __Pyx_RaiseArgumentTypeInvalid(const char* name, PyObject *obj, PyTypeObject *type) {
+/* ArgTypeTest */
+      static void __Pyx_RaiseArgumentTypeInvalid(const char* name, PyObject *obj, PyTypeObject *type) {
     PyErr_Format(PyExc_TypeError,
         "Argument '%.200s' has incorrect type (expected %.200s, got %.200s)",
         name, type->tp_name, Py_TYPE(obj)->tp_name);
@@ -8892,10 +6523,10 @@ static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, in
     return 0;
 }
 
-static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
-#if CYTHON_COMPILING_IN_CPYTHON
+/* PyErrFetchRestore */
+      #if CYTHON_COMPILING_IN_CPYTHON
+static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) {
     PyObject *tmp_type, *tmp_value, *tmp_tb;
-    PyThreadState *tstate = PyThreadState_GET();
     tmp_type = tstate->curexc_type;
     tmp_value = tstate->curexc_value;
     tmp_tb = tstate->curexc_traceback;
@@ -8905,27 +6536,22 @@ static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyOb
     Py_XDECREF(tmp_type);
     Py_XDECREF(tmp_value);
     Py_XDECREF(tmp_tb);
-#else
-    PyErr_Restore(type, value, tb);
-#endif
 }
-static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
-#if CYTHON_COMPILING_IN_CPYTHON
-    PyThreadState *tstate = PyThreadState_GET();
+static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
     *type = tstate->curexc_type;
     *value = tstate->curexc_value;
     *tb = tstate->curexc_traceback;
     tstate->curexc_type = 0;
     tstate->curexc_value = 0;
     tstate->curexc_traceback = 0;
-#else
-    PyErr_Fetch(type, value, tb);
-#endif
 }
+#endif
 
-#if PY_MAJOR_VERSION < 3
+/* RaiseException */
+      #if PY_MAJOR_VERSION < 3
 static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb,
                         CYTHON_UNUSED PyObject *cause) {
+    __Pyx_PyThreadState_declare
     Py_XINCREF(type);
     if (!value || value == Py_None)
         value = NULL;
@@ -8964,6 +6590,7 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb,
             goto raise_error;
         }
     }
+    __Pyx_PyThreadState_assign
     __Pyx_ErrRestore(type, value, tb);
     return;
 raise_error:
@@ -9083,7 +6710,8 @@ bad:
 }
 #endif
 
-static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) {
+/* GetModuleGlobalName */
+        static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) {
     PyObject *result;
 #if CYTHON_COMPILING_IN_CPYTHON
     result = PyDict_GetItem(__pyx_d, name);
@@ -9100,7 +6728,8 @@ static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) {
     return result;
 }
 
-static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) {
+/* FetchCommonType */
+          static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) {
     PyObject* fake_module;
     PyTypeObject* cached_type = NULL;
     fake_module = PyImport_AddModule((char*) "_cython_" CYTHON_ABI);
@@ -9138,7 +6767,8 @@ bad:
     goto done;
 }
 
-static PyObject *
+/* CythonFunction */
+          static PyObject *
 __Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *closure)
 {
     if (unlikely(op->func_doc == NULL)) {
@@ -9493,7 +7123,7 @@ __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m)
         int i;
         for (i = 0; i < m->defaults_pyobjects; i++)
             Py_XDECREF(pydefaults[i]);
-        PyMem_Free(m->defaults);
+        PyObject_Free(m->defaults);
         m->defaults = NULL;
     }
     return 0;
@@ -9681,7 +7311,7 @@ static int __pyx_CyFunction_init(void) {
 }
 static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) {
     __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func;
-    m->defaults = PyMem_Malloc(size);
+    m->defaults = PyObject_Malloc(size);
     if (!m->defaults)
         return PyErr_NoMemory();
     memset(m->defaults, 0, size);
@@ -9704,7 +7334,8 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, Py
     Py_INCREF(dict);
 }
 
-static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases) {
+/* CalculateMetaclass */
+              static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases) {
     Py_ssize_t i, nbases = PyTuple_GET_SIZE(bases);
     for (i=0; i < nbases; i++) {
         PyTypeObject *tmptype;
@@ -9742,7 +7373,8 @@ static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bas
     return (PyObject*) metaclass;
 }
 
-static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name,
+/* Py3ClassCreate */
+              static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name,
                                            PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) {
     PyObject *ns;
     if (metaclass) {
@@ -9808,7 +7440,8 @@ static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObj
     return result;
 }
 
-static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
+/* CodeObjectCache */
+              static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
     int start = 0, mid = 0, end = count - 1;
     if (end >= 0 && code_line > entries[end].code_line) {
         return count;
@@ -9887,7 +7520,8 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) {
     Py_INCREF(code_object);
 }
 
-#include "compile.h"
+/* AddTraceback */
+              #include "compile.h"
 #include "frameobject.h"
 #include "traceback.h"
 static PyCodeObject* __Pyx_CreateCodeObjectForTraceback(
@@ -9967,7 +7601,8 @@ bad:
     Py_XDECREF(py_frame);
 }
 
-#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
+/* CIntFromPyVerify */
+              #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
     __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0)
 #define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\
     __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1)
@@ -9988,7 +7623,62 @@ bad:
         return (target_type) value;\
     }
 
-static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
+/* CIntToPy */
+              static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
+    const long neg_one = (long) -1, const_zero = (long) 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (is_unsigned) {
+        if (sizeof(long) < sizeof(long)) {
+            return PyInt_FromLong((long) value);
+        } else if (sizeof(long) <= sizeof(unsigned long)) {
+            return PyLong_FromUnsignedLong((unsigned long) value);
+        } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
+            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
+        }
+    } else {
+        if (sizeof(long) <= sizeof(long)) {
+            return PyInt_FromLong((long) value);
+        } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
+            return PyLong_FromLongLong((PY_LONG_LONG) value);
+        }
+    }
+    {
+        int one = 1; int little = (int)*(unsigned char *)&one;
+        unsigned char *bytes = (unsigned char *)&value;
+        return _PyLong_FromByteArray(bytes, sizeof(long),
+                                     little, !is_unsigned);
+    }
+}
+
+/* CIntToPy */
+              static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
+    const int neg_one = (int) -1, const_zero = (int) 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (is_unsigned) {
+        if (sizeof(int) < sizeof(long)) {
+            return PyInt_FromLong((long) value);
+        } else if (sizeof(int) <= sizeof(unsigned long)) {
+            return PyLong_FromUnsignedLong((unsigned long) value);
+        } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
+            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
+        }
+    } else {
+        if (sizeof(int) <= sizeof(long)) {
+            return PyInt_FromLong((long) value);
+        } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
+            return PyLong_FromLongLong((PY_LONG_LONG) value);
+        }
+    }
+    {
+        int one = 1; int little = (int)*(unsigned char *)&one;
+        unsigned char *bytes = (unsigned char *)&value;
+        return _PyLong_FromByteArray(bytes, sizeof(int),
+                                     little, !is_unsigned);
+    }
+}
+
+/* CIntFromPy */
+              static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
     const int neg_one = (int) -1, const_zero = (int) 0;
     const int is_unsigned = neg_one > const_zero;
 #if PY_MAJOR_VERSION < 3
@@ -10063,7 +7753,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
             const digit* digits = ((PyLongObject*)x)->ob_digit;
             switch (Py_SIZE(x)) {
                 case  0: return (int) 0;
-                case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, -(sdigit) digits[0])
+                case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0]))
                 case  1: __PYX_VERIFY_RETURN_INT(int,  digit, +digits[0])
                 case -2:
                     if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) {
@@ -10133,7 +7823,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
                             "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers");
 #else
             int val;
-            PyObject *v = __Pyx_PyNumber_Int(x);
+            PyObject *v = __Pyx_PyNumber_IntOrLong(x);
  #if PY_MAJOR_VERSION < 3
             if (likely(v) && !PyLong_Check(v)) {
                 PyObject *tmp = v;
@@ -10156,7 +7846,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
         }
     } else {
         int val;
-        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        PyObject *tmp = __Pyx_PyNumber_IntOrLong(x);
         if (!tmp) return (int) -1;
         val = __Pyx_PyInt_As_int(tmp);
         Py_DECREF(tmp);
@@ -10172,33 +7862,8 @@ raise_neg_overflow:
     return (int) -1;
 }
 
-static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
-    const long neg_one = (long) -1, const_zero = (long) 0;
-    const int is_unsigned = neg_one > const_zero;
-    if (is_unsigned) {
-        if (sizeof(long) < sizeof(long)) {
-            return PyInt_FromLong((long) value);
-        } else if (sizeof(long) <= sizeof(unsigned long)) {
-            return PyLong_FromUnsignedLong((unsigned long) value);
-        } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
-            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
-        }
-    } else {
-        if (sizeof(long) <= sizeof(long)) {
-            return PyInt_FromLong((long) value);
-        } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
-            return PyLong_FromLongLong((PY_LONG_LONG) value);
-        }
-    }
-    {
-        int one = 1; int little = (int)*(unsigned char *)&one;
-        unsigned char *bytes = (unsigned char *)&value;
-        return _PyLong_FromByteArray(bytes, sizeof(long),
-                                     little, !is_unsigned);
-    }
-}
-
-static CYTHON_INLINE unsigned char __Pyx_PyInt_As_unsigned_char(PyObject *x) {
+/* CIntFromPy */
+              static CYTHON_INLINE unsigned char __Pyx_PyInt_As_unsigned_char(PyObject *x) {
     const unsigned char neg_one = (unsigned char) -1, const_zero = (unsigned char) 0;
     const int is_unsigned = neg_one > const_zero;
 #if PY_MAJOR_VERSION < 3
@@ -10273,7 +7938,7 @@ static CYTHON_INLINE unsigned char __Pyx_PyInt_As_unsigned_char(PyObject *x) {
             const digit* digits = ((PyLongObject*)x)->ob_digit;
             switch (Py_SIZE(x)) {
                 case  0: return (unsigned char) 0;
-                case -1: __PYX_VERIFY_RETURN_INT(unsigned char, sdigit, -(sdigit) digits[0])
+                case -1: __PYX_VERIFY_RETURN_INT(unsigned char, sdigit, (sdigit) (-(sdigit)digits[0]))
                 case  1: __PYX_VERIFY_RETURN_INT(unsigned char,  digit, +digits[0])
                 case -2:
                     if (8 * sizeof(unsigned char) - 1 > 1 * PyLong_SHIFT) {
@@ -10343,7 +8008,7 @@ static CYTHON_INLINE unsigned char __Pyx_PyInt_As_unsigned_char(PyObject *x) {
                             "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers");
 #else
             unsigned char val;
-            PyObject *v = __Pyx_PyNumber_Int(x);
+            PyObject *v = __Pyx_PyNumber_IntOrLong(x);
  #if PY_MAJOR_VERSION < 3
             if (likely(v) && !PyLong_Check(v)) {
                 PyObject *tmp = v;
@@ -10366,7 +8031,7 @@ static CYTHON_INLINE unsigned char __Pyx_PyInt_As_unsigned_char(PyObject *x) {
         }
     } else {
         unsigned char val;
-        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        PyObject *tmp = __Pyx_PyNumber_IntOrLong(x);
         if (!tmp) return (unsigned char) -1;
         val = __Pyx_PyInt_As_unsigned_char(tmp);
         Py_DECREF(tmp);
@@ -10382,33 +8047,8 @@ raise_neg_overflow:
     return (unsigned char) -1;
 }
 
-static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
-    const int neg_one = (int) -1, const_zero = (int) 0;
-    const int is_unsigned = neg_one > const_zero;
-    if (is_unsigned) {
-        if (sizeof(int) < sizeof(long)) {
-            return PyInt_FromLong((long) value);
-        } else if (sizeof(int) <= sizeof(unsigned long)) {
-            return PyLong_FromUnsignedLong((unsigned long) value);
-        } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
-            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
-        }
-    } else {
-        if (sizeof(int) <= sizeof(long)) {
-            return PyInt_FromLong((long) value);
-        } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
-            return PyLong_FromLongLong((PY_LONG_LONG) value);
-        }
-    }
-    {
-        int one = 1; int little = (int)*(unsigned char *)&one;
-        unsigned char *bytes = (unsigned char *)&value;
-        return _PyLong_FromByteArray(bytes, sizeof(int),
-                                     little, !is_unsigned);
-    }
-}
-
-static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
+/* CIntFromPy */
+              static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
     const long neg_one = (long) -1, const_zero = (long) 0;
     const int is_unsigned = neg_one > const_zero;
 #if PY_MAJOR_VERSION < 3
@@ -10483,7 +8123,7 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
             const digit* digits = ((PyLongObject*)x)->ob_digit;
             switch (Py_SIZE(x)) {
                 case  0: return (long) 0;
-                case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, -(sdigit) digits[0])
+                case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0]))
                 case  1: __PYX_VERIFY_RETURN_INT(long,  digit, +digits[0])
                 case -2:
                     if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) {
@@ -10553,7 +8193,7 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
                             "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers");
 #else
             long val;
-            PyObject *v = __Pyx_PyNumber_Int(x);
+            PyObject *v = __Pyx_PyNumber_IntOrLong(x);
  #if PY_MAJOR_VERSION < 3
             if (likely(v) && !PyLong_Check(v)) {
                 PyObject *tmp = v;
@@ -10576,7 +8216,7 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
         }
     } else {
         long val;
-        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        PyObject *tmp = __Pyx_PyNumber_IntOrLong(x);
         if (!tmp) return (long) -1;
         val = __Pyx_PyInt_As_long(tmp);
         Py_DECREF(tmp);
@@ -10592,26 +8232,33 @@ raise_neg_overflow:
     return (long) -1;
 }
 
-static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) {
+/* SwapException */
+              #if CYTHON_COMPILING_IN_CPYTHON
+static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
     PyObject *tmp_type, *tmp_value, *tmp_tb;
-#if CYTHON_COMPILING_IN_CPYTHON
-    PyThreadState *tstate = PyThreadState_GET();
     tmp_type = tstate->exc_type;
     tmp_value = tstate->exc_value;
     tmp_tb = tstate->exc_traceback;
     tstate->exc_type = *type;
     tstate->exc_value = *value;
     tstate->exc_traceback = *tb;
+    *type = tmp_type;
+    *value = tmp_value;
+    *tb = tmp_tb;
+}
 #else
+static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) {
+    PyObject *tmp_type, *tmp_value, *tmp_tb;
     PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb);
     PyErr_SetExcInfo(*type, *value, *tb);
-#endif
     *type = tmp_type;
     *value = tmp_value;
     *tb = tmp_tb;
 }
+#endif
 
-static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) {
+/* PyObjectCallMethod1 */
+              static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) {
     PyObject *method, *result = NULL;
     method = __Pyx_PyObject_GetAttrStr(obj, method_name);
     if (unlikely(!method)) goto bad;
@@ -10642,7 +8289,8 @@ bad:
     return result;
 }
 
-#include <structmember.h>
+/* CoroutineBase */
+              #include <structmember.h>
 #include <frameobject.h>
 static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value);
 static PyObject *__Pyx_Coroutine_Close(PyObject *self);
@@ -10652,6 +8300,8 @@ static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args);
 static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
     PyObject *et, *ev, *tb;
     PyObject *value = NULL;
+    __Pyx_PyThreadState_declare
+    __Pyx_PyThreadState_assign
     __Pyx_ErrFetch(&et, &ev, &tb);
     if (!et) {
         Py_XDECREF(tb);
@@ -10756,6 +8406,7 @@ int __Pyx_Coroutine_CheckRunning(__pyx_CoroutineObject *gen) {
 static CYTHON_INLINE
 PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
     PyObject *retval;
+    __Pyx_PyThreadState_declare
     assert(!self->is_running);
     if (unlikely(self->resume_label == 0)) {
         if (unlikely(value && value != Py_None)) {
@@ -10769,16 +8420,16 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
         PyErr_SetNone(PyExc_StopIteration);
         return NULL;
     }
+    __Pyx_PyThreadState_assign
     if (value) {
 #if CYTHON_COMPILING_IN_PYPY
 #else
         if (self->exc_traceback) {
-            PyThreadState *tstate = PyThreadState_GET();
             PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback;
             PyFrameObject *f = tb->tb_frame;
-            Py_XINCREF(tstate->frame);
+            Py_XINCREF(__pyx_tstate->frame);
             assert(f->f_back == NULL);
-            f->f_back = tstate->frame;
+            f->f_back = __pyx_tstate->frame;
         }
 #endif
         __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value,
@@ -10843,7 +8494,7 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
         #endif
         {
             if (value == Py_None)
-                ret = PyIter_Next(yf);
+                ret = Py_TYPE(yf)->tp_iternext(yf);
             else
                 ret = __Pyx_PyObject_CallMethod1(yf, __pyx_n_s_send, value);
         }
@@ -11052,12 +8703,14 @@ static void __Pyx_Coroutine_del(PyObject *self) {
     PyObject *res;
     PyObject *error_type, *error_value, *error_traceback;
     __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self;
+    __Pyx_PyThreadState_declare
     if (gen->resume_label <= 0)
         return ;
 #if PY_VERSION_HEX < 0x030400a1
     assert(self->ob_refcnt == 0);
     self->ob_refcnt = 1;
 #endif
+    __Pyx_PyThreadState_assign
     __Pyx_ErrFetch(&error_type, &error_value, &error_traceback);
     res = __Pyx_Coroutine_Close(self);
     if (res == NULL)
@@ -11160,7 +8813,8 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject* type, __pyx_cor
     return gen;
 }
 
-static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) {
+/* PatchModuleWithCoroutine */
+                  static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) {
 #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
     int result;
     PyObject *globals, *result_obj;
@@ -11199,7 +8853,8 @@ ignore:
     return module;
 }
 
-#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
+/* PatchGeneratorABC */
+                  #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
 static PyObject* __Pyx_patch_abc_module(PyObject *module);
 static PyObject* __Pyx_patch_abc_module(PyObject *module) {
     module = __Pyx_Coroutine_patch_module(
@@ -11252,7 +8907,8 @@ static int __Pyx_patch_abc(void) {
     return 0;
 }
 
-static PyMethodDef __pyx_Generator_methods[] = {
+/* Generator */
+                  static PyMethodDef __pyx_Generator_methods[] = {
     {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O,
      (char*) PyDoc_STR("send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")},
     {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS,
@@ -11340,7 +8996,8 @@ static int __pyx_Generator_init(void) {
     return 0;
 }
 
-static int __Pyx_check_binary_version(void) {
+/* CheckBinaryVersion */
+                  static int __Pyx_check_binary_version(void) {
     char ctversion[4], rtversion[4];
     PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION);
     PyOS_snprintf(rtversion, 4, "%s", Py_GetVersion());
@@ -11355,7 +9012,8 @@ static int __Pyx_check_binary_version(void) {
     return 0;
 }
 
-static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
+/* InitStrings */
+                  static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
     while (t->p) {
         #if PY_MAJOR_VERSION < 3
         if (t->is_unicode) {
@@ -11455,7 +9113,7 @@ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
    if (is_true | (x == Py_False) | (x == Py_None)) return is_true;
    else return PyObject_IsTrue(x);
 }
-static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
   PyNumberMethods *m;
   const char *name = NULL;
   PyObject *res = NULL;
diff --git a/cutadapt/_align.pyx b/cutadapt/_align.pyx
index 6c8fa47..57bc0f8 100644
--- a/cutadapt/_align.pyx
+++ b/cutadapt/_align.pyx
@@ -1,3 +1,4 @@
+# cython: profile=False, emit_code_comments=False
 from cpython.mem cimport PyMem_Malloc, PyMem_Free, PyMem_Realloc
 
 DEF START_WITHIN_SEQ1 = 1
diff --git a/cutadapt/_align.so b/cutadapt/_align.so
deleted file mode 100755
index c2c2133..0000000
Binary files a/cutadapt/_align.so and /dev/null differ
diff --git a/cutadapt/_qualtrim.c b/cutadapt/_qualtrim.c
index 045cb63..d95f16a 100644
--- a/cutadapt/_qualtrim.c
+++ b/cutadapt/_qualtrim.c
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.23.1 */
+/* Generated by Cython 0.23.4 */
 
 /* BEGIN: Cython Metadata
 {
@@ -13,7 +13,7 @@ END: Cython Metadata */
 #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03020000)
     #error Cython requires Python 2.6+ or Python 3.2+.
 #else
-#define CYTHON_ABI "0_23_1"
+#define CYTHON_ABI "0_23_4"
 #include <stddef.h>
 #ifndef offsetof
 #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
@@ -195,7 +195,7 @@ typedef struct {
     #define CYTHON_RESTRICT
   #endif
 #endif
-#define __Pyx_void_to_None(void_result) (void_result, Py_INCREF(Py_None), Py_None)
+#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None)
 
 #ifndef CYTHON_INLINE
   #if defined(__GNUC__)
@@ -297,10 +297,10 @@ typedef struct {PyObject **p; char *s; const Py_ssize_t n; const char* encoding;
     #define __Pyx_sst_abs(value) abs(value)
 #elif SIZEOF_LONG >= SIZEOF_SIZE_T
     #define __Pyx_sst_abs(value) labs(value)
-#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-    #define __Pyx_sst_abs(value) llabs(value)
 #elif defined (_MSC_VER) && defined (_M_X64)
     #define __Pyx_sst_abs(value) _abs64(value)
+#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+    #define __Pyx_sst_abs(value) llabs(value)
 #elif defined (__GNUC__)
     #define __Pyx_sst_abs(value) __builtin_llabs(value)
 #else
@@ -578,6 +578,18 @@ static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject*);
 #endif
 static long __Pyx__PyObject_Ord(PyObject* c);
 
+#include <string.h>
+
+static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals);
+
+static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals);
+
+#if PY_MAJOR_VERSION >= 3
+#define __Pyx_PyString_Equals __Pyx_PyUnicode_Equals
+#else
+#define __Pyx_PyString_Equals __Pyx_PyBytes_Equals
+#endif
+
 typedef struct {
     int code_line;
     PyCodeObject* code_object;
@@ -616,46 +628,63 @@ int __pyx_module_is_main_cutadapt___qualtrim = 0;
 static PyObject *__pyx_builtin_range;
 static PyObject *__pyx_builtin_reversed;
 static PyObject *__pyx_builtin_xrange;
+static char __pyx_k_G[] = "G";
 static char __pyx_k_i[] = "i";
+static char __pyx_k_q[] = "q";
 static char __pyx_k_s[] = "s";
 static char __pyx_k_base[] = "base";
 static char __pyx_k_main[] = "__main__";
 static char __pyx_k_stop[] = "stop";
 static char __pyx_k_test[] = "__test__";
+static char __pyx_k_bases[] = "bases";
+static char __pyx_k_max_i[] = "max_i";
 static char __pyx_k_range[] = "range";
 static char __pyx_k_start[] = "start";
+static char __pyx_k_cutoff[] = "cutoff";
 static char __pyx_k_xrange[] = "xrange";
 static char __pyx_k_max_qual[] = "max_qual";
 static char __pyx_k_reversed[] = "reversed";
+static char __pyx_k_sequence[] = "sequence";
 static char __pyx_k_qualities[] = "qualities";
 static char __pyx_k_cutoff_back[] = "cutoff_back";
 static char __pyx_k_cutoff_front[] = "cutoff_front";
 static char __pyx_k_Quality_trimming[] = "\nQuality trimming.\n";
 static char __pyx_k_cutadapt__qualtrim[] = "cutadapt._qualtrim";
+static char __pyx_k_nextseq_trim_index[] = "nextseq_trim_index";
 static char __pyx_k_quality_trim_index[] = "quality_trim_index";
 static char __pyx_k_home_marcel_scm_cutadapt_cutada[] = "/home/marcel/scm/cutadapt/cutadapt/_qualtrim.pyx";
+static PyObject *__pyx_n_s_G;
 static PyObject *__pyx_n_s_base;
+static PyObject *__pyx_n_s_bases;
 static PyObject *__pyx_n_s_cutadapt__qualtrim;
+static PyObject *__pyx_n_s_cutoff;
 static PyObject *__pyx_n_s_cutoff_back;
 static PyObject *__pyx_n_s_cutoff_front;
 static PyObject *__pyx_kp_s_home_marcel_scm_cutadapt_cutada;
 static PyObject *__pyx_n_s_i;
 static PyObject *__pyx_n_s_main;
+static PyObject *__pyx_n_s_max_i;
 static PyObject *__pyx_n_s_max_qual;
+static PyObject *__pyx_n_s_nextseq_trim_index;
+static PyObject *__pyx_n_s_q;
 static PyObject *__pyx_n_s_qualities;
 static PyObject *__pyx_n_s_quality_trim_index;
 static PyObject *__pyx_n_s_range;
 static PyObject *__pyx_n_s_reversed;
 static PyObject *__pyx_n_s_s;
+static PyObject *__pyx_n_s_sequence;
 static PyObject *__pyx_n_s_start;
 static PyObject *__pyx_n_s_stop;
 static PyObject *__pyx_n_s_test;
 static PyObject *__pyx_n_s_xrange;
 static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_qualities, int __pyx_v_cutoff_front, int __pyx_v_cutoff_back, int __pyx_v_base); /* proto */
+static PyObject *__pyx_pf_8cutadapt_9_qualtrim_2nextseq_trim_index(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_sequence, int __pyx_v_cutoff, int __pyx_v_base); /* proto */
 static PyObject *__pyx_tuple_;
+static PyObject *__pyx_tuple__3;
 static PyObject *__pyx_codeobj__2;
+static PyObject *__pyx_codeobj__4;
 
-/* "cutadapt/_qualtrim.pyx":6
+/* "cutadapt/_qualtrim.pyx":7
  * """
  * 
  * def quality_trim_index(str qualities, int cutoff_front, int cutoff_back, int base=33):             # <<<<<<<<<<<<<<
@@ -700,12 +729,12 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_1quality_trim_index(PyObject *__p
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_cutoff_front)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
         }
         case  2:
         if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_cutoff_back)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
         }
         case  3:
         if (kw_args > 0) {
@@ -714,7 +743,7 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_1quality_trim_index(PyObject *__p
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "quality_trim_index") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "quality_trim_index") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -727,23 +756,23 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_1quality_trim_index(PyObject *__p
       }
     }
     __pyx_v_qualities = ((PyObject*)values[0]);
-    __pyx_v_cutoff_front = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_cutoff_front == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-    __pyx_v_cutoff_back = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_cutoff_back == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_cutoff_front = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_cutoff_front == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_cutoff_back = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_cutoff_back == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
     if (values[3]) {
-      __pyx_v_base = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_base == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_base = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_base == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
     } else {
       __pyx_v_base = ((int)33);
     }
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._qualtrim.quality_trim_index", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_qualities), (&PyString_Type), 1, "qualities", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_qualities), (&PyString_Type), 1, "qualities", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(__pyx_self, __pyx_v_qualities, __pyx_v_cutoff_front, __pyx_v_cutoff_back, __pyx_v_base);
 
   /* function exit code */
@@ -776,17 +805,17 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("quality_trim_index", 0);
 
-  /* "cutadapt/_qualtrim.pyx":21
+  /* "cutadapt/_qualtrim.pyx":22
  * 	cdef int s
  * 	cdef int max_qual
  * 	cdef int stop = len(qualities)             # <<<<<<<<<<<<<<
  * 	cdef int start = 0
  * 	cdef int i
  */
-  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_v_stop = __pyx_t_1;
 
-  /* "cutadapt/_qualtrim.pyx":22
+  /* "cutadapt/_qualtrim.pyx":23
  * 	cdef int max_qual
  * 	cdef int stop = len(qualities)
  * 	cdef int start = 0             # <<<<<<<<<<<<<<
@@ -795,7 +824,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
   __pyx_v_start = 0;
 
-  /* "cutadapt/_qualtrim.pyx":26
+  /* "cutadapt/_qualtrim.pyx":27
  * 
  * 	# find trim position for 5' end
  * 	s = 0             # <<<<<<<<<<<<<<
@@ -804,7 +833,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
   __pyx_v_s = 0;
 
-  /* "cutadapt/_qualtrim.pyx":27
+  /* "cutadapt/_qualtrim.pyx":28
  * 	# find trim position for 5' end
  * 	s = 0
  * 	max_qual = 0             # <<<<<<<<<<<<<<
@@ -813,31 +842,31 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
   __pyx_v_max_qual = 0;
 
-  /* "cutadapt/_qualtrim.pyx":28
+  /* "cutadapt/_qualtrim.pyx":29
  * 	s = 0
  * 	max_qual = 0
  * 	for i in range(len(qualities)):             # <<<<<<<<<<<<<<
  * 		s += cutoff_front - (ord(qualities[i]) - base)
  * 		if s < 0:
  */
-  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
     __pyx_v_i = __pyx_t_2;
 
-    /* "cutadapt/_qualtrim.pyx":29
+    /* "cutadapt/_qualtrim.pyx":30
  * 	max_qual = 0
  * 	for i in range(len(qualities)):
  * 		s += cutoff_front - (ord(qualities[i]) - base)             # <<<<<<<<<<<<<<
  * 		if s < 0:
  * 			break
  */
-    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_3); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_3); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     __pyx_v_s = (__pyx_v_s + (__pyx_v_cutoff_front - (__pyx_t_4 - __pyx_v_base)));
 
-    /* "cutadapt/_qualtrim.pyx":30
+    /* "cutadapt/_qualtrim.pyx":31
  * 	for i in range(len(qualities)):
  * 		s += cutoff_front - (ord(qualities[i]) - base)
  * 		if s < 0:             # <<<<<<<<<<<<<<
@@ -847,7 +876,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
     __pyx_t_5 = ((__pyx_v_s < 0) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":31
+      /* "cutadapt/_qualtrim.pyx":32
  * 		s += cutoff_front - (ord(qualities[i]) - base)
  * 		if s < 0:
  * 			break             # <<<<<<<<<<<<<<
@@ -856,7 +885,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
       goto __pyx_L4_break;
 
-      /* "cutadapt/_qualtrim.pyx":30
+      /* "cutadapt/_qualtrim.pyx":31
  * 	for i in range(len(qualities)):
  * 		s += cutoff_front - (ord(qualities[i]) - base)
  * 		if s < 0:             # <<<<<<<<<<<<<<
@@ -865,7 +894,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
     }
 
-    /* "cutadapt/_qualtrim.pyx":32
+    /* "cutadapt/_qualtrim.pyx":33
  * 		if s < 0:
  * 			break
  * 		if s > max_qual:             # <<<<<<<<<<<<<<
@@ -875,7 +904,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
     __pyx_t_5 = ((__pyx_v_s > __pyx_v_max_qual) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":33
+      /* "cutadapt/_qualtrim.pyx":34
  * 			break
  * 		if s > max_qual:
  * 			max_qual = s             # <<<<<<<<<<<<<<
@@ -884,7 +913,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
       __pyx_v_max_qual = __pyx_v_s;
 
-      /* "cutadapt/_qualtrim.pyx":34
+      /* "cutadapt/_qualtrim.pyx":35
  * 		if s > max_qual:
  * 			max_qual = s
  * 			start = i + 1             # <<<<<<<<<<<<<<
@@ -893,7 +922,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
       __pyx_v_start = (__pyx_v_i + 1);
 
-      /* "cutadapt/_qualtrim.pyx":32
+      /* "cutadapt/_qualtrim.pyx":33
  * 		if s < 0:
  * 			break
  * 		if s > max_qual:             # <<<<<<<<<<<<<<
@@ -904,7 +933,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
   }
   __pyx_L4_break:;
 
-  /* "cutadapt/_qualtrim.pyx":37
+  /* "cutadapt/_qualtrim.pyx":38
  * 
  * 	# same for 3' end
  * 	max_qual = 0             # <<<<<<<<<<<<<<
@@ -913,7 +942,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
   __pyx_v_max_qual = 0;
 
-  /* "cutadapt/_qualtrim.pyx":38
+  /* "cutadapt/_qualtrim.pyx":39
  * 	# same for 3' end
  * 	max_qual = 0
  * 	s = 0             # <<<<<<<<<<<<<<
@@ -922,31 +951,31 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
   __pyx_v_s = 0;
 
-  /* "cutadapt/_qualtrim.pyx":39
+  /* "cutadapt/_qualtrim.pyx":40
  * 	max_qual = 0
  * 	s = 0
  * 	for i in reversed(xrange(len(qualities))):             # <<<<<<<<<<<<<<
  * 		s += cutoff_back - (ord(qualities[i]) - base)
  * 		if s < 0:
  */
-  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   for (__pyx_t_2 = __pyx_t_1-1; __pyx_t_2 >= 0; __pyx_t_2-=1) {
     __pyx_v_i = __pyx_t_2;
 
-    /* "cutadapt/_qualtrim.pyx":40
+    /* "cutadapt/_qualtrim.pyx":41
  * 	s = 0
  * 	for i in reversed(xrange(len(qualities))):
  * 		s += cutoff_back - (ord(qualities[i]) - base)             # <<<<<<<<<<<<<<
  * 		if s < 0:
  * 			break
  */
-    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_3); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_3); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     __pyx_v_s = (__pyx_v_s + (__pyx_v_cutoff_back - (__pyx_t_4 - __pyx_v_base)));
 
-    /* "cutadapt/_qualtrim.pyx":41
+    /* "cutadapt/_qualtrim.pyx":42
  * 	for i in reversed(xrange(len(qualities))):
  * 		s += cutoff_back - (ord(qualities[i]) - base)
  * 		if s < 0:             # <<<<<<<<<<<<<<
@@ -956,7 +985,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
     __pyx_t_5 = ((__pyx_v_s < 0) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":42
+      /* "cutadapt/_qualtrim.pyx":43
  * 		s += cutoff_back - (ord(qualities[i]) - base)
  * 		if s < 0:
  * 			break             # <<<<<<<<<<<<<<
@@ -965,7 +994,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
       goto __pyx_L8_break;
 
-      /* "cutadapt/_qualtrim.pyx":41
+      /* "cutadapt/_qualtrim.pyx":42
  * 	for i in reversed(xrange(len(qualities))):
  * 		s += cutoff_back - (ord(qualities[i]) - base)
  * 		if s < 0:             # <<<<<<<<<<<<<<
@@ -974,7 +1003,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
     }
 
-    /* "cutadapt/_qualtrim.pyx":43
+    /* "cutadapt/_qualtrim.pyx":44
  * 		if s < 0:
  * 			break
  * 		if s > max_qual:             # <<<<<<<<<<<<<<
@@ -984,7 +1013,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
     __pyx_t_5 = ((__pyx_v_s > __pyx_v_max_qual) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":44
+      /* "cutadapt/_qualtrim.pyx":45
  * 			break
  * 		if s > max_qual:
  * 			max_qual = s             # <<<<<<<<<<<<<<
@@ -993,7 +1022,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
       __pyx_v_max_qual = __pyx_v_s;
 
-      /* "cutadapt/_qualtrim.pyx":45
+      /* "cutadapt/_qualtrim.pyx":46
  * 		if s > max_qual:
  * 			max_qual = s
  * 			stop = i             # <<<<<<<<<<<<<<
@@ -1002,7 +1031,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
       __pyx_v_stop = __pyx_v_i;
 
-      /* "cutadapt/_qualtrim.pyx":43
+      /* "cutadapt/_qualtrim.pyx":44
  * 		if s < 0:
  * 			break
  * 		if s > max_qual:             # <<<<<<<<<<<<<<
@@ -1013,7 +1042,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
   }
   __pyx_L8_break:;
 
-  /* "cutadapt/_qualtrim.pyx":46
+  /* "cutadapt/_qualtrim.pyx":47
  * 			max_qual = s
  * 			stop = i
  * 	if start >= stop:             # <<<<<<<<<<<<<<
@@ -1023,18 +1052,19 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
   __pyx_t_5 = ((__pyx_v_start >= __pyx_v_stop) != 0);
   if (__pyx_t_5) {
 
-    /* "cutadapt/_qualtrim.pyx":47
+    /* "cutadapt/_qualtrim.pyx":48
  * 			stop = i
  * 	if start >= stop:
  * 		start, stop = 0, 0             # <<<<<<<<<<<<<<
  * 	return (start, stop)
+ * 
  */
     __pyx_t_2 = 0;
     __pyx_t_6 = 0;
     __pyx_v_start = __pyx_t_2;
     __pyx_v_stop = __pyx_t_6;
 
-    /* "cutadapt/_qualtrim.pyx":46
+    /* "cutadapt/_qualtrim.pyx":47
  * 			max_qual = s
  * 			stop = i
  * 	if start >= stop:             # <<<<<<<<<<<<<<
@@ -1043,17 +1073,19 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
  */
   }
 
-  /* "cutadapt/_qualtrim.pyx":48
+  /* "cutadapt/_qualtrim.pyx":49
  * 	if start >= stop:
  * 		start, stop = 0, 0
  * 	return (start, stop)             # <<<<<<<<<<<<<<
+ * 
+ * 
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_start); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_start); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_7 = __Pyx_PyInt_From_int(__pyx_v_stop); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_7 = __Pyx_PyInt_From_int(__pyx_v_stop); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_7);
-  __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_8);
   __Pyx_GIVEREF(__pyx_t_3);
   PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_3);
@@ -1065,7 +1097,7 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
   __pyx_t_8 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_qualtrim.pyx":6
+  /* "cutadapt/_qualtrim.pyx":7
  * """
  * 
  * def quality_trim_index(str qualities, int cutoff_front, int cutoff_back, int base=33):             # <<<<<<<<<<<<<<
@@ -1086,6 +1118,354 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
   return __pyx_r;
 }
 
+/* "cutadapt/_qualtrim.pyx":52
+ * 
+ * 
+ * def nextseq_trim_index(sequence, int cutoff, int base=33):             # <<<<<<<<<<<<<<
+ * 	"""
+ * 	Variant of the above quality trimming routine that works on NextSeq data.
+ */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_8cutadapt_9_qualtrim_3nextseq_trim_index(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_8cutadapt_9_qualtrim_2nextseq_trim_index[] = "\n\tVariant of the above quality trimming routine that works on NextSeq data.\n\tWith Illumina NextSeq, bases are encoded with two colors. 'No color' (a\n\tdark cycle) usually means that a 'G' was sequenced, but that also occurs\n\twhen sequencing falls off the end of the fragment. The read then contains\n\ta run of high-quality G bases in the end.\n\n\tThis routine works as the one above, but counts qualities belonging  [...]
+static PyMethodDef __pyx_mdef_8cutadapt_9_qualtrim_3nextseq_trim_index = {"nextseq_trim_index", (PyCFunction)__pyx_pw_8cutadapt_9_qualtrim_3nextseq_trim_index, METH_VARARGS|METH_KEYWORDS, __pyx_doc_8cutadapt_9_qualtrim_2nextseq_trim_index};
+static PyObject *__pyx_pw_8cutadapt_9_qualtrim_3nextseq_trim_index(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_sequence = 0;
+  int __pyx_v_cutoff;
+  int __pyx_v_base;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("nextseq_trim_index (wrapper)", 0);
+  {
+    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_sequence,&__pyx_n_s_cutoff,&__pyx_n_s_base,0};
+    PyObject* values[3] = {0,0,0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_sequence)) != 0)) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+        case  1:
+        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_cutoff)) != 0)) kw_args--;
+        else {
+          __Pyx_RaiseArgtupleInvalid("nextseq_trim_index", 0, 2, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        }
+        case  2:
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_base);
+          if (value) { values[2] = value; kw_args--; }
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "nextseq_trim_index") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else {
+      switch (PyTuple_GET_SIZE(__pyx_args)) {
+        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+    }
+    __pyx_v_sequence = values[0];
+    __pyx_v_cutoff = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_cutoff == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    if (values[2]) {
+      __pyx_v_base = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_base == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    } else {
+      __pyx_v_base = ((int)33);
+    }
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("nextseq_trim_index", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("cutadapt._qualtrim.nextseq_trim_index", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_8cutadapt_9_qualtrim_2nextseq_trim_index(__pyx_self, __pyx_v_sequence, __pyx_v_cutoff, __pyx_v_base);
+
+  /* function exit code */
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_pf_8cutadapt_9_qualtrim_2nextseq_trim_index(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_sequence, int __pyx_v_cutoff, int __pyx_v_base) {
+  PyObject *__pyx_v_bases = NULL;
+  PyObject *__pyx_v_qualities = NULL;
+  int __pyx_v_s;
+  int __pyx_v_max_qual;
+  int __pyx_v_max_i;
+  int __pyx_v_i;
+  int __pyx_v_q;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  Py_ssize_t __pyx_t_2;
+  int __pyx_t_3;
+  long __pyx_t_4;
+  int __pyx_t_5;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("nextseq_trim_index", 0);
+
+  /* "cutadapt/_qualtrim.pyx":63
+ * 	bases as being equal to cutoff - 1.
+ * 	"""
+ * 	bases = sequence.sequence             # <<<<<<<<<<<<<<
+ * 	qualities = sequence.qualities
+ * 	cdef:
+ */
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_sequence, __pyx_n_s_sequence); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_bases = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "cutadapt/_qualtrim.pyx":64
+ * 	"""
+ * 	bases = sequence.sequence
+ * 	qualities = sequence.qualities             # <<<<<<<<<<<<<<
+ * 	cdef:
+ * 		int s = 0
+ */
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_sequence, __pyx_n_s_qualities); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_qualities = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "cutadapt/_qualtrim.pyx":66
+ * 	qualities = sequence.qualities
+ * 	cdef:
+ * 		int s = 0             # <<<<<<<<<<<<<<
+ * 		int max_qual = 0
+ * 		int max_i = len(qualities)
+ */
+  __pyx_v_s = 0;
+
+  /* "cutadapt/_qualtrim.pyx":67
+ * 	cdef:
+ * 		int s = 0
+ * 		int max_qual = 0             # <<<<<<<<<<<<<<
+ * 		int max_i = len(qualities)
+ * 		int i, q
+ */
+  __pyx_v_max_qual = 0;
+
+  /* "cutadapt/_qualtrim.pyx":68
+ * 		int s = 0
+ * 		int max_qual = 0
+ * 		int max_i = len(qualities)             # <<<<<<<<<<<<<<
+ * 		int i, q
+ * 
+ */
+  __pyx_t_2 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_max_i = __pyx_t_2;
+
+  /* "cutadapt/_qualtrim.pyx":71
+ * 		int i, q
+ * 
+ * 	s = 0             # <<<<<<<<<<<<<<
+ * 	max_qual = 0
+ * 	max_i = len(qualities)
+ */
+  __pyx_v_s = 0;
+
+  /* "cutadapt/_qualtrim.pyx":72
+ * 
+ * 	s = 0
+ * 	max_qual = 0             # <<<<<<<<<<<<<<
+ * 	max_i = len(qualities)
+ * 	for i in reversed(xrange(max_i)):
+ */
+  __pyx_v_max_qual = 0;
+
+  /* "cutadapt/_qualtrim.pyx":73
+ * 	s = 0
+ * 	max_qual = 0
+ * 	max_i = len(qualities)             # <<<<<<<<<<<<<<
+ * 	for i in reversed(xrange(max_i)):
+ * 		q = ord(qualities[i]) - base
+ */
+  __pyx_t_2 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_max_i = __pyx_t_2;
+
+  /* "cutadapt/_qualtrim.pyx":74
+ * 	max_qual = 0
+ * 	max_i = len(qualities)
+ * 	for i in reversed(xrange(max_i)):             # <<<<<<<<<<<<<<
+ * 		q = ord(qualities[i]) - base
+ * 		if bases[i] == 'G':
+ */
+  for (__pyx_t_3 = __pyx_v_max_i-1; __pyx_t_3 >= 0; __pyx_t_3-=1) {
+    __pyx_v_i = __pyx_t_3;
+
+    /* "cutadapt/_qualtrim.pyx":75
+ * 	max_i = len(qualities)
+ * 	for i in reversed(xrange(max_i)):
+ * 		q = ord(qualities[i]) - base             # <<<<<<<<<<<<<<
+ * 		if bases[i] == 'G':
+ * 			q = cutoff - 1
+ */
+    __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_1); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_v_q = (__pyx_t_4 - __pyx_v_base);
+
+    /* "cutadapt/_qualtrim.pyx":76
+ * 	for i in reversed(xrange(max_i)):
+ * 		q = ord(qualities[i]) - base
+ * 		if bases[i] == 'G':             # <<<<<<<<<<<<<<
+ * 			q = cutoff - 1
+ * 		s += cutoff - q
+ */
+    __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_bases, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_5 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_n_s_G, Py_EQ)); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    if (__pyx_t_5) {
+
+      /* "cutadapt/_qualtrim.pyx":77
+ * 		q = ord(qualities[i]) - base
+ * 		if bases[i] == 'G':
+ * 			q = cutoff - 1             # <<<<<<<<<<<<<<
+ * 		s += cutoff - q
+ * 		if s < 0:
+ */
+      __pyx_v_q = (__pyx_v_cutoff - 1);
+
+      /* "cutadapt/_qualtrim.pyx":76
+ * 	for i in reversed(xrange(max_i)):
+ * 		q = ord(qualities[i]) - base
+ * 		if bases[i] == 'G':             # <<<<<<<<<<<<<<
+ * 			q = cutoff - 1
+ * 		s += cutoff - q
+ */
+    }
+
+    /* "cutadapt/_qualtrim.pyx":78
+ * 		if bases[i] == 'G':
+ * 			q = cutoff - 1
+ * 		s += cutoff - q             # <<<<<<<<<<<<<<
+ * 		if s < 0:
+ * 			break
+ */
+    __pyx_v_s = (__pyx_v_s + (__pyx_v_cutoff - __pyx_v_q));
+
+    /* "cutadapt/_qualtrim.pyx":79
+ * 			q = cutoff - 1
+ * 		s += cutoff - q
+ * 		if s < 0:             # <<<<<<<<<<<<<<
+ * 			break
+ * 		if s > max_qual:
+ */
+    __pyx_t_5 = ((__pyx_v_s < 0) != 0);
+    if (__pyx_t_5) {
+
+      /* "cutadapt/_qualtrim.pyx":80
+ * 		s += cutoff - q
+ * 		if s < 0:
+ * 			break             # <<<<<<<<<<<<<<
+ * 		if s > max_qual:
+ * 			max_qual = s
+ */
+      goto __pyx_L4_break;
+
+      /* "cutadapt/_qualtrim.pyx":79
+ * 			q = cutoff - 1
+ * 		s += cutoff - q
+ * 		if s < 0:             # <<<<<<<<<<<<<<
+ * 			break
+ * 		if s > max_qual:
+ */
+    }
+
+    /* "cutadapt/_qualtrim.pyx":81
+ * 		if s < 0:
+ * 			break
+ * 		if s > max_qual:             # <<<<<<<<<<<<<<
+ * 			max_qual = s
+ * 			max_i = i
+ */
+    __pyx_t_5 = ((__pyx_v_s > __pyx_v_max_qual) != 0);
+    if (__pyx_t_5) {
+
+      /* "cutadapt/_qualtrim.pyx":82
+ * 			break
+ * 		if s > max_qual:
+ * 			max_qual = s             # <<<<<<<<<<<<<<
+ * 			max_i = i
+ * 	return max_i
+ */
+      __pyx_v_max_qual = __pyx_v_s;
+
+      /* "cutadapt/_qualtrim.pyx":83
+ * 		if s > max_qual:
+ * 			max_qual = s
+ * 			max_i = i             # <<<<<<<<<<<<<<
+ * 	return max_i
+ */
+      __pyx_v_max_i = __pyx_v_i;
+
+      /* "cutadapt/_qualtrim.pyx":81
+ * 		if s < 0:
+ * 			break
+ * 		if s > max_qual:             # <<<<<<<<<<<<<<
+ * 			max_qual = s
+ * 			max_i = i
+ */
+    }
+  }
+  __pyx_L4_break:;
+
+  /* "cutadapt/_qualtrim.pyx":84
+ * 			max_qual = s
+ * 			max_i = i
+ * 	return max_i             # <<<<<<<<<<<<<<
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_max_i); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  /* "cutadapt/_qualtrim.pyx":52
+ * 
+ * 
+ * def nextseq_trim_index(sequence, int cutoff, int base=33):             # <<<<<<<<<<<<<<
+ * 	"""
+ * 	Variant of the above quality trimming routine that works on NextSeq data.
+ */
+
+  /* function exit code */
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("cutadapt._qualtrim.nextseq_trim_index", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_bases);
+  __Pyx_XDECREF(__pyx_v_qualities);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
 static PyMethodDef __pyx_methods[] = {
   {0, 0, 0, 0}
 };
@@ -1109,19 +1489,26 @@ static struct PyModuleDef __pyx_moduledef = {
 #endif
 
 static __Pyx_StringTabEntry __pyx_string_tab[] = {
+  {&__pyx_n_s_G, __pyx_k_G, sizeof(__pyx_k_G), 0, 0, 1, 1},
   {&__pyx_n_s_base, __pyx_k_base, sizeof(__pyx_k_base), 0, 0, 1, 1},
+  {&__pyx_n_s_bases, __pyx_k_bases, sizeof(__pyx_k_bases), 0, 0, 1, 1},
   {&__pyx_n_s_cutadapt__qualtrim, __pyx_k_cutadapt__qualtrim, sizeof(__pyx_k_cutadapt__qualtrim), 0, 0, 1, 1},
+  {&__pyx_n_s_cutoff, __pyx_k_cutoff, sizeof(__pyx_k_cutoff), 0, 0, 1, 1},
   {&__pyx_n_s_cutoff_back, __pyx_k_cutoff_back, sizeof(__pyx_k_cutoff_back), 0, 0, 1, 1},
   {&__pyx_n_s_cutoff_front, __pyx_k_cutoff_front, sizeof(__pyx_k_cutoff_front), 0, 0, 1, 1},
   {&__pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_k_home_marcel_scm_cutadapt_cutada, sizeof(__pyx_k_home_marcel_scm_cutadapt_cutada), 0, 0, 1, 0},
   {&__pyx_n_s_i, __pyx_k_i, sizeof(__pyx_k_i), 0, 0, 1, 1},
   {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1},
+  {&__pyx_n_s_max_i, __pyx_k_max_i, sizeof(__pyx_k_max_i), 0, 0, 1, 1},
   {&__pyx_n_s_max_qual, __pyx_k_max_qual, sizeof(__pyx_k_max_qual), 0, 0, 1, 1},
+  {&__pyx_n_s_nextseq_trim_index, __pyx_k_nextseq_trim_index, sizeof(__pyx_k_nextseq_trim_index), 0, 0, 1, 1},
+  {&__pyx_n_s_q, __pyx_k_q, sizeof(__pyx_k_q), 0, 0, 1, 1},
   {&__pyx_n_s_qualities, __pyx_k_qualities, sizeof(__pyx_k_qualities), 0, 0, 1, 1},
   {&__pyx_n_s_quality_trim_index, __pyx_k_quality_trim_index, sizeof(__pyx_k_quality_trim_index), 0, 0, 1, 1},
   {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1},
   {&__pyx_n_s_reversed, __pyx_k_reversed, sizeof(__pyx_k_reversed), 0, 0, 1, 1},
   {&__pyx_n_s_s, __pyx_k_s, sizeof(__pyx_k_s), 0, 0, 1, 1},
+  {&__pyx_n_s_sequence, __pyx_k_sequence, sizeof(__pyx_k_sequence), 0, 0, 1, 1},
   {&__pyx_n_s_start, __pyx_k_start, sizeof(__pyx_k_start), 0, 0, 1, 1},
   {&__pyx_n_s_stop, __pyx_k_stop, sizeof(__pyx_k_stop), 0, 0, 1, 1},
   {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1},
@@ -1129,12 +1516,12 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {0, 0, 0, 0, 0, 0, 0}
 };
 static int __Pyx_InitCachedBuiltins(void) {
-  __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_reversed = __Pyx_GetBuiltinName(__pyx_n_s_reversed); if (!__pyx_builtin_reversed) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_reversed = __Pyx_GetBuiltinName(__pyx_n_s_reversed); if (!__pyx_builtin_reversed) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   #if PY_MAJOR_VERSION >= 3
-  __pyx_builtin_xrange = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_xrange) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_xrange = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_xrange) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   #else
-  __pyx_builtin_xrange = __Pyx_GetBuiltinName(__pyx_n_s_xrange); if (!__pyx_builtin_xrange) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_xrange = __Pyx_GetBuiltinName(__pyx_n_s_xrange); if (!__pyx_builtin_xrange) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   #endif
   return 0;
   __pyx_L1_error:;
@@ -1145,17 +1532,29 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0);
 
-  /* "cutadapt/_qualtrim.pyx":6
+  /* "cutadapt/_qualtrim.pyx":7
  * """
  * 
  * def quality_trim_index(str qualities, int cutoff_front, int cutoff_back, int base=33):             # <<<<<<<<<<<<<<
  * 	"""
  * 	Find the positions at which to trim low-quality ends from a nucleotide sequence.
  */
-  __pyx_tuple_ = PyTuple_Pack(9, __pyx_n_s_qualities, __pyx_n_s_cutoff_front, __pyx_n_s_cutoff_back, __pyx_n_s_base, __pyx_n_s_s, __pyx_n_s_max_qual, __pyx_n_s_stop, __pyx_n_s_start, __pyx_n_s_i); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple_ = PyTuple_Pack(9, __pyx_n_s_qualities, __pyx_n_s_cutoff_front, __pyx_n_s_cutoff_back, __pyx_n_s_base, __pyx_n_s_s, __pyx_n_s_max_qual, __pyx_n_s_stop, __pyx_n_s_start, __pyx_n_s_i); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_tuple_);
   __Pyx_GIVEREF(__pyx_tuple_);
-  __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(4, 0, 9, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_quality_trim_index, 6, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(4, 0, 9, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_quality_trim_index, 7, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "cutadapt/_qualtrim.pyx":52
+ * 
+ * 
+ * def nextseq_trim_index(sequence, int cutoff, int base=33):             # <<<<<<<<<<<<<<
+ * 	"""
+ * 	Variant of the above quality trimming routine that works on NextSeq data.
+ */
+  __pyx_tuple__3 = PyTuple_Pack(10, __pyx_n_s_sequence, __pyx_n_s_cutoff, __pyx_n_s_base, __pyx_n_s_bases, __pyx_n_s_qualities, __pyx_n_s_s, __pyx_n_s_max_qual, __pyx_n_s_max_i, __pyx_n_s_i, __pyx_n_s_q); if (unlikely(!__pyx_tuple__3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_tuple__3);
+  __Pyx_GIVEREF(__pyx_tuple__3);
+  __pyx_codeobj__4 = (PyObject*)__Pyx_PyCode_New(3, 0, 10, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_nextseq_trim_index, 52, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -1264,22 +1663,34 @@ PyMODINIT_FUNC PyInit__qualtrim(void)
   if (__Pyx_patch_abc() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   #endif
 
-  /* "cutadapt/_qualtrim.pyx":6
+  /* "cutadapt/_qualtrim.pyx":7
  * """
  * 
  * def quality_trim_index(str qualities, int cutoff_front, int cutoff_back, int base=33):             # <<<<<<<<<<<<<<
  * 	"""
  * 	Find the positions at which to trim low-quality ends from a nucleotide sequence.
  */
-  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_9_qualtrim_1quality_trim_index, NULL, __pyx_n_s_cutadapt__qualtrim); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_9_qualtrim_1quality_trim_index, NULL, __pyx_n_s_cutadapt__qualtrim); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_quality_trim_index, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "cutadapt/_qualtrim.pyx":52
+ * 
+ * 
+ * def nextseq_trim_index(sequence, int cutoff, int base=33):             # <<<<<<<<<<<<<<
+ * 	"""
+ * 	Variant of the above quality trimming routine that works on NextSeq data.
+ */
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_9_qualtrim_3nextseq_trim_index, NULL, __pyx_n_s_cutadapt__qualtrim); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_quality_trim_index, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_nextseq_trim_index, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
   /* "cutadapt/_qualtrim.pyx":1
  * # kate: syntax Python;             # <<<<<<<<<<<<<<
+ * # cython: profile=False, emit_code_comments=False
  * """
- * Quality trimming.
  */
   __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
@@ -1642,6 +2053,126 @@ static long __Pyx__PyObject_Ord(PyObject* c) {
     return (long)(Py_UCS4)-1;
 }
 
+static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) {
+#if CYTHON_COMPILING_IN_PYPY
+    return PyObject_RichCompareBool(s1, s2, equals);
+#else
+    if (s1 == s2) {
+        return (equals == Py_EQ);
+    } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) {
+        const char *ps1, *ps2;
+        Py_ssize_t length = PyBytes_GET_SIZE(s1);
+        if (length != PyBytes_GET_SIZE(s2))
+            return (equals == Py_NE);
+        ps1 = PyBytes_AS_STRING(s1);
+        ps2 = PyBytes_AS_STRING(s2);
+        if (ps1[0] != ps2[0]) {
+            return (equals == Py_NE);
+        } else if (length == 1) {
+            return (equals == Py_EQ);
+        } else {
+            int result = memcmp(ps1, ps2, (size_t)length);
+            return (equals == Py_EQ) ? (result == 0) : (result != 0);
+        }
+    } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) {
+        return (equals == Py_NE);
+    } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) {
+        return (equals == Py_NE);
+    } else {
+        int result;
+        PyObject* py_result = PyObject_RichCompare(s1, s2, equals);
+        if (!py_result)
+            return -1;
+        result = __Pyx_PyObject_IsTrue(py_result);
+        Py_DECREF(py_result);
+        return result;
+    }
+#endif
+}
+
+static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) {
+#if CYTHON_COMPILING_IN_PYPY
+    return PyObject_RichCompareBool(s1, s2, equals);
+#else
+#if PY_MAJOR_VERSION < 3
+    PyObject* owned_ref = NULL;
+#endif
+    int s1_is_unicode, s2_is_unicode;
+    if (s1 == s2) {
+        goto return_eq;
+    }
+    s1_is_unicode = PyUnicode_CheckExact(s1);
+    s2_is_unicode = PyUnicode_CheckExact(s2);
+#if PY_MAJOR_VERSION < 3
+    if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) {
+        owned_ref = PyUnicode_FromObject(s2);
+        if (unlikely(!owned_ref))
+            return -1;
+        s2 = owned_ref;
+        s2_is_unicode = 1;
+    } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) {
+        owned_ref = PyUnicode_FromObject(s1);
+        if (unlikely(!owned_ref))
+            return -1;
+        s1 = owned_ref;
+        s1_is_unicode = 1;
+    } else if (((!s2_is_unicode) & (!s1_is_unicode))) {
+        return __Pyx_PyBytes_Equals(s1, s2, equals);
+    }
+#endif
+    if (s1_is_unicode & s2_is_unicode) {
+        Py_ssize_t length;
+        int kind;
+        void *data1, *data2;
+        if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0))
+            return -1;
+        length = __Pyx_PyUnicode_GET_LENGTH(s1);
+        if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) {
+            goto return_ne;
+        }
+        kind = __Pyx_PyUnicode_KIND(s1);
+        if (kind != __Pyx_PyUnicode_KIND(s2)) {
+            goto return_ne;
+        }
+        data1 = __Pyx_PyUnicode_DATA(s1);
+        data2 = __Pyx_PyUnicode_DATA(s2);
+        if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) {
+            goto return_ne;
+        } else if (length == 1) {
+            goto return_eq;
+        } else {
+            int result = memcmp(data1, data2, (size_t)(length * kind));
+            #if PY_MAJOR_VERSION < 3
+            Py_XDECREF(owned_ref);
+            #endif
+            return (equals == Py_EQ) ? (result == 0) : (result != 0);
+        }
+    } else if ((s1 == Py_None) & s2_is_unicode) {
+        goto return_ne;
+    } else if ((s2 == Py_None) & s1_is_unicode) {
+        goto return_ne;
+    } else {
+        int result;
+        PyObject* py_result = PyObject_RichCompare(s1, s2, equals);
+        if (!py_result)
+            return -1;
+        result = __Pyx_PyObject_IsTrue(py_result);
+        Py_DECREF(py_result);
+        return result;
+    }
+return_eq:
+    #if PY_MAJOR_VERSION < 3
+    Py_XDECREF(owned_ref);
+    #endif
+    return (equals == Py_EQ);
+return_ne:
+    #if PY_MAJOR_VERSION < 3
+    Py_XDECREF(owned_ref);
+    #endif
+    return (equals == Py_NE);
+#endif
+}
+
 static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
     int start = 0, mid = 0, end = count - 1;
     if (end >= 0 && code_line > entries[end].code_line) {
@@ -1852,27 +2383,27 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
                 case 2:
                     if (8 * sizeof(int) > 1 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) {
-                            return (int) (((((int)digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]));
                         }
                     }
                     break;
                 case 3:
                     if (8 * sizeof(int) > 2 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) {
-                            return (int) (((((((int)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]));
                         }
                     }
                     break;
                 case 4:
                     if (8 * sizeof(int) > 3 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) {
-                            return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]));
                         }
                     }
                     break;
@@ -1906,54 +2437,54 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
                 case -2:
                     if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) {
-                            return (int) -(((((int)digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
                         }
                     }
                     break;
                 case 2:
                     if (8 * sizeof(int) > 1 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) {
-                            return (int) (((((int)digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
                         }
                     }
                     break;
                 case -3:
                     if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) {
-                            return (int) -(((((((int)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
                         }
                     }
                     break;
                 case 3:
                     if (8 * sizeof(int) > 2 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) {
-                            return (int) (((((((int)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
                         }
                     }
                     break;
                 case -4:
                     if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) {
-                            return (int) -(((((((((int)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
                         }
                     }
                     break;
                 case 4:
                     if (8 * sizeof(int) > 3 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) {
-                            return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
                         }
                     }
                     break;
@@ -2088,27 +2619,27 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
                 case 2:
                     if (8 * sizeof(long) > 1 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) {
-                            return (long) (((((long)digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]));
                         }
                     }
                     break;
                 case 3:
                     if (8 * sizeof(long) > 2 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) {
-                            return (long) (((((((long)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]));
                         }
                     }
                     break;
                 case 4:
                     if (8 * sizeof(long) > 3 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) {
-                            return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]));
                         }
                     }
                     break;
@@ -2142,54 +2673,54 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
                 case -2:
                     if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
-                            return (long) -(((((long)digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
                         }
                     }
                     break;
                 case 2:
                     if (8 * sizeof(long) > 1 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
-                            return (long) (((((long)digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
                         }
                     }
                     break;
                 case -3:
                     if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
-                            return (long) -(((((((long)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
                         }
                     }
                     break;
                 case 3:
                     if (8 * sizeof(long) > 2 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
-                            return (long) (((((((long)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
                         }
                     }
                     break;
                 case -4:
                     if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
-                            return (long) -(((((((((long)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
                         }
                     }
                     break;
                 case 4:
                     if (8 * sizeof(long) > 3 * PyLong_SHIFT) {
                         if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
-                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0])))
+                            __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
                         } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
-                            return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+                            return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
                         }
                     }
                     break;
@@ -2429,32 +2960,32 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
       switch (size) {
          case 2:
            if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) {
-             return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | digits[0]));
+             return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
            }
            break;
          case -2:
            if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) {
-             return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | digits[0]));
+             return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
            }
            break;
          case 3:
            if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) {
-             return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+             return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
            }
            break;
          case -3:
            if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) {
-             return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+             return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
            }
            break;
          case 4:
            if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) {
-             return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+             return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
            }
            break;
          case -4:
            if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) {
-             return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | digits[2]) << PyLong_SHIFT) | digits[1]) << PyLong_SHIFT) | digits[0]));
+             return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
            }
            break;
       }
diff --git a/cutadapt/_qualtrim.pyx b/cutadapt/_qualtrim.pyx
index 4169c4c..3bd88c7 100644
--- a/cutadapt/_qualtrim.pyx
+++ b/cutadapt/_qualtrim.pyx
@@ -1,4 +1,5 @@
 # kate: syntax Python;
+# cython: profile=False, emit_code_comments=False
 """
 Quality trimming.
 """
@@ -46,3 +47,38 @@ def quality_trim_index(str qualities, int cutoff_front, int cutoff_back, int bas
 	if start >= stop:
 		start, stop = 0, 0
 	return (start, stop)
+
+
+def nextseq_trim_index(sequence, int cutoff, int base=33):
+	"""
+	Variant of the above quality trimming routine that works on NextSeq data.
+	With Illumina NextSeq, bases are encoded with two colors. 'No color' (a
+	dark cycle) usually means that a 'G' was sequenced, but that also occurs
+	when sequencing falls off the end of the fragment. The read then contains
+	a run of high-quality G bases in the end.
+
+	This routine works as the one above, but counts qualities belonging to 'G'
+	bases as being equal to cutoff - 1.
+	"""
+	bases = sequence.sequence
+	qualities = sequence.qualities
+	cdef:
+		int s = 0
+		int max_qual = 0
+		int max_i = len(qualities)
+		int i, q
+
+	s = 0
+	max_qual = 0
+	max_i = len(qualities)
+	for i in reversed(xrange(max_i)):
+		q = ord(qualities[i]) - base
+		if bases[i] == 'G':
+			q = cutoff - 1
+		s += cutoff - q
+		if s < 0:
+			break
+		if s > max_qual:
+			max_qual = s
+			max_i = i
+	return max_i
diff --git a/cutadapt/_qualtrim.so b/cutadapt/_qualtrim.so
deleted file mode 100755
index 91bedf2..0000000
Binary files a/cutadapt/_qualtrim.so and /dev/null differ
diff --git a/cutadapt/_seqio.c b/cutadapt/_seqio.c
index 3ffc7d9..f82cc40 100644
--- a/cutadapt/_seqio.c
+++ b/cutadapt/_seqio.c
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.23.3 */
+/* Generated by Cython 0.23.4 */
 
 /* BEGIN: Cython Metadata
 {
@@ -13,7 +13,7 @@ END: Cython Metadata */
 #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03020000)
     #error Cython requires Python 2.6+ or Python 3.2+.
 #else
-#define CYTHON_ABI "0_23_3"
+#define CYTHON_ABI "0_23_4"
 #include <stddef.h>
 #ifndef offsetof
 #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
@@ -195,7 +195,7 @@ typedef struct {
     #define CYTHON_RESTRICT
   #endif
 #endif
-#define __Pyx_void_to_None(void_result) (void_result, Py_INCREF(Py_None), Py_None)
+#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None)
 
 #ifndef CYTHON_INLINE
   #if defined(__GNUC__)
@@ -297,10 +297,10 @@ typedef struct {PyObject **p; char *s; const Py_ssize_t n; const char* encoding;
     #define __Pyx_sst_abs(value) abs(value)
 #elif SIZEOF_LONG >= SIZEOF_SIZE_T
     #define __Pyx_sst_abs(value) labs(value)
-#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-    #define __Pyx_sst_abs(value) llabs(value)
 #elif defined (_MSC_VER) && defined (_M_X64)
     #define __Pyx_sst_abs(value) _abs64(value)
+#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+    #define __Pyx_sst_abs(value) llabs(value)
 #elif defined (__GNUC__)
     #define __Pyx_sst_abs(value) __builtin_llabs(value)
 #else
@@ -462,7 +462,7 @@ struct __pyx_defaults {
   PyObject *__pyx_arg_sequence_class;
 };
 
-/* "cutadapt/_seqio.pyx":25
+/* "cutadapt/_seqio.pyx":8
  * 
  * 
  * cdef class Sequence(object):             # <<<<<<<<<<<<<<
@@ -476,10 +476,11 @@ struct __pyx_obj_8cutadapt_6_seqio_Sequence {
   PyObject *qualities;
   PyObject *name2;
   PyObject *match;
+  PyObject *match_info;
 };
 
 
-/* "cutadapt/_seqio.pyx":106
+/* "cutadapt/_seqio.pyx":88
  * 		self.delivers_qualities = True
  * 
  * 	def __iter__(self):             # <<<<<<<<<<<<<<
@@ -584,27 +585,15 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject
 
 static PyObject *__Pyx_GetBuiltinName(PyObject *name);
 
+static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
+    Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found);
+
 static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name);
 
 static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\
     PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\
     const char* function_name);
 
-static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
-    Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found);
-
-#if CYTHON_COMPILING_IN_CPYTHON
-static PyObject* __Pyx_PyInt_SubtractObjC(PyObject *op1, PyObject *op2, long intval, int inplace);
-#else
-#define __Pyx_PyInt_SubtractObjC(op1, op2, intval, inplace)\
-    (inplace ? PyNumber_InPlaceSubtract(op1, op2) : PyNumber_Subtract(op1, op2))
-#endif
-
-static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice(
-        PyObject* obj, Py_ssize_t cstart, Py_ssize_t cstop,
-        PyObject** py_start, PyObject** py_stop, PyObject** py_slice,
-        int has_cstart, int has_cstop, int wraparound);
-
 static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
     const char *name, int exact);
 
@@ -707,11 +696,6 @@ static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name);
 
 static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases);
 
-static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname,
-                                           PyObject *mkw, PyObject *modname, PyObject *doc);
-static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict,
-                                      PyObject *mkw, int calculate_metaclass, int allow_py2_metaclass);
-
 static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type);
 
 #define __Pyx_CyFunction_USED 1
@@ -767,6 +751,11 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m,
                                                               PyObject *dict);
 static int __pyx_CyFunction_init(void);
 
+static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname,
+                                           PyObject *mkw, PyObject *modname, PyObject *doc);
+static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict,
+                                      PyObject *mkw, int calculate_metaclass, int allow_py2_metaclass);
+
 typedef struct {
     int code_line;
     PyCodeObject* code_object;
@@ -843,23 +832,17 @@ static PyTypeObject *__pyx_ptype_8cutadapt_6_seqio___pyx_scope_struct____iter__
 int __pyx_module_is_main_cutadapt___seqio = 0;
 
 /* Implementation of 'cutadapt._seqio' */
-static PyObject *__pyx_builtin_Exception;
-static PyObject *__pyx_builtin_object;
 static PyObject *__pyx_builtin_NotImplementedError;
-static PyObject *__pyx_builtin_ValueError;
-static char __pyx_k_[] = "...";
+static PyObject *__pyx_builtin_super;
+static char __pyx_k_[] = "";
 static char __pyx_k_i[] = "i";
-static char __pyx_k_n[] = "n";
-static char __pyx_k_s[] = "s";
-static char __pyx_k__2[] = "";
-static char __pyx_k__3[] = "@";
-static char __pyx_k__4[] = "\r\n";
-static char __pyx_k__5[] = "+\n";
-static char __pyx_k__6[] = "+";
+static char __pyx_k__2[] = "@";
+static char __pyx_k__3[] = "\r\n";
+static char __pyx_k__4[] = "+\n";
+static char __pyx_k__5[] = "+";
 static char __pyx_k_it[] = "it";
 static char __pyx_k_doc[] = "__doc__";
 static char __pyx_k_args[] = "args";
-static char __pyx_k_exit[] = "__exit__";
 static char __pyx_k_file[] = "file";
 static char __pyx_k_init[] = "__init__";
 static char __pyx_k_iter[] = "__iter__";
@@ -871,83 +854,67 @@ static char __pyx_k_send[] = "send";
 static char __pyx_k_test[] = "__test__";
 static char __pyx_k_class[] = "__class__";
 static char __pyx_k_close[] = "close";
-static char __pyx_k_enter[] = "__enter__";
 static char __pyx_k_match[] = "match";
 static char __pyx_k_name2[] = "name2";
+static char __pyx_k_seqio[] = "seqio";
 static char __pyx_k_strip[] = "strip";
+static char __pyx_k_super[] = "super";
 static char __pyx_k_throw[] = "throw";
 static char __pyx_k_xopen[] = "xopen";
 static char __pyx_k_file_2[] = "_file";
 static char __pyx_k_format[] = "format";
 static char __pyx_k_import[] = "__import__";
 static char __pyx_k_module[] = "__module__";
-static char __pyx_k_object[] = "object";
 static char __pyx_k_rstrip[] = "rstrip";
 static char __pyx_k_prepare[] = "__prepare__";
 static char __pyx_k_shorten[] = "_shorten";
 static char __pyx_k_qualname[] = "__qualname__";
 static char __pyx_k_sequence[] = "sequence";
-static char __pyx_k_Exception[] = "Exception";
 static char __pyx_k_metaclass[] = "__metaclass__";
 static char __pyx_k_qualities[] = "qualities";
-static char __pyx_k_ValueError[] = "ValueError";
+static char __pyx_k_match_info[] = "match_info";
 static char __pyx_k_FastqReader[] = "FastqReader";
 static char __pyx_k_FormatError[] = "FormatError";
-static char __pyx_k_close_on_exit[] = "_close_on_exit";
 static char __pyx_k_qualities_0_r[] = ", qualities={0!r}";
+static char __pyx_k_SequenceReader[] = "SequenceReader";
 static char __pyx_k_sequence_class[] = "sequence_class";
 static char __pyx_k_cutadapt__seqio[] = "cutadapt._seqio";
-static char __pyx_k_FastqReader_close[] = "FastqReader.close";
-static char __pyx_k_FastqReader___exit[] = "FastqReader.__exit__";
 static char __pyx_k_FastqReader___init[] = "FastqReader.__init__";
 static char __pyx_k_FastqReader___iter[] = "FastqReader.__iter__";
 static char __pyx_k_delivers_qualities[] = "delivers_qualities";
-static char __pyx_k_FastqReader___enter[] = "FastqReader.__enter__";
 static char __pyx_k_NotImplementedError[] = "NotImplementedError";
 static char __pyx_k_FASTQ_file_ended_prematurely[] = "FASTQ file ended prematurely";
 static char __pyx_k_Sequence_name_0_r_sequence_1_r[] = "<Sequence(name={0!r}, sequence={1!r}{2})>";
 static char __pyx_k_At_line_0_Sequence_descriptions[] = "At line {0}: Sequence descriptions in the FASTQ file don't match ({1!r} != {2!r}).\nThe second sequence description must be either empty or equal to the first description.";
-static char __pyx_k_Raised_when_an_input_file_FASTA[] = "\n\tRaised when an input file (FASTA or FASTQ) is malformatted.\n\t";
 static char __pyx_k_Reader_for_FASTQ_files_Does_not[] = "\n\tReader for FASTQ files. Does not support multi-line FASTQ files.\n\t";
 static char __pyx_k_home_marcel_scm_cutadapt_cutada[] = "/home/marcel/scm/cutadapt/cutadapt/_seqio.pyx";
-static char __pyx_k_I_O_operation_on_closed_FastqRea[] = "I/O operation on closed FastqReader";
 static char __pyx_k_In_read_named_0_r_length_of_qual[] = "In read named {0!r}: length of quality sequence ({1}) and length of read ({2}) do not match";
 static char __pyx_k_Line_0_in_FASTQ_file_is_expected[] = "Line {0} in FASTQ file is expected to start with '@', but found {1!r}";
 static char __pyx_k_Line_0_in_FASTQ_file_is_expected_2[] = "Line {0} in FASTQ file is expected to start with '+', but found {1!r}";
 static PyObject *__pyx_kp_s_;
 static PyObject *__pyx_kp_s_At_line_0_Sequence_descriptions;
-static PyObject *__pyx_n_s_Exception;
 static PyObject *__pyx_kp_s_FASTQ_file_ended_prematurely;
 static PyObject *__pyx_n_s_FastqReader;
-static PyObject *__pyx_n_s_FastqReader___enter;
-static PyObject *__pyx_n_s_FastqReader___exit;
 static PyObject *__pyx_n_s_FastqReader___init;
 static PyObject *__pyx_n_s_FastqReader___iter;
-static PyObject *__pyx_n_s_FastqReader_close;
 static PyObject *__pyx_n_s_FormatError;
-static PyObject *__pyx_kp_s_I_O_operation_on_closed_FastqRea;
 static PyObject *__pyx_kp_s_In_read_named_0_r_length_of_qual;
 static PyObject *__pyx_kp_s_Line_0_in_FASTQ_file_is_expected;
 static PyObject *__pyx_kp_s_Line_0_in_FASTQ_file_is_expected_2;
 static PyObject *__pyx_n_s_NotImplementedError;
-static PyObject *__pyx_kp_s_Raised_when_an_input_file_FASTA;
 static PyObject *__pyx_kp_s_Reader_for_FASTQ_files_Does_not;
+static PyObject *__pyx_n_s_SequenceReader;
 static PyObject *__pyx_kp_s_Sequence_name_0_r_sequence_1_r;
-static PyObject *__pyx_n_s_ValueError;
 static PyObject *__pyx_kp_s__2;
 static PyObject *__pyx_kp_s__3;
 static PyObject *__pyx_kp_s__4;
 static PyObject *__pyx_kp_s__5;
-static PyObject *__pyx_kp_s__6;
 static PyObject *__pyx_n_s_args;
 static PyObject *__pyx_n_s_class;
 static PyObject *__pyx_n_s_close;
-static PyObject *__pyx_n_s_close_on_exit;
 static PyObject *__pyx_n_s_cutadapt__seqio;
 static PyObject *__pyx_n_s_delivers_qualities;
 static PyObject *__pyx_n_s_doc;
-static PyObject *__pyx_n_s_enter;
-static PyObject *__pyx_n_s_exit;
 static PyObject *__pyx_n_s_file;
 static PyObject *__pyx_n_s_file_2;
 static PyObject *__pyx_n_s_format;
@@ -960,29 +927,28 @@ static PyObject *__pyx_n_s_iter;
 static PyObject *__pyx_n_s_line;
 static PyObject *__pyx_n_s_main;
 static PyObject *__pyx_n_s_match;
+static PyObject *__pyx_n_s_match_info;
 static PyObject *__pyx_n_s_metaclass;
 static PyObject *__pyx_n_s_module;
-static PyObject *__pyx_n_s_n;
 static PyObject *__pyx_n_s_name;
 static PyObject *__pyx_n_s_name2;
-static PyObject *__pyx_n_s_object;
 static PyObject *__pyx_n_s_prepare;
 static PyObject *__pyx_n_s_qualities;
 static PyObject *__pyx_kp_s_qualities_0_r;
 static PyObject *__pyx_n_s_qualname;
 static PyObject *__pyx_n_s_rstrip;
-static PyObject *__pyx_n_s_s;
 static PyObject *__pyx_n_s_self;
 static PyObject *__pyx_n_s_send;
+static PyObject *__pyx_n_s_seqio;
 static PyObject *__pyx_n_s_sequence;
 static PyObject *__pyx_n_s_sequence_class;
 static PyObject *__pyx_n_s_shorten;
 static PyObject *__pyx_n_s_strip;
+static PyObject *__pyx_n_s_super;
 static PyObject *__pyx_n_s_test;
 static PyObject *__pyx_n_s_throw;
 static PyObject *__pyx_n_s_xopen;
-static PyObject *__pyx_pf_8cutadapt_6_seqio__shorten(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_s, PyObject *__pyx_v_n); /* proto */
-static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_name, PyObject *__pyx_v_sequence, PyObject *__pyx_v_qualities, PyObject *__pyx_v_name2, PyObject *__pyx_v_match); /* proto */
+static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_name, PyObject *__pyx_v_sequence, PyObject *__pyx_v_qualities, PyObject *__pyx_v_name2, PyObject *__pyx_v_match, PyObject *__pyx_v_match_info); /* proto */
 static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_key); /* proto */
 static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
 static Py_ssize_t __pyx_pf_8cutadapt_6_seqio_8Sequence_6__len__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
@@ -1003,233 +969,26 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_5name2_4__del__(struct __pyx_obj
 static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_5match___get__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
 static int __pyx_pf_8cutadapt_6_seqio_8Sequence_5match_2__set__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_value); /* proto */
 static int __pyx_pf_8cutadapt_6_seqio_8Sequence_5match_4__del__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_11__defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */
+static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info___get__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
+static int __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_2__set__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_value); /* proto */
+static int __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_4__del__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_5__defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */
 static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_file, PyObject *__pyx_v_sequence_class); /* proto */
 static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_2__iter__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_5close(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_7__enter__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_9__exit__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_args); /* proto */
 static PyObject *__pyx_tp_new_8cutadapt_6_seqio_Sequence(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
 static PyObject *__pyx_tp_new_8cutadapt_6_seqio___pyx_scope_struct____iter__(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
-static PyObject *__pyx_int_3;
-static PyObject *__pyx_int_100;
+static PyObject *__pyx_tuple__6;
 static PyObject *__pyx_tuple__7;
 static PyObject *__pyx_tuple__8;
-static PyObject *__pyx_tuple__9;
 static PyObject *__pyx_tuple__10;
-static PyObject *__pyx_tuple__12;
-static PyObject *__pyx_tuple__14;
-static PyObject *__pyx_tuple__16;
-static PyObject *__pyx_tuple__18;
-static PyObject *__pyx_tuple__20;
+static PyObject *__pyx_codeobj__9;
 static PyObject *__pyx_codeobj__11;
-static PyObject *__pyx_codeobj__13;
-static PyObject *__pyx_codeobj__15;
-static PyObject *__pyx_codeobj__17;
-static PyObject *__pyx_codeobj__19;
-static PyObject *__pyx_codeobj__21;
-
-/* "cutadapt/_seqio.pyx":16
- * 
- * 
- * def _shorten(s, n=100):             # <<<<<<<<<<<<<<
- * 	"""Shorten string s to at most n characters, appending "..." if necessary."""
- * 	if s is None:
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_8cutadapt_6_seqio_1_shorten(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_8cutadapt_6_seqio__shorten[] = "Shorten string s to at most n characters, appending \"...\" if necessary.";
-static PyMethodDef __pyx_mdef_8cutadapt_6_seqio_1_shorten = {"_shorten", (PyCFunction)__pyx_pw_8cutadapt_6_seqio_1_shorten, METH_VARARGS|METH_KEYWORDS, __pyx_doc_8cutadapt_6_seqio__shorten};
-static PyObject *__pyx_pw_8cutadapt_6_seqio_1_shorten(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  PyObject *__pyx_v_s = 0;
-  PyObject *__pyx_v_n = 0;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("_shorten (wrapper)", 0);
-  {
-    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_s,&__pyx_n_s_n,0};
-    PyObject* values[2] = {0,0};
-    values[1] = ((PyObject *)__pyx_int_100);
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_s)) != 0)) kw_args--;
-        else goto __pyx_L5_argtuple_error;
-        case  1:
-        if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_n);
-          if (value) { values[1] = value; kw_args--; }
-        }
-      }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_shorten") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else {
-      switch (PyTuple_GET_SIZE(__pyx_args)) {
-        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-    }
-    __pyx_v_s = values[0];
-    __pyx_v_n = values[1];
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("_shorten", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("cutadapt._seqio._shorten", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_8cutadapt_6_seqio__shorten(__pyx_self, __pyx_v_s, __pyx_v_n);
-
-  /* function exit code */
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static PyObject *__pyx_pf_8cutadapt_6_seqio__shorten(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_s, PyObject *__pyx_v_n) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  int __pyx_t_1;
-  int __pyx_t_2;
-  Py_ssize_t __pyx_t_3;
-  PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("_shorten", 0);
-  __Pyx_INCREF(__pyx_v_s);
-
-  /* "cutadapt/_seqio.pyx":18
- * def _shorten(s, n=100):
- * 	"""Shorten string s to at most n characters, appending "..." if necessary."""
- * 	if s is None:             # <<<<<<<<<<<<<<
- * 		return None
- * 	if len(s) > n:
- */
-  __pyx_t_1 = (__pyx_v_s == Py_None);
-  __pyx_t_2 = (__pyx_t_1 != 0);
-  if (__pyx_t_2) {
-
-    /* "cutadapt/_seqio.pyx":19
- * 	"""Shorten string s to at most n characters, appending "..." if necessary."""
- * 	if s is None:
- * 		return None             # <<<<<<<<<<<<<<
- * 	if len(s) > n:
- * 		s = s[:n-3] + '...'
- */
-    __Pyx_XDECREF(__pyx_r);
-    __Pyx_INCREF(Py_None);
-    __pyx_r = Py_None;
-    goto __pyx_L0;
-
-    /* "cutadapt/_seqio.pyx":18
- * def _shorten(s, n=100):
- * 	"""Shorten string s to at most n characters, appending "..." if necessary."""
- * 	if s is None:             # <<<<<<<<<<<<<<
- * 		return None
- * 	if len(s) > n:
- */
-  }
-
-  /* "cutadapt/_seqio.pyx":20
- * 	if s is None:
- * 		return None
- * 	if len(s) > n:             # <<<<<<<<<<<<<<
- * 		s = s[:n-3] + '...'
- * 	return s
- */
-  __pyx_t_3 = PyObject_Length(__pyx_v_s); if (unlikely(__pyx_t_3 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_4 = PyInt_FromSsize_t(__pyx_t_3); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_4);
-  __pyx_t_5 = PyObject_RichCompare(__pyx_t_4, __pyx_v_n, Py_GT); __Pyx_XGOTREF(__pyx_t_5); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-  if (__pyx_t_2) {
-
-    /* "cutadapt/_seqio.pyx":21
- * 		return None
- * 	if len(s) > n:
- * 		s = s[:n-3] + '...'             # <<<<<<<<<<<<<<
- * 	return s
- * 
- */
-    __pyx_t_5 = __Pyx_PyInt_SubtractObjC(__pyx_v_n, __pyx_int_3, 3, 0); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_5);
-    __pyx_t_4 = __Pyx_PyObject_GetSlice(__pyx_v_s, 0, 0, NULL, &__pyx_t_5, NULL, 0, 0, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    __pyx_t_5 = PyNumber_Add(__pyx_t_4, __pyx_kp_s_); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_5);
-    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-    __Pyx_DECREF_SET(__pyx_v_s, __pyx_t_5);
-    __pyx_t_5 = 0;
-
-    /* "cutadapt/_seqio.pyx":20
- * 	if s is None:
- * 		return None
- * 	if len(s) > n:             # <<<<<<<<<<<<<<
- * 		s = s[:n-3] + '...'
- * 	return s
- */
-  }
-
-  /* "cutadapt/_seqio.pyx":22
- * 	if len(s) > n:
- * 		s = s[:n-3] + '...'
- * 	return s             # <<<<<<<<<<<<<<
- * 
- * 
- */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(__pyx_v_s);
-  __pyx_r = __pyx_v_s;
-  goto __pyx_L0;
-
-  /* "cutadapt/_seqio.pyx":16
- * 
- * 
- * def _shorten(s, n=100):             # <<<<<<<<<<<<<<
- * 	"""Shorten string s to at most n characters, appending "..." if necessary."""
- * 	if s is None:
- */
-
-  /* function exit code */
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_AddTraceback("cutadapt._seqio._shorten", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_s);
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
 
-/* "cutadapt/_seqio.pyx":41
- * 		public object match
+/* "cutadapt/_seqio.pyx":25
+ * 		public object match_info
  * 
- * 	def __init__(self, str name, str sequence, str qualities=None, str name2='',             # <<<<<<<<<<<<<<
- * 			match=None):
+ * 	def __init__(self, str name, str sequence, str qualities=None, str name2='', match=None,             # <<<<<<<<<<<<<<
+ * 				 match_info=None):
  * 		"""Set qualities to None if there are no quality values"""
  */
 
@@ -1245,6 +1004,7 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
   PyObject *__pyx_v_qualities = 0;
   PyObject *__pyx_v_name2 = 0;
   PyObject *__pyx_v_match = 0;
+  PyObject *__pyx_v_match_info = 0;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
@@ -1252,23 +1012,25 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
   {
-    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_name,&__pyx_n_s_sequence,&__pyx_n_s_qualities,&__pyx_n_s_name2,&__pyx_n_s_match,0};
-    PyObject* values[5] = {0,0,0,0,0};
+    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_name,&__pyx_n_s_sequence,&__pyx_n_s_qualities,&__pyx_n_s_name2,&__pyx_n_s_match,&__pyx_n_s_match_info,0};
+    PyObject* values[6] = {0,0,0,0,0,0};
     values[2] = ((PyObject*)Py_None);
-    values[3] = ((PyObject*)__pyx_kp_s__2);
+    values[3] = ((PyObject*)__pyx_kp_s_);
+    values[4] = ((PyObject *)Py_None);
 
-    /* "cutadapt/_seqio.pyx":42
+    /* "cutadapt/_seqio.pyx":26
  * 
- * 	def __init__(self, str name, str sequence, str qualities=None, str name2='',
- * 			match=None):             # <<<<<<<<<<<<<<
+ * 	def __init__(self, str name, str sequence, str qualities=None, str name2='', match=None,
+ * 				 match_info=None):             # <<<<<<<<<<<<<<
  * 		"""Set qualities to None if there are no quality values"""
  * 		self.name = name
  */
-    values[4] = ((PyObject *)Py_None);
+    values[5] = ((PyObject *)Py_None);
     if (unlikely(__pyx_kwds)) {
       Py_ssize_t kw_args;
       const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
       switch (pos_args) {
+        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
         case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
         case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
         case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
@@ -1285,7 +1047,7 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_sequence)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 5, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 6, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
         }
         case  2:
         if (kw_args > 0) {
@@ -1302,12 +1064,18 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
           PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_match);
           if (value) { values[4] = value; kw_args--; }
         }
+        case  5:
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_match_info);
+          if (value) { values[5] = value; kw_args--; }
+        }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
+        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
         case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
         case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
         case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
@@ -1322,26 +1090,27 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
     __pyx_v_qualities = ((PyObject*)values[2]);
     __pyx_v_name2 = ((PyObject*)values[3]);
     __pyx_v_match = values[4];
+    __pyx_v_match_info = values[5];
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 5, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 6, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._seqio.Sequence.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return -1;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyString_Type), 1, "name", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_sequence), (&PyString_Type), 1, "sequence", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_qualities), (&PyString_Type), 1, "qualities", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name2), (&PyString_Type), 1, "name2", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self), __pyx_v_name, __pyx_v_sequence, __pyx_v_qualities, __pyx_v_name2, __pyx_v_match);
-
-  /* "cutadapt/_seqio.pyx":41
- * 		public object match
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyString_Type), 1, "name", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_sequence), (&PyString_Type), 1, "sequence", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_qualities), (&PyString_Type), 1, "qualities", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name2), (&PyString_Type), 1, "name2", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self), __pyx_v_name, __pyx_v_sequence, __pyx_v_qualities, __pyx_v_name2, __pyx_v_match, __pyx_v_match_info);
+
+  /* "cutadapt/_seqio.pyx":25
+ * 		public object match_info
  * 
- * 	def __init__(self, str name, str sequence, str qualities=None, str name2='',             # <<<<<<<<<<<<<<
- * 			match=None):
+ * 	def __init__(self, str name, str sequence, str qualities=None, str name2='', match=None,             # <<<<<<<<<<<<<<
+ * 				 match_info=None):
  * 		"""Set qualities to None if there are no quality values"""
  */
 
@@ -1354,7 +1123,7 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
   return __pyx_r;
 }
 
-static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_name, PyObject *__pyx_v_sequence, PyObject *__pyx_v_qualities, PyObject *__pyx_v_name2, PyObject *__pyx_v_match) {
+static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_name, PyObject *__pyx_v_sequence, PyObject *__pyx_v_qualities, PyObject *__pyx_v_name2, PyObject *__pyx_v_match, PyObject *__pyx_v_match_info) {
   PyObject *__pyx_v_rname = NULL;
   int __pyx_r;
   __Pyx_RefNannyDeclarations
@@ -1376,8 +1145,8 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__init__", 0);
 
-  /* "cutadapt/_seqio.pyx":44
- * 			match=None):
+  /* "cutadapt/_seqio.pyx":28
+ * 				 match_info=None):
  * 		"""Set qualities to None if there are no quality values"""
  * 		self.name = name             # <<<<<<<<<<<<<<
  * 		self.sequence = sequence
@@ -1389,7 +1158,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   __Pyx_DECREF(__pyx_v_self->name);
   __pyx_v_self->name = __pyx_v_name;
 
-  /* "cutadapt/_seqio.pyx":45
+  /* "cutadapt/_seqio.pyx":29
  * 		"""Set qualities to None if there are no quality values"""
  * 		self.name = name
  * 		self.sequence = sequence             # <<<<<<<<<<<<<<
@@ -1402,7 +1171,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   __Pyx_DECREF(__pyx_v_self->sequence);
   __pyx_v_self->sequence = __pyx_v_sequence;
 
-  /* "cutadapt/_seqio.pyx":46
+  /* "cutadapt/_seqio.pyx":30
  * 		self.name = name
  * 		self.sequence = sequence
  * 		self.qualities = qualities             # <<<<<<<<<<<<<<
@@ -1415,12 +1184,12 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   __Pyx_DECREF(__pyx_v_self->qualities);
   __pyx_v_self->qualities = __pyx_v_qualities;
 
-  /* "cutadapt/_seqio.pyx":47
+  /* "cutadapt/_seqio.pyx":31
  * 		self.sequence = sequence
  * 		self.qualities = qualities
  * 		self.name2 = name2             # <<<<<<<<<<<<<<
  * 		self.match = match
- * 		if qualities is not None and len(qualities) != len(sequence):
+ * 		self.match_info = match_info
  */
   __Pyx_INCREF(__pyx_v_name2);
   __Pyx_GIVEREF(__pyx_v_name2);
@@ -1428,12 +1197,12 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   __Pyx_DECREF(__pyx_v_self->name2);
   __pyx_v_self->name2 = __pyx_v_name2;
 
-  /* "cutadapt/_seqio.pyx":48
+  /* "cutadapt/_seqio.pyx":32
  * 		self.qualities = qualities
  * 		self.name2 = name2
  * 		self.match = match             # <<<<<<<<<<<<<<
+ * 		self.match_info = match_info
  * 		if qualities is not None and len(qualities) != len(sequence):
- * 			rname = _shorten(name)
  */
   __Pyx_INCREF(__pyx_v_match);
   __Pyx_GIVEREF(__pyx_v_match);
@@ -1441,12 +1210,25 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   __Pyx_DECREF(__pyx_v_self->match);
   __pyx_v_self->match = __pyx_v_match;
 
-  /* "cutadapt/_seqio.pyx":49
+  /* "cutadapt/_seqio.pyx":33
  * 		self.name2 = name2
  * 		self.match = match
+ * 		self.match_info = match_info             # <<<<<<<<<<<<<<
+ * 		if qualities is not None and len(qualities) != len(sequence):
+ * 			rname = _shorten(name)
+ */
+  __Pyx_INCREF(__pyx_v_match_info);
+  __Pyx_GIVEREF(__pyx_v_match_info);
+  __Pyx_GOTREF(__pyx_v_self->match_info);
+  __Pyx_DECREF(__pyx_v_self->match_info);
+  __pyx_v_self->match_info = __pyx_v_match_info;
+
+  /* "cutadapt/_seqio.pyx":34
+ * 		self.match = match
+ * 		self.match_info = match_info
  * 		if qualities is not None and len(qualities) != len(sequence):             # <<<<<<<<<<<<<<
  * 			rname = _shorten(name)
- * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length of read ({2}) do not match".format(
+ * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length "
  */
   __pyx_t_2 = (__pyx_v_qualities != ((PyObject*)Py_None));
   __pyx_t_3 = (__pyx_t_2 != 0);
@@ -1455,21 +1237,21 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
     __pyx_t_1 = __pyx_t_3;
     goto __pyx_L4_bool_binop_done;
   }
-  __pyx_t_4 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_5 = PyObject_Length(__pyx_v_sequence); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_5 = PyObject_Length(__pyx_v_sequence); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_t_3 = ((__pyx_t_4 != __pyx_t_5) != 0);
   __pyx_t_1 = __pyx_t_3;
   __pyx_L4_bool_binop_done:;
   if (__pyx_t_1) {
 
-    /* "cutadapt/_seqio.pyx":50
- * 		self.match = match
+    /* "cutadapt/_seqio.pyx":35
+ * 		self.match_info = match_info
  * 		if qualities is not None and len(qualities) != len(sequence):
  * 			rname = _shorten(name)             # <<<<<<<<<<<<<<
- * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length of read ({2}) do not match".format(
- * 				rname, len(qualities), len(sequence)))
+ * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length "
+ * 				"of read ({2}) do not match".format(
  */
-    __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_7);
     __pyx_t_8 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_7))) {
@@ -1482,16 +1264,16 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
       }
     }
     if (!__pyx_t_8) {
-      __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_name); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_name); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_6);
     } else {
-      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_9);
       __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
       __Pyx_INCREF(__pyx_v_name);
       __Pyx_GIVEREF(__pyx_v_name);
       PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_name);
-      __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_6);
       __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
     }
@@ -1499,30 +1281,38 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
     __pyx_v_rname = __pyx_t_6;
     __pyx_t_6 = 0;
 
-    /* "cutadapt/_seqio.pyx":51
+    /* "cutadapt/_seqio.pyx":36
  * 		if qualities is not None and len(qualities) != len(sequence):
  * 			rname = _shorten(name)
- * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length of read ({2}) do not match".format(             # <<<<<<<<<<<<<<
- * 				rname, len(qualities), len(sequence)))
- * 
+ * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length "             # <<<<<<<<<<<<<<
+ * 				"of read ({2}) do not match".format(
+ * 					rname, len(qualities), len(sequence)))
  */
-    __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_7);
-    __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_In_read_named_0_r_length_of_qual, __pyx_n_s_format); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_8);
 
-    /* "cutadapt/_seqio.pyx":52
+    /* "cutadapt/_seqio.pyx":37
  * 			rname = _shorten(name)
- * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length of read ({2}) do not match".format(
- * 				rname, len(qualities), len(sequence)))             # <<<<<<<<<<<<<<
+ * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length "
+ * 				"of read ({2}) do not match".format(             # <<<<<<<<<<<<<<
+ * 					rname, len(qualities), len(sequence)))
+ * 
+ */
+    __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_In_read_named_0_r_length_of_qual, __pyx_n_s_format); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_8);
+
+    /* "cutadapt/_seqio.pyx":38
+ * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length "
+ * 				"of read ({2}) do not match".format(
+ * 					rname, len(qualities), len(sequence)))             # <<<<<<<<<<<<<<
  * 
  * 	def __getitem__(self, key):
  */
-    __pyx_t_5 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_10 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_10 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_10);
-    __pyx_t_5 = PyObject_Length(__pyx_v_sequence); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_11 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = PyObject_Length(__pyx_v_sequence); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_11 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_11);
     __pyx_t_12 = NULL;
     __pyx_t_5 = 0;
@@ -1536,7 +1326,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
         __pyx_t_5 = 1;
       }
     }
-    __pyx_t_13 = PyTuple_New(3+__pyx_t_5); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_13 = PyTuple_New(3+__pyx_t_5); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_13);
     if (__pyx_t_12) {
       __Pyx_GIVEREF(__pyx_t_12); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_12); __pyx_t_12 = NULL;
@@ -1550,7 +1340,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
     PyTuple_SET_ITEM(__pyx_t_13, 2+__pyx_t_5, __pyx_t_11);
     __pyx_t_10 = 0;
     __pyx_t_11 = 0;
-    __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_13, NULL); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_13, NULL); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_9);
     __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
     __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
@@ -1565,39 +1355,39 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
       }
     }
     if (!__pyx_t_8) {
-      __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_9); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_9); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
       __Pyx_GOTREF(__pyx_t_6);
     } else {
-      __pyx_t_13 = PyTuple_New(1+1); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_13 = PyTuple_New(1+1); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_13);
       __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_8); __pyx_t_8 = NULL;
       __Pyx_GIVEREF(__pyx_t_9);
       PyTuple_SET_ITEM(__pyx_t_13, 0+1, __pyx_t_9);
       __pyx_t_9 = 0;
-      __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_13, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_13, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_6);
       __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
     }
     __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
     __Pyx_Raise(__pyx_t_6, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-    /* "cutadapt/_seqio.pyx":49
- * 		self.name2 = name2
+    /* "cutadapt/_seqio.pyx":34
  * 		self.match = match
+ * 		self.match_info = match_info
  * 		if qualities is not None and len(qualities) != len(sequence):             # <<<<<<<<<<<<<<
  * 			rname = _shorten(name)
- * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length of read ({2}) do not match".format(
+ * 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length "
  */
   }
 
-  /* "cutadapt/_seqio.pyx":41
- * 		public object match
+  /* "cutadapt/_seqio.pyx":25
+ * 		public object match_info
  * 
- * 	def __init__(self, str name, str sequence, str qualities=None, str name2='',             # <<<<<<<<<<<<<<
- * 			match=None):
+ * 	def __init__(self, str name, str sequence, str qualities=None, str name2='', match=None,             # <<<<<<<<<<<<<<
+ * 				 match_info=None):
  * 		"""Set qualities to None if there are no quality values"""
  */
 
@@ -1621,8 +1411,8 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":54
- * 				rname, len(qualities), len(sequence)))
+/* "cutadapt/_seqio.pyx":40
+ * 					rname, len(qualities), len(sequence)))
  * 
  * 	def __getitem__(self, key):             # <<<<<<<<<<<<<<
  * 		"""slicing"""
@@ -1662,7 +1452,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__getitem__", 0);
 
-  /* "cutadapt/_seqio.pyx":56
+  /* "cutadapt/_seqio.pyx":42
  * 	def __getitem__(self, key):
  * 		"""slicing"""
  * 		return self.__class__(             # <<<<<<<<<<<<<<
@@ -1670,29 +1460,29 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
  * 			self.sequence[key],
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_class); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_class); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
 
-  /* "cutadapt/_seqio.pyx":58
+  /* "cutadapt/_seqio.pyx":44
  * 		return self.__class__(
  * 			self.name,
  * 			self.sequence[key],             # <<<<<<<<<<<<<<
  * 			self.qualities[key] if self.qualities is not None else None,
  * 			self.name2,
  */
-  __pyx_t_3 = PyObject_GetItem(__pyx_v_self->sequence, __pyx_v_key); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_t_3 = PyObject_GetItem(__pyx_v_self->sequence, __pyx_v_key); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
   __Pyx_GOTREF(__pyx_t_3);
 
-  /* "cutadapt/_seqio.pyx":59
+  /* "cutadapt/_seqio.pyx":45
  * 			self.name,
  * 			self.sequence[key],
  * 			self.qualities[key] if self.qualities is not None else None,             # <<<<<<<<<<<<<<
  * 			self.name2,
- * 			self.match)
+ * 			self.match,
  */
   __pyx_t_5 = (__pyx_v_self->qualities != ((PyObject*)Py_None));
   if ((__pyx_t_5 != 0)) {
-    __pyx_t_6 = PyObject_GetItem(__pyx_v_self->qualities, __pyx_v_key); if (unlikely(__pyx_t_6 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+    __pyx_t_6 = PyObject_GetItem(__pyx_v_self->qualities, __pyx_v_key); if (unlikely(__pyx_t_6 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
     __Pyx_GOTREF(__pyx_t_6);
     __pyx_t_4 = __pyx_t_6;
     __pyx_t_6 = 0;
@@ -1701,10 +1491,10 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
     __pyx_t_4 = Py_None;
   }
 
-  /* "cutadapt/_seqio.pyx":61
- * 			self.qualities[key] if self.qualities is not None else None,
+  /* "cutadapt/_seqio.pyx":48
  * 			self.name2,
- * 			self.match)             # <<<<<<<<<<<<<<
+ * 			self.match,
+ * 			self.match_info)             # <<<<<<<<<<<<<<
  * 
  * 	def __repr__(self):
  */
@@ -1720,7 +1510,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
       __pyx_t_7 = 1;
     }
   }
-  __pyx_t_8 = PyTuple_New(5+__pyx_t_7); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_8 = PyTuple_New(6+__pyx_t_7); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_8);
   if (__pyx_t_6) {
     __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL;
@@ -1738,9 +1528,12 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
   __Pyx_INCREF(__pyx_v_self->match);
   __Pyx_GIVEREF(__pyx_v_self->match);
   PyTuple_SET_ITEM(__pyx_t_8, 4+__pyx_t_7, __pyx_v_self->match);
+  __Pyx_INCREF(__pyx_v_self->match_info);
+  __Pyx_GIVEREF(__pyx_v_self->match_info);
+  PyTuple_SET_ITEM(__pyx_t_8, 5+__pyx_t_7, __pyx_v_self->match_info);
   __pyx_t_3 = 0;
   __pyx_t_4 = 0;
-  __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -1748,8 +1541,8 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_seqio.pyx":54
- * 				rname, len(qualities), len(sequence)))
+  /* "cutadapt/_seqio.pyx":40
+ * 					rname, len(qualities), len(sequence)))
  * 
  * 	def __getitem__(self, key):             # <<<<<<<<<<<<<<
  * 		"""slicing"""
@@ -1772,8 +1565,8 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":63
- * 			self.match)
+/* "cutadapt/_seqio.pyx":50
+ * 			self.match_info)
  * 
  * 	def __repr__(self):             # <<<<<<<<<<<<<<
  * 		qstr = ''
@@ -1812,17 +1605,17 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__repr__", 0);
 
-  /* "cutadapt/_seqio.pyx":64
+  /* "cutadapt/_seqio.pyx":51
  * 
  * 	def __repr__(self):
  * 		qstr = ''             # <<<<<<<<<<<<<<
  * 		if self.qualities is not None:
  * 			qstr = ', qualities={0!r}'.format(_shorten(self.qualities))
  */
-  __Pyx_INCREF(__pyx_kp_s__2);
-  __pyx_v_qstr = __pyx_kp_s__2;
+  __Pyx_INCREF(__pyx_kp_s_);
+  __pyx_v_qstr = __pyx_kp_s_;
 
-  /* "cutadapt/_seqio.pyx":65
+  /* "cutadapt/_seqio.pyx":52
  * 	def __repr__(self):
  * 		qstr = ''
  * 		if self.qualities is not None:             # <<<<<<<<<<<<<<
@@ -1833,16 +1626,16 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
   __pyx_t_2 = (__pyx_t_1 != 0);
   if (__pyx_t_2) {
 
-    /* "cutadapt/_seqio.pyx":66
+    /* "cutadapt/_seqio.pyx":53
  * 		qstr = ''
  * 		if self.qualities is not None:
  * 			qstr = ', qualities={0!r}'.format(_shorten(self.qualities))             # <<<<<<<<<<<<<<
  * 		return '<Sequence(name={0!r}, sequence={1!r}{2})>'.format(_shorten(self.name), _shorten(self.sequence), qstr)
  * 
  */
-    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_qualities_0_r, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_qualities_0_r, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_6);
     __pyx_t_7 = NULL;
     if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_6))) {
@@ -1855,16 +1648,16 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
       }
     }
     if (!__pyx_t_7) {
-      __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_v_self->qualities); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_v_self->qualities); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_5);
     } else {
-      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_8);
       __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL;
       __Pyx_INCREF(__pyx_v_self->qualities);
       __Pyx_GIVEREF(__pyx_v_self->qualities);
       PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_v_self->qualities);
-      __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_5);
       __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
     }
@@ -1880,17 +1673,17 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
       }
     }
     if (!__pyx_t_6) {
-      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
       __Pyx_GOTREF(__pyx_t_3);
     } else {
-      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_8);
       __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL;
       __Pyx_GIVEREF(__pyx_t_5);
       PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_5);
       __pyx_t_5 = 0;
-      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_3);
       __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
     }
@@ -1898,7 +1691,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
     __Pyx_DECREF_SET(__pyx_v_qstr, __pyx_t_3);
     __pyx_t_3 = 0;
 
-    /* "cutadapt/_seqio.pyx":65
+    /* "cutadapt/_seqio.pyx":52
  * 	def __repr__(self):
  * 		qstr = ''
  * 		if self.qualities is not None:             # <<<<<<<<<<<<<<
@@ -1907,7 +1700,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
  */
   }
 
-  /* "cutadapt/_seqio.pyx":67
+  /* "cutadapt/_seqio.pyx":54
  * 		if self.qualities is not None:
  * 			qstr = ', qualities={0!r}'.format(_shorten(self.qualities))
  * 		return '<Sequence(name={0!r}, sequence={1!r}{2})>'.format(_shorten(self.name), _shorten(self.sequence), qstr)             # <<<<<<<<<<<<<<
@@ -1915,9 +1708,9 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
  * 	def __len__(self):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Sequence_name_0_r_sequence_1_r, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Sequence_name_0_r_sequence_1_r, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_4);
-  __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_5);
   __pyx_t_6 = NULL;
   if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_5))) {
@@ -1930,21 +1723,21 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
     }
   }
   if (!__pyx_t_6) {
-    __pyx_t_8 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_self->name); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_8 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_self->name); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_8);
   } else {
-    __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_7);
     __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
     __Pyx_INCREF(__pyx_v_self->name);
     __Pyx_GIVEREF(__pyx_v_self->name);
     PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_v_self->name);
-    __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_8);
     __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
   }
   __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-  __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_7);
   __pyx_t_6 = NULL;
   if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_7))) {
@@ -1957,16 +1750,16 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
     }
   }
   if (!__pyx_t_6) {
-    __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_self->sequence); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_self->sequence); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_5);
   } else {
-    __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_9);
     __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL;
     __Pyx_INCREF(__pyx_v_self->sequence);
     __Pyx_GIVEREF(__pyx_v_self->sequence);
     PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_self->sequence);
-    __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_5);
     __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
   }
@@ -1983,7 +1776,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
       __pyx_t_10 = 1;
     }
   }
-  __pyx_t_9 = PyTuple_New(3+__pyx_t_10); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_9 = PyTuple_New(3+__pyx_t_10); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_9);
   if (__pyx_t_7) {
     __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL;
@@ -1997,7 +1790,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
   PyTuple_SET_ITEM(__pyx_t_9, 2+__pyx_t_10, __pyx_v_qstr);
   __pyx_t_8 = 0;
   __pyx_t_5 = 0;
-  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
@@ -2005,8 +1798,8 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
   __pyx_t_3 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_seqio.pyx":63
- * 			self.match)
+  /* "cutadapt/_seqio.pyx":50
+ * 			self.match_info)
  * 
  * 	def __repr__(self):             # <<<<<<<<<<<<<<
  * 		qstr = ''
@@ -2031,7 +1824,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":69
+/* "cutadapt/_seqio.pyx":56
  * 		return '<Sequence(name={0!r}, sequence={1!r}{2})>'.format(_shorten(self.name), _shorten(self.sequence), qstr)
  * 
  * 	def __len__(self):             # <<<<<<<<<<<<<<
@@ -2062,7 +1855,7 @@ static Py_ssize_t __pyx_pf_8cutadapt_6_seqio_8Sequence_6__len__(struct __pyx_obj
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__len__", 0);
 
-  /* "cutadapt/_seqio.pyx":70
+  /* "cutadapt/_seqio.pyx":57
  * 
  * 	def __len__(self):
  * 		return len(self.sequence)             # <<<<<<<<<<<<<<
@@ -2071,12 +1864,12 @@ static Py_ssize_t __pyx_pf_8cutadapt_6_seqio_8Sequence_6__len__(struct __pyx_obj
  */
   __pyx_t_1 = __pyx_v_self->sequence;
   __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __pyx_r = __pyx_t_2;
   goto __pyx_L0;
 
-  /* "cutadapt/_seqio.pyx":69
+  /* "cutadapt/_seqio.pyx":56
  * 		return '<Sequence(name={0!r}, sequence={1!r}{2})>'.format(_shorten(self.name), _shorten(self.sequence), qstr)
  * 
  * 	def __len__(self):             # <<<<<<<<<<<<<<
@@ -2094,7 +1887,7 @@ static Py_ssize_t __pyx_pf_8cutadapt_6_seqio_8Sequence_6__len__(struct __pyx_obj
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":72
+/* "cutadapt/_seqio.pyx":59
  * 		return len(self.sequence)
  * 
  * 	def __richcmp__(self, other, int op):             # <<<<<<<<<<<<<<
@@ -2130,7 +1923,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__richcmp__", 0);
 
-  /* "cutadapt/_seqio.pyx":73
+  /* "cutadapt/_seqio.pyx":60
  * 
  * 	def __richcmp__(self, other, int op):
  * 		if 2 <= op <= 3:             # <<<<<<<<<<<<<<
@@ -2144,21 +1937,21 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
   __pyx_t_2 = (__pyx_t_1 != 0);
   if (__pyx_t_2) {
 
-    /* "cutadapt/_seqio.pyx":74
+    /* "cutadapt/_seqio.pyx":61
  * 	def __richcmp__(self, other, int op):
  * 		if 2 <= op <= 3:
  * 			eq = self.name == other.name and \             # <<<<<<<<<<<<<<
  * 				self.sequence == other.sequence and \
  * 				self.qualities == other.qualities
  */
-    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_name); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_name); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_name); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_name); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_5);
-    __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     if (__pyx_t_2) {
       __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
     } else {
@@ -2168,21 +1961,21 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
       goto __pyx_L4_bool_binop_done;
     }
 
-    /* "cutadapt/_seqio.pyx":75
+    /* "cutadapt/_seqio.pyx":62
  * 		if 2 <= op <= 3:
  * 			eq = self.name == other.name and \
  * 				self.sequence == other.sequence and \             # <<<<<<<<<<<<<<
  * 				self.qualities == other.qualities
  * 			if op == 2:
  */
-    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_sequence); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_sequence); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_6);
-    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_sequence); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_sequence); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_5);
-    __pyx_t_4 = PyObject_RichCompare(__pyx_t_6, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = PyObject_RichCompare(__pyx_t_6, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     if (__pyx_t_2) {
       __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
     } else {
@@ -2192,18 +1985,18 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
       goto __pyx_L4_bool_binop_done;
     }
 
-    /* "cutadapt/_seqio.pyx":76
+    /* "cutadapt/_seqio.pyx":63
  * 			eq = self.name == other.name and \
  * 				self.sequence == other.sequence and \
  * 				self.qualities == other.qualities             # <<<<<<<<<<<<<<
  * 			if op == 2:
  * 				return eq
  */
-    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_qualities); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_qualities); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_qualities); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_qualities); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_5);
-    __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
     __Pyx_INCREF(__pyx_t_6);
@@ -2213,7 +2006,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
     __pyx_v_eq = __pyx_t_3;
     __pyx_t_3 = 0;
 
-    /* "cutadapt/_seqio.pyx":77
+    /* "cutadapt/_seqio.pyx":64
  * 				self.sequence == other.sequence and \
  * 				self.qualities == other.qualities
  * 			if op == 2:             # <<<<<<<<<<<<<<
@@ -2223,7 +2016,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
     __pyx_t_2 = ((__pyx_v_op == 2) != 0);
     if (__pyx_t_2) {
 
-      /* "cutadapt/_seqio.pyx":78
+      /* "cutadapt/_seqio.pyx":65
  * 				self.qualities == other.qualities
  * 			if op == 2:
  * 				return eq             # <<<<<<<<<<<<<<
@@ -2235,7 +2028,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
       __pyx_r = __pyx_v_eq;
       goto __pyx_L0;
 
-      /* "cutadapt/_seqio.pyx":77
+      /* "cutadapt/_seqio.pyx":64
  * 				self.sequence == other.sequence and \
  * 				self.qualities == other.qualities
  * 			if op == 2:             # <<<<<<<<<<<<<<
@@ -2244,7 +2037,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
  */
     }
 
-    /* "cutadapt/_seqio.pyx":80
+    /* "cutadapt/_seqio.pyx":67
  * 				return eq
  * 			else:
  * 				return not eq             # <<<<<<<<<<<<<<
@@ -2253,15 +2046,15 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
  */
     /*else*/ {
       __Pyx_XDECREF(__pyx_r);
-      __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_v_eq); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 80; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_3 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 80; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_v_eq); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_3);
       __pyx_r = __pyx_t_3;
       __pyx_t_3 = 0;
       goto __pyx_L0;
     }
 
-    /* "cutadapt/_seqio.pyx":73
+    /* "cutadapt/_seqio.pyx":60
  * 
  * 	def __richcmp__(self, other, int op):
  * 		if 2 <= op <= 3:             # <<<<<<<<<<<<<<
@@ -2270,7 +2063,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
  */
   }
 
-  /* "cutadapt/_seqio.pyx":82
+  /* "cutadapt/_seqio.pyx":69
  * 				return not eq
  * 		else:
  * 			raise NotImplementedError()             # <<<<<<<<<<<<<<
@@ -2278,14 +2071,14 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
  * 	def __reduce__(self):
  */
   /*else*/ {
-    __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_builtin_NotImplementedError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_builtin_NotImplementedError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
     __Pyx_Raise(__pyx_t_3, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
 
-  /* "cutadapt/_seqio.pyx":72
+  /* "cutadapt/_seqio.pyx":59
  * 		return len(self.sequence)
  * 
  * 	def __richcmp__(self, other, int op):             # <<<<<<<<<<<<<<
@@ -2308,7 +2101,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":84
+/* "cutadapt/_seqio.pyx":71
  * 			raise NotImplementedError()
  * 
  * 	def __reduce__(self):             # <<<<<<<<<<<<<<
@@ -2339,7 +2132,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10__reduce__(struct __pyx_
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__reduce__", 0);
 
-  /* "cutadapt/_seqio.pyx":85
+  /* "cutadapt/_seqio.pyx":72
  * 
  * 	def __reduce__(self):
  * 		return (Sequence, (self.name, self.sequence, self.qualities, self.name2))             # <<<<<<<<<<<<<<
@@ -2347,7 +2140,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10__reduce__(struct __pyx_
  * 
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyTuple_New(4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyTuple_New(4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 72; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(__pyx_v_self->name);
   __Pyx_GIVEREF(__pyx_v_self->name);
@@ -2361,7 +2154,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10__reduce__(struct __pyx_
   __Pyx_INCREF(__pyx_v_self->name2);
   __Pyx_GIVEREF(__pyx_v_self->name2);
   PyTuple_SET_ITEM(__pyx_t_1, 3, __pyx_v_self->name2);
-  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 72; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_INCREF(((PyObject *)__pyx_ptype_8cutadapt_6_seqio_Sequence));
   __Pyx_GIVEREF(((PyObject *)__pyx_ptype_8cutadapt_6_seqio_Sequence));
@@ -2373,7 +2166,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10__reduce__(struct __pyx_
   __pyx_t_2 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_seqio.pyx":84
+  /* "cutadapt/_seqio.pyx":71
  * 			raise NotImplementedError()
  * 
  * 	def __reduce__(self):             # <<<<<<<<<<<<<<
@@ -2393,7 +2186,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10__reduce__(struct __pyx_
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":35
+/* "cutadapt/_seqio.pyx":18
  * 	"""
  * 	cdef:
  * 		public str name             # <<<<<<<<<<<<<<
@@ -2451,7 +2244,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_4name_2__set__(struct __pyx_obj_
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__set__", 0);
-  if (!(likely(PyString_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyString_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_t_1 = __pyx_v_value;
   __Pyx_INCREF(__pyx_t_1);
   __Pyx_GIVEREF(__pyx_t_1);
@@ -2501,7 +2294,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_4name_4__del__(struct __pyx_obj_
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":36
+/* "cutadapt/_seqio.pyx":19
  * 	cdef:
  * 		public str name
  * 		public str sequence             # <<<<<<<<<<<<<<
@@ -2559,7 +2352,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_8sequence_2__set__(struct __pyx_
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__set__", 0);
-  if (!(likely(PyString_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyString_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_t_1 = __pyx_v_value;
   __Pyx_INCREF(__pyx_t_1);
   __Pyx_GIVEREF(__pyx_t_1);
@@ -2609,7 +2402,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_8sequence_4__del__(struct __pyx_
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":37
+/* "cutadapt/_seqio.pyx":20
  * 		public str name
  * 		public str sequence
  * 		public str qualities             # <<<<<<<<<<<<<<
@@ -2667,7 +2460,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_9qualities_2__set__(struct __pyx
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__set__", 0);
-  if (!(likely(PyString_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyString_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_t_1 = __pyx_v_value;
   __Pyx_INCREF(__pyx_t_1);
   __Pyx_GIVEREF(__pyx_t_1);
@@ -2717,12 +2510,12 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_9qualities_4__del__(struct __pyx
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":38
+/* "cutadapt/_seqio.pyx":21
  * 		public str sequence
  * 		public str qualities
  * 		public str name2             # <<<<<<<<<<<<<<
  * 		public object match
- * 
+ * 		public object match_info
  */
 
 /* Python wrapper */
@@ -2775,7 +2568,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_5name2_2__set__(struct __pyx_obj
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__set__", 0);
-  if (!(likely(PyString_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyString_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_t_1 = __pyx_v_value;
   __Pyx_INCREF(__pyx_t_1);
   __Pyx_GIVEREF(__pyx_t_1);
@@ -2825,12 +2618,12 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_5name2_4__del__(struct __pyx_obj
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":39
+/* "cutadapt/_seqio.pyx":22
  * 		public str qualities
  * 		public str name2
  * 		public object match             # <<<<<<<<<<<<<<
+ * 		public object match_info
  * 
- * 	def __init__(self, str name, str sequence, str qualities=None, str name2='',
  */
 
 /* Python wrapper */
@@ -2920,15 +2713,110 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_5match_4__del__(struct __pyx_obj
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":94
- * 	_close_on_exit = False
+/* "cutadapt/_seqio.pyx":23
+ * 		public str name2
+ * 		public object match
+ * 		public object match_info             # <<<<<<<<<<<<<<
  * 
+ * 	def __init__(self, str name, str sequence, str qualities=None, str name2='', match=None,
+ */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info___get__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self));
+
+  /* function exit code */
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info___get__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(__pyx_v_self->match_info);
+  __pyx_r = __pyx_v_self->match_info;
+  goto __pyx_L0;
+
+  /* function exit code */
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
+static int __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_2__set__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self), ((PyObject *)__pyx_v_value));
+
+  /* function exit code */
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static int __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_2__set__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__set__", 0);
+  __Pyx_INCREF(__pyx_v_value);
+  __Pyx_GIVEREF(__pyx_v_value);
+  __Pyx_GOTREF(__pyx_v_self->match_info);
+  __Pyx_DECREF(__pyx_v_self->match_info);
+  __pyx_v_self->match_info = __pyx_v_value;
+
+  /* function exit code */
+  __pyx_r = 0;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_5__del__(PyObject *__pyx_v_self); /*proto*/
+static int __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_5__del__(PyObject *__pyx_v_self) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__del__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_4__del__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self));
+
+  /* function exit code */
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static int __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_4__del__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__del__", 0);
+  __Pyx_INCREF(Py_None);
+  __Pyx_GIVEREF(Py_None);
+  __Pyx_GOTREF(__pyx_v_self->match_info);
+  __Pyx_DECREF(__pyx_v_self->match_info);
+  __pyx_v_self->match_info = Py_None;
+
+  /* function exit code */
+  __pyx_r = 0;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "cutadapt/_seqio.pyx":79
+ * 	Reader for FASTQ files. Does not support multi-line FASTQ files.
+ * 	"""
  * 	def __init__(self, file, sequence_class=Sequence):             # <<<<<<<<<<<<<<
  * 		"""
  * 		file is a filename or a file-like object.
  */
 
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_11__defaults__(CYTHON_UNUSED PyObject *__pyx_self) {
+static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_5__defaults__(CYTHON_UNUSED PyObject *__pyx_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -2938,12 +2826,12 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_11__defaults__(CYTHON_
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__defaults__", 0);
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(__Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_sequence_class);
   __Pyx_GIVEREF(__Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_sequence_class);
   PyTuple_SET_ITEM(__pyx_t_1, 0, __Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_sequence_class);
-  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_GIVEREF(__pyx_t_1);
   PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1);
@@ -3004,7 +2892,7 @@ static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_1__init__(PyObject *__
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_file)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
         }
         case  2:
         if (kw_args > 0) {
@@ -3013,7 +2901,7 @@ static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_1__init__(PyObject *__
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -3030,7 +2918,7 @@ static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_1__init__(PyObject *__
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._seqio.FastqReader.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
@@ -3046,114 +2934,86 @@ static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_1__init__(PyObject *__
 static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_file, PyObject *__pyx_v_sequence_class) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  int __pyx_t_1;
-  int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
   PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
-  PyObject *__pyx_t_6 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__init__", 0);
-  __Pyx_INCREF(__pyx_v_file);
 
-  /* "cutadapt/_seqio.pyx":99
+  /* "cutadapt/_seqio.pyx":84
  * 		If file is a filename, then .gz files are supported.
  * 		"""
- * 		if isinstance(file, basestring):             # <<<<<<<<<<<<<<
- * 			file = xopen(file)
- * 			self._close_on_exit = True
- */
-  __pyx_t_1 = __Pyx_PyBaseString_Check(__pyx_v_file); 
-  __pyx_t_2 = (__pyx_t_1 != 0);
-  if (__pyx_t_2) {
-
-    /* "cutadapt/_seqio.pyx":100
- * 		"""
- * 		if isinstance(file, basestring):
- * 			file = xopen(file)             # <<<<<<<<<<<<<<
- * 			self._close_on_exit = True
- * 		self._file = file
+ * 		super(FastqReader, self).__init__(file)             # <<<<<<<<<<<<<<
+ * 		self.sequence_class = sequence_class
+ * 		self.delivers_qualities = True
  */
-    __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_xopen); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_5 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_4))) {
-      __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4);
-      if (likely(__pyx_t_5)) {
-        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
-        __Pyx_INCREF(__pyx_t_5);
-        __Pyx_INCREF(function);
-        __Pyx_DECREF_SET(__pyx_t_4, function);
-      }
-    }
-    if (!__pyx_t_5) {
-      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_v_file); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_3);
-    } else {
-      __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __pyx_t_5 = NULL;
-      __Pyx_INCREF(__pyx_v_file);
-      __Pyx_GIVEREF(__pyx_v_file);
-      PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_v_file);
-      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_6, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_3);
-      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_FastqReader); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+  __Pyx_INCREF(__pyx_v_self);
+  __Pyx_GIVEREF(__pyx_v_self);
+  PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_self);
+  __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_super, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_init); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = NULL;
+  if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
+    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3);
+    if (likely(__pyx_t_2)) {
+      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
+      __Pyx_INCREF(__pyx_t_2);
+      __Pyx_INCREF(function);
+      __Pyx_DECREF_SET(__pyx_t_3, function);
     }
+  }
+  if (!__pyx_t_2) {
+    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_file); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+  } else {
+    __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __pyx_t_2 = NULL;
+    __Pyx_INCREF(__pyx_v_file);
+    __Pyx_GIVEREF(__pyx_v_file);
+    PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_file);
+    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
     __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-    __Pyx_DECREF_SET(__pyx_v_file, __pyx_t_3);
-    __pyx_t_3 = 0;
-
-    /* "cutadapt/_seqio.pyx":101
- * 		if isinstance(file, basestring):
- * 			file = xopen(file)
- * 			self._close_on_exit = True             # <<<<<<<<<<<<<<
- * 		self._file = file
- * 		self.sequence_class = sequence_class
- */
-    if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_close_on_exit, Py_True) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_seqio.pyx":99
- * 		If file is a filename, then .gz files are supported.
- * 		"""
- * 		if isinstance(file, basestring):             # <<<<<<<<<<<<<<
- * 			file = xopen(file)
- * 			self._close_on_exit = True
- */
   }
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_seqio.pyx":102
- * 			file = xopen(file)
- * 			self._close_on_exit = True
- * 		self._file = file             # <<<<<<<<<<<<<<
- * 		self.sequence_class = sequence_class
- * 		self.delivers_qualities = True
- */
-  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_file_2, __pyx_v_file) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_seqio.pyx":103
- * 			self._close_on_exit = True
- * 		self._file = file
+  /* "cutadapt/_seqio.pyx":85
+ * 		"""
+ * 		super(FastqReader, self).__init__(file)
  * 		self.sequence_class = sequence_class             # <<<<<<<<<<<<<<
  * 		self.delivers_qualities = True
  * 
  */
-  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_sequence_class, __pyx_v_sequence_class) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_sequence_class, __pyx_v_sequence_class) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "cutadapt/_seqio.pyx":104
- * 		self._file = file
+  /* "cutadapt/_seqio.pyx":86
+ * 		super(FastqReader, self).__init__(file)
  * 		self.sequence_class = sequence_class
  * 		self.delivers_qualities = True             # <<<<<<<<<<<<<<
  * 
  * 	def __iter__(self):
  */
-  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_delivers_qualities, Py_True) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_delivers_qualities, Py_True) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "cutadapt/_seqio.pyx":94
- * 	_close_on_exit = False
- * 
+  /* "cutadapt/_seqio.pyx":79
+ * 	Reader for FASTQ files. Does not support multi-line FASTQ files.
+ * 	"""
  * 	def __init__(self, file, sequence_class=Sequence):             # <<<<<<<<<<<<<<
  * 		"""
  * 		file is a filename or a file-like object.
@@ -3163,21 +3023,20 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader___init__(CYTHON_UNUSED
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
   __Pyx_XDECREF(__pyx_t_3);
   __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_XDECREF(__pyx_t_6);
   __Pyx_AddTraceback("cutadapt._seqio.FastqReader.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_file);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_CoroutineObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
-/* "cutadapt/_seqio.pyx":106
+/* "cutadapt/_seqio.pyx":88
  * 		self.delivers_qualities = True
  * 
  * 	def __iter__(self):             # <<<<<<<<<<<<<<
@@ -3218,7 +3077,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_2__iter__(CYTHON_UNUSE
   __Pyx_INCREF(__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_self);
   {
-    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_FastqReader___iter); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_FastqReader___iter); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -3267,9 +3126,9 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "cutadapt/_seqio.pyx":110
+  /* "cutadapt/_seqio.pyx":92
  * 		Yield Sequence objects
  * 		"""
  * 		cdef int i = 0             # <<<<<<<<<<<<<<
@@ -3278,89 +3137,89 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
   __pyx_cur_scope->__pyx_v_i = 0;
 
-  /* "cutadapt/_seqio.pyx":113
+  /* "cutadapt/_seqio.pyx":95
  * 		cdef int strip
  * 		cdef str line, name, qualities, sequence, name2
  * 		sequence_class = self.sequence_class             # <<<<<<<<<<<<<<
  * 
  * 		it = iter(self._file)
  */
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_sequence_class); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_sequence_class); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_GIVEREF(__pyx_t_1);
   __pyx_cur_scope->__pyx_v_sequence_class = __pyx_t_1;
   __pyx_t_1 = 0;
 
-  /* "cutadapt/_seqio.pyx":115
+  /* "cutadapt/_seqio.pyx":97
  * 		sequence_class = self.sequence_class
  * 
  * 		it = iter(self._file)             # <<<<<<<<<<<<<<
  * 		line = next(it)
  * 		if not (line and line[0] == '@'):
  */
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_file_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_file_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __Pyx_GIVEREF(__pyx_t_2);
   __pyx_cur_scope->__pyx_v_it = __pyx_t_2;
   __pyx_t_2 = 0;
 
-  /* "cutadapt/_seqio.pyx":116
+  /* "cutadapt/_seqio.pyx":98
  * 
  * 		it = iter(self._file)
  * 		line = next(it)             # <<<<<<<<<<<<<<
  * 		if not (line and line[0] == '@'):
  * 			raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))
  */
-  __pyx_t_2 = __Pyx_PyIter_Next(__pyx_cur_scope->__pyx_v_it); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyIter_Next(__pyx_cur_scope->__pyx_v_it); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
-  if (!(likely(PyString_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyString_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_2)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GIVEREF(__pyx_t_2);
   __pyx_cur_scope->__pyx_v_line = ((PyObject*)__pyx_t_2);
   __pyx_t_2 = 0;
 
-  /* "cutadapt/_seqio.pyx":117
+  /* "cutadapt/_seqio.pyx":99
  * 		it = iter(self._file)
  * 		line = next(it)
  * 		if not (line and line[0] == '@'):             # <<<<<<<<<<<<<<
  * 			raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))
  * 		strip = -2 if line.endswith('\r\n') else -1
  */
-  __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__pyx_t_4) {
   } else {
     __pyx_t_3 = __pyx_t_4;
     goto __pyx_L5_bool_binop_done;
   }
-  __pyx_t_2 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_2 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_t_2 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_2 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_4 = (__Pyx_PyString_Equals(__pyx_t_2, __pyx_kp_s__3, Py_EQ)); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = (__Pyx_PyString_Equals(__pyx_t_2, __pyx_kp_s__2, Py_EQ)); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_t_3 = __pyx_t_4;
   __pyx_L5_bool_binop_done:;
   __pyx_t_4 = ((!__pyx_t_3) != 0);
   if (__pyx_t_4) {
 
-    /* "cutadapt/_seqio.pyx":118
+    /* "cutadapt/_seqio.pyx":100
  * 		line = next(it)
  * 		if not (line and line[0] == '@'):
  * 			raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))             # <<<<<<<<<<<<<<
  * 		strip = -2 if line.endswith('\r\n') else -1
  * 		name = line[1:strip]
  */
-    __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected, __pyx_n_s_format); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected, __pyx_n_s_format); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_6);
-    __pyx_t_7 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_7 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_7);
     if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
       PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     }
-    __pyx_t_8 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_8 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_8);
     __pyx_t_9 = NULL;
     __pyx_t_10 = 0;
@@ -3374,7 +3233,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
         __pyx_t_10 = 1;
       }
     }
-    __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_11);
     if (__pyx_t_9) {
       __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_9); __pyx_t_9 = NULL;
@@ -3385,7 +3244,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
     PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, __pyx_t_8);
     __pyx_t_7 = 0;
     __pyx_t_8 = 0;
-    __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_5);
     __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
@@ -3400,26 +3259,26 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       }
     }
     if (!__pyx_t_6) {
-      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_11 = PyTuple_New(1+1); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_11 = PyTuple_New(1+1); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_11);
       __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_6); __pyx_t_6 = NULL;
       __Pyx_GIVEREF(__pyx_t_5);
       PyTuple_SET_ITEM(__pyx_t_11, 0+1, __pyx_t_5);
       __pyx_t_5 = 0;
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_11, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_11, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_2);
       __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
     }
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-    /* "cutadapt/_seqio.pyx":117
+    /* "cutadapt/_seqio.pyx":99
  * 		it = iter(self._file)
  * 		line = next(it)
  * 		if not (line and line[0] == '@'):             # <<<<<<<<<<<<<<
@@ -3428,7 +3287,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
   }
 
-  /* "cutadapt/_seqio.pyx":119
+  /* "cutadapt/_seqio.pyx":101
  * 		if not (line and line[0] == '@'):
  * 			raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))
  * 		strip = -2 if line.endswith('\r\n') else -1             # <<<<<<<<<<<<<<
@@ -3437,9 +3296,9 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
   if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
     PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", "endswith");
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
-  __pyx_t_4 = __Pyx_PyStr_Tailmatch(__pyx_cur_scope->__pyx_v_line, __pyx_kp_s__4, 0, PY_SSIZE_T_MAX, 1); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_PyStr_Tailmatch(__pyx_cur_scope->__pyx_v_line, __pyx_kp_s__3, 0, PY_SSIZE_T_MAX, 1); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if ((__pyx_t_4 != 0)) {
     __pyx_t_12 = -2;
   } else {
@@ -3447,7 +3306,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
   }
   __pyx_cur_scope->__pyx_v_strip = __pyx_t_12;
 
-  /* "cutadapt/_seqio.pyx":120
+  /* "cutadapt/_seqio.pyx":102
  * 			raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))
  * 		strip = -2 if line.endswith('\r\n') else -1
  * 		name = line[1:strip]             # <<<<<<<<<<<<<<
@@ -3456,15 +3315,15 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
   if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
     PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
-  __pyx_t_2 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_GIVEREF(__pyx_t_2);
   __pyx_cur_scope->__pyx_v_name = ((PyObject*)__pyx_t_2);
   __pyx_t_2 = 0;
 
-  /* "cutadapt/_seqio.pyx":122
+  /* "cutadapt/_seqio.pyx":104
  * 		name = line[1:strip]
  * 
  * 		i = 1             # <<<<<<<<<<<<<<
@@ -3473,7 +3332,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
   __pyx_cur_scope->__pyx_v_i = 1;
 
-  /* "cutadapt/_seqio.pyx":123
+  /* "cutadapt/_seqio.pyx":105
  * 
  * 		i = 1
  * 		for line in it:             # <<<<<<<<<<<<<<
@@ -3484,26 +3343,26 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
     __pyx_t_2 = __pyx_cur_scope->__pyx_v_it; __Pyx_INCREF(__pyx_t_2); __pyx_t_10 = 0;
     __pyx_t_13 = NULL;
   } else {
-    __pyx_t_10 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_it); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_10 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_it); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_13 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_13 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
   for (;;) {
     if (likely(!__pyx_t_13)) {
       if (likely(PyList_CheckExact(__pyx_t_2))) {
         if (__pyx_t_10 >= PyList_GET_SIZE(__pyx_t_2)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_1); __pyx_t_10++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_1); __pyx_t_10++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         #else
-        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_10); __pyx_t_10++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_10); __pyx_t_10++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_1);
         #endif
       } else {
         if (__pyx_t_10 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
         #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_1); __pyx_t_10++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_1); __pyx_t_10++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         #else
-        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_10); __pyx_t_10++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_10); __pyx_t_10++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_1);
         #endif
       }
@@ -3513,19 +3372,19 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
         PyObject* exc_type = PyErr_Occurred();
         if (exc_type) {
           if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         }
         break;
       }
       __Pyx_GOTREF(__pyx_t_1);
     }
-    if (!(likely(PyString_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(PyString_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_cur_scope->__pyx_v_line);
     __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_line, ((PyObject*)__pyx_t_1));
     __Pyx_GIVEREF(__pyx_t_1);
     __pyx_t_1 = 0;
 
-    /* "cutadapt/_seqio.pyx":124
+    /* "cutadapt/_seqio.pyx":106
  * 		i = 1
  * 		for line in it:
  * 			if i == 0:             # <<<<<<<<<<<<<<
@@ -3535,46 +3394,46 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
     switch (__pyx_cur_scope->__pyx_v_i) {
       case 0:
 
-      /* "cutadapt/_seqio.pyx":125
+      /* "cutadapt/_seqio.pyx":107
  * 		for line in it:
  * 			if i == 0:
  * 				if not (line and line[0] == '@'):             # <<<<<<<<<<<<<<
  * 					raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))
  * 				name = line[1:strip]
  */
-      __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       if (__pyx_t_3) {
       } else {
         __pyx_t_4 = __pyx_t_3;
         goto __pyx_L10_bool_binop_done;
       }
-      __pyx_t_1 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+      __pyx_t_1 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
       __Pyx_GOTREF(__pyx_t_1);
-      __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_kp_s__3, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_kp_s__2, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
       __pyx_t_4 = __pyx_t_3;
       __pyx_L10_bool_binop_done:;
       __pyx_t_3 = ((!__pyx_t_4) != 0);
       if (__pyx_t_3) {
 
-        /* "cutadapt/_seqio.pyx":126
+        /* "cutadapt/_seqio.pyx":108
  * 			if i == 0:
  * 				if not (line and line[0] == '@'):
  * 					raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))             # <<<<<<<<<<<<<<
  * 				name = line[1:strip]
  * 			elif i == 1:
  */
-        __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_11);
-        __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected, __pyx_n_s_format); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected, __pyx_n_s_format); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_6);
-        __pyx_t_8 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_8 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_8);
         if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
           PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         }
-        __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_7);
         __pyx_t_9 = NULL;
         __pyx_t_14 = 0;
@@ -3588,7 +3447,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
             __pyx_t_14 = 1;
           }
         }
-        __pyx_t_15 = PyTuple_New(2+__pyx_t_14); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_15 = PyTuple_New(2+__pyx_t_14); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_15);
         if (__pyx_t_9) {
           __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_15, 0, __pyx_t_9); __pyx_t_9 = NULL;
@@ -3599,7 +3458,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
         PyTuple_SET_ITEM(__pyx_t_15, 1+__pyx_t_14, __pyx_t_7);
         __pyx_t_8 = 0;
         __pyx_t_7 = 0;
-        __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_15, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_15, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_5);
         __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
         __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
@@ -3614,26 +3473,26 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
           }
         }
         if (!__pyx_t_6) {
-          __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
           __Pyx_GOTREF(__pyx_t_1);
         } else {
-          __pyx_t_15 = PyTuple_New(1+1); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_15 = PyTuple_New(1+1); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_GOTREF(__pyx_t_15);
           __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_15, 0, __pyx_t_6); __pyx_t_6 = NULL;
           __Pyx_GIVEREF(__pyx_t_5);
           PyTuple_SET_ITEM(__pyx_t_15, 0+1, __pyx_t_5);
           __pyx_t_5 = 0;
-          __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_15, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_15, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_GOTREF(__pyx_t_1);
           __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
         }
         __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
         __Pyx_Raise(__pyx_t_1, 0, 0, 0);
         __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-        /* "cutadapt/_seqio.pyx":125
+        /* "cutadapt/_seqio.pyx":107
  * 		for line in it:
  * 			if i == 0:
  * 				if not (line and line[0] == '@'):             # <<<<<<<<<<<<<<
@@ -3642,7 +3501,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
       }
 
-      /* "cutadapt/_seqio.pyx":127
+      /* "cutadapt/_seqio.pyx":109
  * 				if not (line and line[0] == '@'):
  * 					raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))
  * 				name = line[1:strip]             # <<<<<<<<<<<<<<
@@ -3651,16 +3510,16 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
       if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
         PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 109; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       }
-      __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 109; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_1);
       __Pyx_GOTREF(__pyx_cur_scope->__pyx_v_name);
       __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_name, ((PyObject*)__pyx_t_1));
       __Pyx_GIVEREF(__pyx_t_1);
       __pyx_t_1 = 0;
 
-      /* "cutadapt/_seqio.pyx":124
+      /* "cutadapt/_seqio.pyx":106
  * 		i = 1
  * 		for line in it:
  * 			if i == 0:             # <<<<<<<<<<<<<<
@@ -3669,7 +3528,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
       break;
 
-      /* "cutadapt/_seqio.pyx":128
+      /* "cutadapt/_seqio.pyx":110
  * 					raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))
  * 				name = line[1:strip]
  * 			elif i == 1:             # <<<<<<<<<<<<<<
@@ -3678,7 +3537,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
       case 1:
 
-      /* "cutadapt/_seqio.pyx":129
+      /* "cutadapt/_seqio.pyx":111
  * 				name = line[1:strip]
  * 			elif i == 1:
  * 				sequence = line[:strip]             # <<<<<<<<<<<<<<
@@ -3687,16 +3546,16 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
       if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
         PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       }
-      __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_1);
       __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_sequence);
       __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_sequence, ((PyObject*)__pyx_t_1));
       __Pyx_GIVEREF(__pyx_t_1);
       __pyx_t_1 = 0;
 
-      /* "cutadapt/_seqio.pyx":128
+      /* "cutadapt/_seqio.pyx":110
  * 					raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))
  * 				name = line[1:strip]
  * 			elif i == 1:             # <<<<<<<<<<<<<<
@@ -3705,7 +3564,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
       break;
 
-      /* "cutadapt/_seqio.pyx":130
+      /* "cutadapt/_seqio.pyx":112
  * 			elif i == 1:
  * 				sequence = line[:strip]
  * 			elif i == 2:             # <<<<<<<<<<<<<<
@@ -3714,30 +3573,30 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
       case 2:
 
-      /* "cutadapt/_seqio.pyx":131
+      /* "cutadapt/_seqio.pyx":113
  * 				sequence = line[:strip]
  * 			elif i == 2:
  * 				if line == '+\n':  # check most common case first             # <<<<<<<<<<<<<<
  * 					name2 = ''
  * 				else:
  */
-      __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_cur_scope->__pyx_v_line, __pyx_kp_s__5, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_cur_scope->__pyx_v_line, __pyx_kp_s__4, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __pyx_t_4 = (__pyx_t_3 != 0);
       if (__pyx_t_4) {
 
-        /* "cutadapt/_seqio.pyx":132
+        /* "cutadapt/_seqio.pyx":114
  * 			elif i == 2:
  * 				if line == '+\n':  # check most common case first
  * 					name2 = ''             # <<<<<<<<<<<<<<
  * 				else:
  * 					line = line[:strip]
  */
-        __Pyx_INCREF(__pyx_kp_s__2);
+        __Pyx_INCREF(__pyx_kp_s_);
         __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_name2);
-        __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_name2, __pyx_kp_s__2);
-        __Pyx_GIVEREF(__pyx_kp_s__2);
+        __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_name2, __pyx_kp_s_);
+        __Pyx_GIVEREF(__pyx_kp_s_);
 
-        /* "cutadapt/_seqio.pyx":131
+        /* "cutadapt/_seqio.pyx":113
  * 				sequence = line[:strip]
  * 			elif i == 2:
  * 				if line == '+\n':  # check most common case first             # <<<<<<<<<<<<<<
@@ -3747,7 +3606,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
         goto __pyx_L12;
       }
 
-      /* "cutadapt/_seqio.pyx":134
+      /* "cutadapt/_seqio.pyx":116
  * 					name2 = ''
  * 				else:
  * 					line = line[:strip]             # <<<<<<<<<<<<<<
@@ -3757,51 +3616,51 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       /*else*/ {
         if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
           PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         }
-        __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_1);
         __Pyx_GOTREF(__pyx_cur_scope->__pyx_v_line);
         __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_line, ((PyObject*)__pyx_t_1));
         __Pyx_GIVEREF(__pyx_t_1);
         __pyx_t_1 = 0;
 
-        /* "cutadapt/_seqio.pyx":135
+        /* "cutadapt/_seqio.pyx":117
  * 				else:
  * 					line = line[:strip]
  * 					if not (line and line[0] == '+'):             # <<<<<<<<<<<<<<
  * 						raise FormatError("Line {0} in FASTQ file is expected to start with '+', but found {1!r}".format(i+1, line[:10]))
  * 					if len(line) > 1:
  */
-        __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         if (__pyx_t_3) {
         } else {
           __pyx_t_4 = __pyx_t_3;
           goto __pyx_L14_bool_binop_done;
         }
-        __pyx_t_1 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+        __pyx_t_1 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
         __Pyx_GOTREF(__pyx_t_1);
-        __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_kp_s__6, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_kp_s__5, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
         __pyx_t_4 = __pyx_t_3;
         __pyx_L14_bool_binop_done:;
         __pyx_t_3 = ((!__pyx_t_4) != 0);
         if (__pyx_t_3) {
 
-          /* "cutadapt/_seqio.pyx":136
+          /* "cutadapt/_seqio.pyx":118
  * 					line = line[:strip]
  * 					if not (line and line[0] == '+'):
  * 						raise FormatError("Line {0} in FASTQ file is expected to start with '+', but found {1!r}".format(i+1, line[:10]))             # <<<<<<<<<<<<<<
  * 					if len(line) > 1:
  * 						if not line[1:] == name:
  */
-          __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_GOTREF(__pyx_t_11);
-          __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected_2, __pyx_n_s_format); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected_2, __pyx_n_s_format); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_GOTREF(__pyx_t_5);
-          __pyx_t_6 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_6 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_GOTREF(__pyx_t_6);
-          __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_GOTREF(__pyx_t_7);
           __pyx_t_8 = NULL;
           __pyx_t_14 = 0;
@@ -3815,7 +3674,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
               __pyx_t_14 = 1;
             }
           }
-          __pyx_t_9 = PyTuple_New(2+__pyx_t_14); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_9 = PyTuple_New(2+__pyx_t_14); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_GOTREF(__pyx_t_9);
           if (__pyx_t_8) {
             __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
@@ -3826,7 +3685,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
           PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_14, __pyx_t_7);
           __pyx_t_6 = 0;
           __pyx_t_7 = 0;
-          __pyx_t_15 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_15 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_GOTREF(__pyx_t_15);
           __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
           __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
@@ -3841,26 +3700,26 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
             }
           }
           if (!__pyx_t_5) {
-            __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_15); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_15); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
             __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
             __Pyx_GOTREF(__pyx_t_1);
           } else {
-            __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
             __Pyx_GOTREF(__pyx_t_9);
             __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_5); __pyx_t_5 = NULL;
             __Pyx_GIVEREF(__pyx_t_15);
             PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_15);
             __pyx_t_15 = 0;
-            __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
             __Pyx_GOTREF(__pyx_t_1);
             __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
           }
           __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
           __Pyx_Raise(__pyx_t_1, 0, 0, 0);
           __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-          /* "cutadapt/_seqio.pyx":135
+          /* "cutadapt/_seqio.pyx":117
  * 				else:
  * 					line = line[:strip]
  * 					if not (line and line[0] == '+'):             # <<<<<<<<<<<<<<
@@ -3869,61 +3728,61 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
         }
 
-        /* "cutadapt/_seqio.pyx":137
+        /* "cutadapt/_seqio.pyx":119
  * 					if not (line and line[0] == '+'):
  * 						raise FormatError("Line {0} in FASTQ file is expected to start with '+', but found {1!r}".format(i+1, line[:10]))
  * 					if len(line) > 1:             # <<<<<<<<<<<<<<
  * 						if not line[1:] == name:
  * 							raise FormatError(
  */
-        __pyx_t_14 = PyObject_Length(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_14 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_14 = PyObject_Length(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_14 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __pyx_t_3 = ((__pyx_t_14 > 1) != 0);
         if (__pyx_t_3) {
 
-          /* "cutadapt/_seqio.pyx":138
+          /* "cutadapt/_seqio.pyx":120
  * 						raise FormatError("Line {0} in FASTQ file is expected to start with '+', but found {1!r}".format(i+1, line[:10]))
  * 					if len(line) > 1:
  * 						if not line[1:] == name:             # <<<<<<<<<<<<<<
  * 							raise FormatError(
  * 								"At line {0}: Sequence descriptions in the FASTQ file don't match "
  */
-          __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_GOTREF(__pyx_t_1);
-          __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_cur_scope->__pyx_v_name, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_cur_scope->__pyx_v_name, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
           __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
           __pyx_t_4 = ((!(__pyx_t_3 != 0)) != 0);
           if (__pyx_t_4) {
 
-            /* "cutadapt/_seqio.pyx":139
+            /* "cutadapt/_seqio.pyx":121
  * 					if len(line) > 1:
  * 						if not line[1:] == name:
  * 							raise FormatError(             # <<<<<<<<<<<<<<
  * 								"At line {0}: Sequence descriptions in the FASTQ file don't match "
  * 								"({1!r} != {2!r}).\n"
  */
-            __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
             __Pyx_GOTREF(__pyx_t_11);
 
-            /* "cutadapt/_seqio.pyx":143
+            /* "cutadapt/_seqio.pyx":125
  * 								"({1!r} != {2!r}).\n"
  * 								"The second sequence description must be either empty "
  * 								"or equal to the first description.".format(i+1,             # <<<<<<<<<<<<<<
  * 									name, line[1:]))
  * 						name2 = name
  */
-            __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_At_line_0_Sequence_descriptions, __pyx_n_s_format); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_At_line_0_Sequence_descriptions, __pyx_n_s_format); if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
             __Pyx_GOTREF(__pyx_t_15);
-            __pyx_t_5 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            __pyx_t_5 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
             __Pyx_GOTREF(__pyx_t_5);
 
-            /* "cutadapt/_seqio.pyx":144
+            /* "cutadapt/_seqio.pyx":126
  * 								"The second sequence description must be either empty "
  * 								"or equal to the first description.".format(i+1,
  * 									name, line[1:]))             # <<<<<<<<<<<<<<
  * 						name2 = name
  * 					else:
  */
-            __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
             __Pyx_GOTREF(__pyx_t_7);
             __pyx_t_6 = NULL;
             __pyx_t_14 = 0;
@@ -3937,7 +3796,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
                 __pyx_t_14 = 1;
               }
             }
-            __pyx_t_8 = PyTuple_New(3+__pyx_t_14); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            __pyx_t_8 = PyTuple_New(3+__pyx_t_14); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
             __Pyx_GOTREF(__pyx_t_8);
             if (__pyx_t_6) {
               __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL;
@@ -3951,7 +3810,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
             PyTuple_SET_ITEM(__pyx_t_8, 2+__pyx_t_14, __pyx_t_7);
             __pyx_t_5 = 0;
             __pyx_t_7 = 0;
-            __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_15, __pyx_t_8, NULL); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_15, __pyx_t_8, NULL); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
             __Pyx_GOTREF(__pyx_t_9);
             __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
             __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
@@ -3966,26 +3825,26 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
               }
             }
             if (!__pyx_t_15) {
-              __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_9); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+              __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_9); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
               __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
               __Pyx_GOTREF(__pyx_t_1);
             } else {
-              __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+              __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
               __Pyx_GOTREF(__pyx_t_8);
               __Pyx_GIVEREF(__pyx_t_15); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_15); __pyx_t_15 = NULL;
               __Pyx_GIVEREF(__pyx_t_9);
               PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_9);
               __pyx_t_9 = 0;
-              __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+              __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
               __Pyx_GOTREF(__pyx_t_1);
               __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
             }
             __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
             __Pyx_Raise(__pyx_t_1, 0, 0, 0);
             __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-            /* "cutadapt/_seqio.pyx":138
+            /* "cutadapt/_seqio.pyx":120
  * 						raise FormatError("Line {0} in FASTQ file is expected to start with '+', but found {1!r}".format(i+1, line[:10]))
  * 					if len(line) > 1:
  * 						if not line[1:] == name:             # <<<<<<<<<<<<<<
@@ -3994,7 +3853,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
           }
 
-          /* "cutadapt/_seqio.pyx":145
+          /* "cutadapt/_seqio.pyx":127
  * 								"or equal to the first description.".format(i+1,
  * 									name, line[1:]))
  * 						name2 = name             # <<<<<<<<<<<<<<
@@ -4006,7 +3865,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
           __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_name2, __pyx_cur_scope->__pyx_v_name);
           __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_name);
 
-          /* "cutadapt/_seqio.pyx":137
+          /* "cutadapt/_seqio.pyx":119
  * 					if not (line and line[0] == '+'):
  * 						raise FormatError("Line {0} in FASTQ file is expected to start with '+', but found {1!r}".format(i+1, line[:10]))
  * 					if len(line) > 1:             # <<<<<<<<<<<<<<
@@ -4016,7 +3875,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
           goto __pyx_L16;
         }
 
-        /* "cutadapt/_seqio.pyx":147
+        /* "cutadapt/_seqio.pyx":129
  * 						name2 = name
  * 					else:
  * 						name2 = ''             # <<<<<<<<<<<<<<
@@ -4024,16 +3883,16 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  * 				if len(line) == len(sequence) - strip:
  */
         /*else*/ {
-          __Pyx_INCREF(__pyx_kp_s__2);
+          __Pyx_INCREF(__pyx_kp_s_);
           __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_name2);
-          __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_name2, __pyx_kp_s__2);
-          __Pyx_GIVEREF(__pyx_kp_s__2);
+          __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_name2, __pyx_kp_s_);
+          __Pyx_GIVEREF(__pyx_kp_s_);
         }
         __pyx_L16:;
       }
       __pyx_L12:;
 
-      /* "cutadapt/_seqio.pyx":130
+      /* "cutadapt/_seqio.pyx":112
  * 			elif i == 1:
  * 				sequence = line[:strip]
  * 			elif i == 2:             # <<<<<<<<<<<<<<
@@ -4042,7 +3901,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
       break;
 
-      /* "cutadapt/_seqio.pyx":148
+      /* "cutadapt/_seqio.pyx":130
  * 					else:
  * 						name2 = ''
  * 			elif i == 3:             # <<<<<<<<<<<<<<
@@ -4051,20 +3910,20 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
       case 3:
 
-      /* "cutadapt/_seqio.pyx":149
+      /* "cutadapt/_seqio.pyx":131
  * 						name2 = ''
  * 			elif i == 3:
  * 				if len(line) == len(sequence) - strip:             # <<<<<<<<<<<<<<
  * 					qualities = line[:strip]
  * 				else:
  */
-      __pyx_t_14 = PyObject_Length(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_14 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 149; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      if (unlikely(!__pyx_cur_scope->__pyx_v_sequence)) { __Pyx_RaiseUnboundLocalError("sequence"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 149; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
-      __pyx_t_16 = PyObject_Length(__pyx_cur_scope->__pyx_v_sequence); if (unlikely(__pyx_t_16 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 149; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_14 = PyObject_Length(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_14 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      if (unlikely(!__pyx_cur_scope->__pyx_v_sequence)) { __Pyx_RaiseUnboundLocalError("sequence"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
+      __pyx_t_16 = PyObject_Length(__pyx_cur_scope->__pyx_v_sequence); if (unlikely(__pyx_t_16 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __pyx_t_4 = ((__pyx_t_14 == (__pyx_t_16 - __pyx_cur_scope->__pyx_v_strip)) != 0);
       if (__pyx_t_4) {
 
-        /* "cutadapt/_seqio.pyx":150
+        /* "cutadapt/_seqio.pyx":132
  * 			elif i == 3:
  * 				if len(line) == len(sequence) - strip:
  * 					qualities = line[:strip]             # <<<<<<<<<<<<<<
@@ -4073,16 +3932,16 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
         if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
           PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         }
-        __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_1);
         __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_qualities);
         __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_qualities, ((PyObject*)__pyx_t_1));
         __Pyx_GIVEREF(__pyx_t_1);
         __pyx_t_1 = 0;
 
-        /* "cutadapt/_seqio.pyx":149
+        /* "cutadapt/_seqio.pyx":131
  * 						name2 = ''
  * 			elif i == 3:
  * 				if len(line) == len(sequence) - strip:             # <<<<<<<<<<<<<<
@@ -4092,7 +3951,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
         goto __pyx_L18;
       }
 
-      /* "cutadapt/_seqio.pyx":152
+      /* "cutadapt/_seqio.pyx":134
  * 					qualities = line[:strip]
  * 				else:
  * 					qualities = line.rstrip('\r\n')             # <<<<<<<<<<<<<<
@@ -4100,12 +3959,12 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  * 			i = (i + 1) % 4
  */
       /*else*/ {
-        __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_line, __pyx_n_s_rstrip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_line, __pyx_n_s_rstrip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_1);
-        __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_11);
         __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-        if (!(likely(PyString_CheckExact(__pyx_t_11))||((__pyx_t_11) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_11)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        if (!(likely(PyString_CheckExact(__pyx_t_11))||((__pyx_t_11) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_11)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_qualities);
         __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_qualities, ((PyObject*)__pyx_t_11));
         __Pyx_GIVEREF(__pyx_t_11);
@@ -4113,15 +3972,15 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       }
       __pyx_L18:;
 
-      /* "cutadapt/_seqio.pyx":153
+      /* "cutadapt/_seqio.pyx":135
  * 				else:
  * 					qualities = line.rstrip('\r\n')
  * 				yield sequence_class(name, sequence, qualities, name2=name2)             # <<<<<<<<<<<<<<
  * 			i = (i + 1) % 4
  * 		if i != 0:
  */
-      if (unlikely(!__pyx_cur_scope->__pyx_v_sequence)) { __Pyx_RaiseUnboundLocalError("sequence"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
-      __pyx_t_11 = PyTuple_New(3); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      if (unlikely(!__pyx_cur_scope->__pyx_v_sequence)) { __Pyx_RaiseUnboundLocalError("sequence"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
+      __pyx_t_11 = PyTuple_New(3); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_11);
       __Pyx_INCREF(__pyx_cur_scope->__pyx_v_name);
       __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_name);
@@ -4132,11 +3991,11 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       __Pyx_INCREF(__pyx_cur_scope->__pyx_v_qualities);
       __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_qualities);
       PyTuple_SET_ITEM(__pyx_t_11, 2, __pyx_cur_scope->__pyx_v_qualities);
-      __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_1);
-      if (unlikely(!__pyx_cur_scope->__pyx_v_name2)) { __Pyx_RaiseUnboundLocalError("name2"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
-      if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_name2, __pyx_cur_scope->__pyx_v_name2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_cur_scope->__pyx_v_sequence_class, __pyx_t_11, __pyx_t_1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      if (unlikely(!__pyx_cur_scope->__pyx_v_name2)) { __Pyx_RaiseUnboundLocalError("name2"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
+      if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_name2, __pyx_cur_scope->__pyx_v_name2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_cur_scope->__pyx_v_sequence_class, __pyx_t_11, __pyx_t_1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_8);
       __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
       __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -4157,9 +4016,9 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       __Pyx_XGOTREF(__pyx_t_2);
       __pyx_t_10 = __pyx_cur_scope->__pyx_t_1;
       __pyx_t_13 = __pyx_cur_scope->__pyx_t_2;
-      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-      /* "cutadapt/_seqio.pyx":148
+      /* "cutadapt/_seqio.pyx":130
  * 					else:
  * 						name2 = ''
  * 			elif i == 3:             # <<<<<<<<<<<<<<
@@ -4170,7 +4029,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       default: break;
     }
 
-    /* "cutadapt/_seqio.pyx":154
+    /* "cutadapt/_seqio.pyx":136
  * 					qualities = line.rstrip('\r\n')
  * 				yield sequence_class(name, sequence, qualities, name2=name2)
  * 			i = (i + 1) % 4             # <<<<<<<<<<<<<<
@@ -4179,7 +4038,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
  */
     __pyx_cur_scope->__pyx_v_i = __Pyx_mod_long((__pyx_cur_scope->__pyx_v_i + 1), 4);
 
-    /* "cutadapt/_seqio.pyx":123
+    /* "cutadapt/_seqio.pyx":105
  * 
  * 		i = 1
  * 		for line in it:             # <<<<<<<<<<<<<<
@@ -4189,42 +4048,38 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
   }
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_seqio.pyx":155
+  /* "cutadapt/_seqio.pyx":137
  * 				yield sequence_class(name, sequence, qualities, name2=name2)
  * 			i = (i + 1) % 4
  * 		if i != 0:             # <<<<<<<<<<<<<<
  * 			raise FormatError("FASTQ file ended prematurely")
- * 
  */
   __pyx_t_4 = ((__pyx_cur_scope->__pyx_v_i != 0) != 0);
   if (__pyx_t_4) {
 
-    /* "cutadapt/_seqio.pyx":156
+    /* "cutadapt/_seqio.pyx":138
  * 			i = (i + 1) % 4
  * 		if i != 0:
  * 			raise FormatError("FASTQ file ended prematurely")             # <<<<<<<<<<<<<<
- * 
- * 	def close(self):
  */
-    __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_8);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     __Pyx_Raise(__pyx_t_8, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-    /* "cutadapt/_seqio.pyx":155
+    /* "cutadapt/_seqio.pyx":137
  * 				yield sequence_class(name, sequence, qualities, name2=name2)
  * 			i = (i + 1) % 4
  * 		if i != 0:             # <<<<<<<<<<<<<<
  * 			raise FormatError("FASTQ file ended prematurely")
- * 
  */
   }
 
-  /* "cutadapt/_seqio.pyx":106
+  /* "cutadapt/_seqio.pyx":88
  * 		self.delivers_qualities = True
  * 
  * 	def __iter__(self):             # <<<<<<<<<<<<<<
@@ -4254,374 +4109,6 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
   return __pyx_r;
 }
 
-/* "cutadapt/_seqio.pyx":158
- * 			raise FormatError("FASTQ file ended prematurely")
- * 
- * 	def close(self):             # <<<<<<<<<<<<<<
- * 		if self._close_on_exit and self._file is not None:
- * 			self._file.close()
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_6close(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/
-static PyMethodDef __pyx_mdef_8cutadapt_6_seqio_11FastqReader_6close = {"close", (PyCFunction)__pyx_pw_8cutadapt_6_seqio_11FastqReader_6close, METH_O, 0};
-static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_6close(PyObject *__pyx_self, PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("close (wrapper)", 0);
-  __pyx_r = __pyx_pf_8cutadapt_6_seqio_11FastqReader_5close(__pyx_self, ((PyObject *)__pyx_v_self));
-
-  /* function exit code */
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_5close(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  int __pyx_t_1;
-  PyObject *__pyx_t_2 = NULL;
-  int __pyx_t_3;
-  int __pyx_t_4;
-  PyObject *__pyx_t_5 = NULL;
-  PyObject *__pyx_t_6 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("close", 0);
-
-  /* "cutadapt/_seqio.pyx":159
- * 
- * 	def close(self):
- * 		if self._close_on_exit and self._file is not None:             # <<<<<<<<<<<<<<
- * 			self._file.close()
- * 			self._file = None
- */
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_close_on_exit); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  if (__pyx_t_3) {
-  } else {
-    __pyx_t_1 = __pyx_t_3;
-    goto __pyx_L4_bool_binop_done;
-  }
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = (__pyx_t_2 != Py_None);
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_4 = (__pyx_t_3 != 0);
-  __pyx_t_1 = __pyx_t_4;
-  __pyx_L4_bool_binop_done:;
-  if (__pyx_t_1) {
-
-    /* "cutadapt/_seqio.pyx":160
- * 	def close(self):
- * 		if self._close_on_exit and self._file is not None:
- * 			self._file.close()             # <<<<<<<<<<<<<<
- * 			self._file = None
- * 
- */
-    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_5);
-    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_close); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_6);
-    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    __pyx_t_5 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_6))) {
-      __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6);
-      if (likely(__pyx_t_5)) {
-        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
-        __Pyx_INCREF(__pyx_t_5);
-        __Pyx_INCREF(function);
-        __Pyx_DECREF_SET(__pyx_t_6, function);
-      }
-    }
-    if (__pyx_t_5) {
-      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_5); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    } else {
-      __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_6); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    }
-    __Pyx_GOTREF(__pyx_t_2);
-    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-
-    /* "cutadapt/_seqio.pyx":161
- * 		if self._close_on_exit and self._file is not None:
- * 			self._file.close()
- * 			self._file = None             # <<<<<<<<<<<<<<
- * 
- * 	def __enter__(self):
- */
-    if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_file_2, Py_None) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_seqio.pyx":159
- * 
- * 	def close(self):
- * 		if self._close_on_exit and self._file is not None:             # <<<<<<<<<<<<<<
- * 			self._file.close()
- * 			self._file = None
- */
-  }
-
-  /* "cutadapt/_seqio.pyx":158
- * 			raise FormatError("FASTQ file ended prematurely")
- * 
- * 	def close(self):             # <<<<<<<<<<<<<<
- * 		if self._close_on_exit and self._file is not None:
- * 			self._file.close()
- */
-
-  /* function exit code */
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_XDECREF(__pyx_t_6);
-  __Pyx_AddTraceback("cutadapt._seqio.FastqReader.close", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* "cutadapt/_seqio.pyx":163
- * 			self._file = None
- * 
- * 	def __enter__(self):             # <<<<<<<<<<<<<<
- * 		if self._file is None:
- * 			raise ValueError("I/O operation on closed FastqReader")
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_8__enter__(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/
-static PyMethodDef __pyx_mdef_8cutadapt_6_seqio_11FastqReader_8__enter__ = {"__enter__", (PyCFunction)__pyx_pw_8cutadapt_6_seqio_11FastqReader_8__enter__, METH_O, 0};
-static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_8__enter__(PyObject *__pyx_self, PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__enter__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_8cutadapt_6_seqio_11FastqReader_7__enter__(__pyx_self, ((PyObject *)__pyx_v_self));
-
-  /* function exit code */
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_7__enter__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
-  int __pyx_t_3;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__enter__", 0);
-
-  /* "cutadapt/_seqio.pyx":164
- * 
- * 	def __enter__(self):
- * 		if self._file is None:             # <<<<<<<<<<<<<<
- * 			raise ValueError("I/O operation on closed FastqReader")
- * 		return self
- */
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = (__pyx_t_1 == Py_None);
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __pyx_t_3 = (__pyx_t_2 != 0);
-  if (__pyx_t_3) {
-
-    /* "cutadapt/_seqio.pyx":165
- * 	def __enter__(self):
- * 		if self._file is None:
- * 			raise ValueError("I/O operation on closed FastqReader")             # <<<<<<<<<<<<<<
- * 		return self
- * 
- */
-    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_Raise(__pyx_t_1, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-    /* "cutadapt/_seqio.pyx":164
- * 
- * 	def __enter__(self):
- * 		if self._file is None:             # <<<<<<<<<<<<<<
- * 			raise ValueError("I/O operation on closed FastqReader")
- * 		return self
- */
-  }
-
-  /* "cutadapt/_seqio.pyx":166
- * 		if self._file is None:
- * 			raise ValueError("I/O operation on closed FastqReader")
- * 		return self             # <<<<<<<<<<<<<<
- * 
- * 	def __exit__(self, *args):
- */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(__pyx_v_self);
-  __pyx_r = __pyx_v_self;
-  goto __pyx_L0;
-
-  /* "cutadapt/_seqio.pyx":163
- * 			self._file = None
- * 
- * 	def __enter__(self):             # <<<<<<<<<<<<<<
- * 		if self._file is None:
- * 			raise ValueError("I/O operation on closed FastqReader")
- */
-
-  /* function exit code */
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("cutadapt._seqio.FastqReader.__enter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* "cutadapt/_seqio.pyx":168
- * 		return self
- * 
- * 	def __exit__(self, *args):             # <<<<<<<<<<<<<<
- * 		self.close()
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_10__exit__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyMethodDef __pyx_mdef_8cutadapt_6_seqio_11FastqReader_10__exit__ = {"__exit__", (PyCFunction)__pyx_pw_8cutadapt_6_seqio_11FastqReader_10__exit__, METH_VARARGS|METH_KEYWORDS, 0};
-static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_10__exit__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  PyObject *__pyx_v_self = 0;
-  CYTHON_UNUSED PyObject *__pyx_v_args = 0;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__exit__ (wrapper)", 0);
-  if (PyTuple_GET_SIZE(__pyx_args) > 1) {
-    __pyx_v_args = PyTuple_GetSlice(__pyx_args, 1, PyTuple_GET_SIZE(__pyx_args));
-    if (unlikely(!__pyx_v_args)) {
-      __Pyx_RefNannyFinishContext();
-      return NULL;
-    }
-    __Pyx_GOTREF(__pyx_v_args);
-  } else {
-    __pyx_v_args = __pyx_empty_tuple; __Pyx_INCREF(__pyx_empty_tuple);
-  }
-  {
-    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_self,0};
-    PyObject* values[1] = {0};
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        default:
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_self)) != 0)) kw_args--;
-        else goto __pyx_L5_argtuple_error;
-      }
-      if (unlikely(kw_args > 0)) {
-        const Py_ssize_t used_pos_args = (pos_args < 1) ? pos_args : 1;
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, used_pos_args, "__exit__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else if (PyTuple_GET_SIZE(__pyx_args) < 1) {
-      goto __pyx_L5_argtuple_error;
-    } else {
-      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-    }
-    __pyx_v_self = values[0];
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__exit__", 0, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_DECREF(__pyx_v_args); __pyx_v_args = 0;
-  __Pyx_AddTraceback("cutadapt._seqio.FastqReader.__exit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_8cutadapt_6_seqio_11FastqReader_9__exit__(__pyx_self, __pyx_v_self, __pyx_v_args);
-
-  /* function exit code */
-  __Pyx_XDECREF(__pyx_v_args);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_9__exit__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_args) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__exit__", 0);
-
-  /* "cutadapt/_seqio.pyx":169
- * 
- * 	def __exit__(self, *args):
- * 		self.close()             # <<<<<<<<<<<<<<
- */
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_close); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = NULL;
-  if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
-    __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
-    if (likely(__pyx_t_3)) {
-      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
-      __Pyx_INCREF(__pyx_t_3);
-      __Pyx_INCREF(function);
-      __Pyx_DECREF_SET(__pyx_t_2, function);
-    }
-  }
-  if (__pyx_t_3) {
-    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  } else {
-    __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
-  /* "cutadapt/_seqio.pyx":168
- * 		return self
- * 
- * 	def __exit__(self, *args):             # <<<<<<<<<<<<<<
- * 		self.close()
- */
-
-  /* function exit code */
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("cutadapt._seqio.FastqReader.__exit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
 static PyObject *__pyx_tp_new_8cutadapt_6_seqio_Sequence(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) {
   struct __pyx_obj_8cutadapt_6_seqio_Sequence *p;
   PyObject *o;
@@ -4637,6 +4124,7 @@ static PyObject *__pyx_tp_new_8cutadapt_6_seqio_Sequence(PyTypeObject *t, CYTHON
   p->qualities = ((PyObject*)Py_None); Py_INCREF(Py_None);
   p->name2 = ((PyObject*)Py_None); Py_INCREF(Py_None);
   p->match = Py_None; Py_INCREF(Py_None);
+  p->match_info = Py_None; Py_INCREF(Py_None);
   return o;
 }
 
@@ -4653,6 +4141,7 @@ static void __pyx_tp_dealloc_8cutadapt_6_seqio_Sequence(PyObject *o) {
   Py_CLEAR(p->qualities);
   Py_CLEAR(p->name2);
   Py_CLEAR(p->match);
+  Py_CLEAR(p->match_info);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
@@ -4662,6 +4151,9 @@ static int __pyx_tp_traverse_8cutadapt_6_seqio_Sequence(PyObject *o, visitproc v
   if (p->match) {
     e = (*v)(p->match, a); if (e) return e;
   }
+  if (p->match_info) {
+    e = (*v)(p->match_info, a); if (e) return e;
+  }
   return 0;
 }
 
@@ -4671,6 +4163,9 @@ static int __pyx_tp_clear_8cutadapt_6_seqio_Sequence(PyObject *o) {
   tmp = ((PyObject*)p->match);
   p->match = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->match_info);
+  p->match_info = Py_None; Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
   return 0;
 }
 static PyObject *__pyx_sq_item_8cutadapt_6_seqio_Sequence(PyObject *o, Py_ssize_t i) {
@@ -4746,6 +4241,19 @@ static int __pyx_setprop_8cutadapt_6_seqio_8Sequence_match(PyObject *o, PyObject
   }
 }
 
+static PyObject *__pyx_getprop_8cutadapt_6_seqio_8Sequence_match_info(PyObject *o, CYTHON_UNUSED void *x) {
+  return __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_1__get__(o);
+}
+
+static int __pyx_setprop_8cutadapt_6_seqio_8Sequence_match_info(PyObject *o, PyObject *v, CYTHON_UNUSED void *x) {
+  if (v) {
+    return __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_3__set__(o, v);
+  }
+  else {
+    return __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_5__del__(o);
+  }
+}
+
 static PyMethodDef __pyx_methods_8cutadapt_6_seqio_Sequence[] = {
   {"__reduce__", (PyCFunction)__pyx_pw_8cutadapt_6_seqio_8Sequence_11__reduce__, METH_NOARGS, 0},
   {0, 0, 0, 0}
@@ -4757,6 +4265,7 @@ static struct PyGetSetDef __pyx_getsets_8cutadapt_6_seqio_Sequence[] = {
   {(char *)"qualities", __pyx_getprop_8cutadapt_6_seqio_8Sequence_qualities, __pyx_setprop_8cutadapt_6_seqio_8Sequence_qualities, 0, 0},
   {(char *)"name2", __pyx_getprop_8cutadapt_6_seqio_8Sequence_name2, __pyx_setprop_8cutadapt_6_seqio_8Sequence_name2, 0, 0},
   {(char *)"match", __pyx_getprop_8cutadapt_6_seqio_8Sequence_match, __pyx_setprop_8cutadapt_6_seqio_8Sequence_match, 0, 0},
+  {(char *)"match_info", __pyx_getprop_8cutadapt_6_seqio_8Sequence_match_info, __pyx_setprop_8cutadapt_6_seqio_8Sequence_match_info, 0, 0},
   {0, 0, 0, 0, 0}
 };
 
@@ -4992,38 +4501,28 @@ static struct PyModuleDef __pyx_moduledef = {
 static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_kp_s_, __pyx_k_, sizeof(__pyx_k_), 0, 0, 1, 0},
   {&__pyx_kp_s_At_line_0_Sequence_descriptions, __pyx_k_At_line_0_Sequence_descriptions, sizeof(__pyx_k_At_line_0_Sequence_descriptions), 0, 0, 1, 0},
-  {&__pyx_n_s_Exception, __pyx_k_Exception, sizeof(__pyx_k_Exception), 0, 0, 1, 1},
   {&__pyx_kp_s_FASTQ_file_ended_prematurely, __pyx_k_FASTQ_file_ended_prematurely, sizeof(__pyx_k_FASTQ_file_ended_prematurely), 0, 0, 1, 0},
   {&__pyx_n_s_FastqReader, __pyx_k_FastqReader, sizeof(__pyx_k_FastqReader), 0, 0, 1, 1},
-  {&__pyx_n_s_FastqReader___enter, __pyx_k_FastqReader___enter, sizeof(__pyx_k_FastqReader___enter), 0, 0, 1, 1},
-  {&__pyx_n_s_FastqReader___exit, __pyx_k_FastqReader___exit, sizeof(__pyx_k_FastqReader___exit), 0, 0, 1, 1},
   {&__pyx_n_s_FastqReader___init, __pyx_k_FastqReader___init, sizeof(__pyx_k_FastqReader___init), 0, 0, 1, 1},
   {&__pyx_n_s_FastqReader___iter, __pyx_k_FastqReader___iter, sizeof(__pyx_k_FastqReader___iter), 0, 0, 1, 1},
-  {&__pyx_n_s_FastqReader_close, __pyx_k_FastqReader_close, sizeof(__pyx_k_FastqReader_close), 0, 0, 1, 1},
   {&__pyx_n_s_FormatError, __pyx_k_FormatError, sizeof(__pyx_k_FormatError), 0, 0, 1, 1},
-  {&__pyx_kp_s_I_O_operation_on_closed_FastqRea, __pyx_k_I_O_operation_on_closed_FastqRea, sizeof(__pyx_k_I_O_operation_on_closed_FastqRea), 0, 0, 1, 0},
   {&__pyx_kp_s_In_read_named_0_r_length_of_qual, __pyx_k_In_read_named_0_r_length_of_qual, sizeof(__pyx_k_In_read_named_0_r_length_of_qual), 0, 0, 1, 0},
   {&__pyx_kp_s_Line_0_in_FASTQ_file_is_expected, __pyx_k_Line_0_in_FASTQ_file_is_expected, sizeof(__pyx_k_Line_0_in_FASTQ_file_is_expected), 0, 0, 1, 0},
   {&__pyx_kp_s_Line_0_in_FASTQ_file_is_expected_2, __pyx_k_Line_0_in_FASTQ_file_is_expected_2, sizeof(__pyx_k_Line_0_in_FASTQ_file_is_expected_2), 0, 0, 1, 0},
   {&__pyx_n_s_NotImplementedError, __pyx_k_NotImplementedError, sizeof(__pyx_k_NotImplementedError), 0, 0, 1, 1},
-  {&__pyx_kp_s_Raised_when_an_input_file_FASTA, __pyx_k_Raised_when_an_input_file_FASTA, sizeof(__pyx_k_Raised_when_an_input_file_FASTA), 0, 0, 1, 0},
   {&__pyx_kp_s_Reader_for_FASTQ_files_Does_not, __pyx_k_Reader_for_FASTQ_files_Does_not, sizeof(__pyx_k_Reader_for_FASTQ_files_Does_not), 0, 0, 1, 0},
+  {&__pyx_n_s_SequenceReader, __pyx_k_SequenceReader, sizeof(__pyx_k_SequenceReader), 0, 0, 1, 1},
   {&__pyx_kp_s_Sequence_name_0_r_sequence_1_r, __pyx_k_Sequence_name_0_r_sequence_1_r, sizeof(__pyx_k_Sequence_name_0_r_sequence_1_r), 0, 0, 1, 0},
-  {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1},
   {&__pyx_kp_s__2, __pyx_k__2, sizeof(__pyx_k__2), 0, 0, 1, 0},
   {&__pyx_kp_s__3, __pyx_k__3, sizeof(__pyx_k__3), 0, 0, 1, 0},
   {&__pyx_kp_s__4, __pyx_k__4, sizeof(__pyx_k__4), 0, 0, 1, 0},
   {&__pyx_kp_s__5, __pyx_k__5, sizeof(__pyx_k__5), 0, 0, 1, 0},
-  {&__pyx_kp_s__6, __pyx_k__6, sizeof(__pyx_k__6), 0, 0, 1, 0},
   {&__pyx_n_s_args, __pyx_k_args, sizeof(__pyx_k_args), 0, 0, 1, 1},
   {&__pyx_n_s_class, __pyx_k_class, sizeof(__pyx_k_class), 0, 0, 1, 1},
   {&__pyx_n_s_close, __pyx_k_close, sizeof(__pyx_k_close), 0, 0, 1, 1},
-  {&__pyx_n_s_close_on_exit, __pyx_k_close_on_exit, sizeof(__pyx_k_close_on_exit), 0, 0, 1, 1},
   {&__pyx_n_s_cutadapt__seqio, __pyx_k_cutadapt__seqio, sizeof(__pyx_k_cutadapt__seqio), 0, 0, 1, 1},
   {&__pyx_n_s_delivers_qualities, __pyx_k_delivers_qualities, sizeof(__pyx_k_delivers_qualities), 0, 0, 1, 1},
   {&__pyx_n_s_doc, __pyx_k_doc, sizeof(__pyx_k_doc), 0, 0, 1, 1},
-  {&__pyx_n_s_enter, __pyx_k_enter, sizeof(__pyx_k_enter), 0, 0, 1, 1},
-  {&__pyx_n_s_exit, __pyx_k_exit, sizeof(__pyx_k_exit), 0, 0, 1, 1},
   {&__pyx_n_s_file, __pyx_k_file, sizeof(__pyx_k_file), 0, 0, 1, 1},
   {&__pyx_n_s_file_2, __pyx_k_file_2, sizeof(__pyx_k_file_2), 0, 0, 1, 1},
   {&__pyx_n_s_format, __pyx_k_format, sizeof(__pyx_k_format), 0, 0, 1, 1},
@@ -5036,34 +4535,32 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s_line, __pyx_k_line, sizeof(__pyx_k_line), 0, 0, 1, 1},
   {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1},
   {&__pyx_n_s_match, __pyx_k_match, sizeof(__pyx_k_match), 0, 0, 1, 1},
+  {&__pyx_n_s_match_info, __pyx_k_match_info, sizeof(__pyx_k_match_info), 0, 0, 1, 1},
   {&__pyx_n_s_metaclass, __pyx_k_metaclass, sizeof(__pyx_k_metaclass), 0, 0, 1, 1},
   {&__pyx_n_s_module, __pyx_k_module, sizeof(__pyx_k_module), 0, 0, 1, 1},
-  {&__pyx_n_s_n, __pyx_k_n, sizeof(__pyx_k_n), 0, 0, 1, 1},
   {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1},
   {&__pyx_n_s_name2, __pyx_k_name2, sizeof(__pyx_k_name2), 0, 0, 1, 1},
-  {&__pyx_n_s_object, __pyx_k_object, sizeof(__pyx_k_object), 0, 0, 1, 1},
   {&__pyx_n_s_prepare, __pyx_k_prepare, sizeof(__pyx_k_prepare), 0, 0, 1, 1},
   {&__pyx_n_s_qualities, __pyx_k_qualities, sizeof(__pyx_k_qualities), 0, 0, 1, 1},
   {&__pyx_kp_s_qualities_0_r, __pyx_k_qualities_0_r, sizeof(__pyx_k_qualities_0_r), 0, 0, 1, 0},
   {&__pyx_n_s_qualname, __pyx_k_qualname, sizeof(__pyx_k_qualname), 0, 0, 1, 1},
   {&__pyx_n_s_rstrip, __pyx_k_rstrip, sizeof(__pyx_k_rstrip), 0, 0, 1, 1},
-  {&__pyx_n_s_s, __pyx_k_s, sizeof(__pyx_k_s), 0, 0, 1, 1},
   {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1},
   {&__pyx_n_s_send, __pyx_k_send, sizeof(__pyx_k_send), 0, 0, 1, 1},
+  {&__pyx_n_s_seqio, __pyx_k_seqio, sizeof(__pyx_k_seqio), 0, 0, 1, 1},
   {&__pyx_n_s_sequence, __pyx_k_sequence, sizeof(__pyx_k_sequence), 0, 0, 1, 1},
   {&__pyx_n_s_sequence_class, __pyx_k_sequence_class, sizeof(__pyx_k_sequence_class), 0, 0, 1, 1},
   {&__pyx_n_s_shorten, __pyx_k_shorten, sizeof(__pyx_k_shorten), 0, 0, 1, 1},
   {&__pyx_n_s_strip, __pyx_k_strip, sizeof(__pyx_k_strip), 0, 0, 1, 1},
+  {&__pyx_n_s_super, __pyx_k_super, sizeof(__pyx_k_super), 0, 0, 1, 1},
   {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1},
   {&__pyx_n_s_throw, __pyx_k_throw, sizeof(__pyx_k_throw), 0, 0, 1, 1},
   {&__pyx_n_s_xopen, __pyx_k_xopen, sizeof(__pyx_k_xopen), 0, 0, 1, 1},
   {0, 0, 0, 0, 0, 0, 0}
 };
 static int __Pyx_InitCachedBuiltins(void) {
-  __pyx_builtin_Exception = __Pyx_GetBuiltinName(__pyx_n_s_Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_object = __Pyx_GetBuiltinName(__pyx_n_s_object); if (!__pyx_builtin_object) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_NotImplementedError = __Pyx_GetBuiltinName(__pyx_n_s_NotImplementedError); if (!__pyx_builtin_NotImplementedError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_NotImplementedError = __Pyx_GetBuiltinName(__pyx_n_s_NotImplementedError); if (!__pyx_builtin_NotImplementedError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_super = __Pyx_GetBuiltinName(__pyx_n_s_super); if (!__pyx_builtin_super) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   return 0;
   __pyx_L1_error:;
   return -1;
@@ -5073,109 +4570,49 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0);
 
-  /* "cutadapt/_seqio.pyx":152
+  /* "cutadapt/_seqio.pyx":134
  * 					qualities = line[:strip]
  * 				else:
  * 					qualities = line.rstrip('\r\n')             # <<<<<<<<<<<<<<
  * 				yield sequence_class(name, sequence, qualities, name2=name2)
  * 			i = (i + 1) % 4
  */
-  __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s__4); if (unlikely(!__pyx_tuple__7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_tuple__7);
-  __Pyx_GIVEREF(__pyx_tuple__7);
+  __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_s__3); if (unlikely(!__pyx_tuple__6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_tuple__6);
+  __Pyx_GIVEREF(__pyx_tuple__6);
 
-  /* "cutadapt/_seqio.pyx":156
+  /* "cutadapt/_seqio.pyx":138
  * 			i = (i + 1) % 4
  * 		if i != 0:
  * 			raise FormatError("FASTQ file ended prematurely")             # <<<<<<<<<<<<<<
- * 
- * 	def close(self):
- */
-  __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_FASTQ_file_ended_prematurely); if (unlikely(!__pyx_tuple__8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_tuple__8);
-  __Pyx_GIVEREF(__pyx_tuple__8);
-
-  /* "cutadapt/_seqio.pyx":165
- * 	def __enter__(self):
- * 		if self._file is None:
- * 			raise ValueError("I/O operation on closed FastqReader")             # <<<<<<<<<<<<<<
- * 		return self
- * 
  */
-  __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_I_O_operation_on_closed_FastqRea); if (unlikely(!__pyx_tuple__9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_tuple__9);
-  __Pyx_GIVEREF(__pyx_tuple__9);
-
-  /* "cutadapt/_seqio.pyx":16
- * 
- * 
- * def _shorten(s, n=100):             # <<<<<<<<<<<<<<
- * 	"""Shorten string s to at most n characters, appending "..." if necessary."""
- * 	if s is None:
- */
-  __pyx_tuple__10 = PyTuple_Pack(2, __pyx_n_s_s, __pyx_n_s_n); if (unlikely(!__pyx_tuple__10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_tuple__10);
-  __Pyx_GIVEREF(__pyx_tuple__10);
-  __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_shorten, 16, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s_FASTQ_file_ended_prematurely); if (unlikely(!__pyx_tuple__7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_tuple__7);
+  __Pyx_GIVEREF(__pyx_tuple__7);
 
-  /* "cutadapt/_seqio.pyx":94
- * 	_close_on_exit = False
- * 
+  /* "cutadapt/_seqio.pyx":79
+ * 	Reader for FASTQ files. Does not support multi-line FASTQ files.
+ * 	"""
  * 	def __init__(self, file, sequence_class=Sequence):             # <<<<<<<<<<<<<<
  * 		"""
  * 		file is a filename or a file-like object.
  */
-  __pyx_tuple__12 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_file, __pyx_n_s_sequence_class); if (unlikely(!__pyx_tuple__12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_tuple__12);
-  __Pyx_GIVEREF(__pyx_tuple__12);
-  __pyx_codeobj__13 = (PyObject*)__Pyx_PyCode_New(3, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__12, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_init, 94, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__8 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_file, __pyx_n_s_sequence_class); if (unlikely(!__pyx_tuple__8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_tuple__8);
+  __Pyx_GIVEREF(__pyx_tuple__8);
+  __pyx_codeobj__9 = (PyObject*)__Pyx_PyCode_New(3, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_init, 79, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "cutadapt/_seqio.pyx":106
+  /* "cutadapt/_seqio.pyx":88
  * 		self.delivers_qualities = True
  * 
  * 	def __iter__(self):             # <<<<<<<<<<<<<<
  * 		"""
  * 		Yield Sequence objects
  */
-  __pyx_tuple__14 = PyTuple_Pack(10, __pyx_n_s_self, __pyx_n_s_i, __pyx_n_s_strip, __pyx_n_s_line, __pyx_n_s_name, __pyx_n_s_qualities, __pyx_n_s_sequence, __pyx_n_s_name2, __pyx_n_s_sequence_class, __pyx_n_s_it); if (unlikely(!__pyx_tuple__14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_tuple__14);
-  __Pyx_GIVEREF(__pyx_tuple__14);
-  __pyx_codeobj__15 = (PyObject*)__Pyx_PyCode_New(1, 0, 10, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__14, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_iter, 106, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_seqio.pyx":158
- * 			raise FormatError("FASTQ file ended prematurely")
- * 
- * 	def close(self):             # <<<<<<<<<<<<<<
- * 		if self._close_on_exit and self._file is not None:
- * 			self._file.close()
- */
-  __pyx_tuple__16 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_tuple__16);
-  __Pyx_GIVEREF(__pyx_tuple__16);
-  __pyx_codeobj__17 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__16, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_close, 158, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__17)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_seqio.pyx":163
- * 			self._file = None
- * 
- * 	def __enter__(self):             # <<<<<<<<<<<<<<
- * 		if self._file is None:
- * 			raise ValueError("I/O operation on closed FastqReader")
- */
-  __pyx_tuple__18 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__18)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_tuple__18);
-  __Pyx_GIVEREF(__pyx_tuple__18);
-  __pyx_codeobj__19 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__18, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_enter, 163, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__19)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_seqio.pyx":168
- * 		return self
- * 
- * 	def __exit__(self, *args):             # <<<<<<<<<<<<<<
- * 		self.close()
- */
-  __pyx_tuple__20 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_args); if (unlikely(!__pyx_tuple__20)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_tuple__20);
-  __Pyx_GIVEREF(__pyx_tuple__20);
-  __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(1, 0, 2, 0, CO_VARARGS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__20, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_exit, 168, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple__10 = PyTuple_Pack(10, __pyx_n_s_self, __pyx_n_s_i, __pyx_n_s_strip, __pyx_n_s_line, __pyx_n_s_name, __pyx_n_s_qualities, __pyx_n_s_sequence, __pyx_n_s_name2, __pyx_n_s_sequence_class, __pyx_n_s_it); if (unlikely(!__pyx_tuple__10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_tuple__10);
+  __Pyx_GIVEREF(__pyx_tuple__10);
+  __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(1, 0, 10, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_iter, 88, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -5185,8 +4622,6 @@ static int __Pyx_InitCachedConstants(void) {
 
 static int __Pyx_InitGlobals(void) {
   if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
-  __pyx_int_3 = PyInt_FromLong(3); if (unlikely(!__pyx_int_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_int_100 = PyInt_FromLong(100); if (unlikely(!__pyx_int_100)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   return 0;
   __pyx_L1_error:;
   return -1;
@@ -5281,11 +4716,11 @@ PyMODINIT_FUNC PyInit__seqio(void)
   /*--- Variable export code ---*/
   /*--- Function export code ---*/
   /*--- Type init code ---*/
-  if (PyType_Ready(&__pyx_type_8cutadapt_6_seqio_Sequence) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_8cutadapt_6_seqio_Sequence) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_type_8cutadapt_6_seqio_Sequence.tp_print = 0;
   #if CYTHON_COMPILING_IN_CPYTHON
   {
-    PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_8cutadapt_6_seqio_Sequence, "__init__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_8cutadapt_6_seqio_Sequence, "__init__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {
       __pyx_wrapperbase_8cutadapt_6_seqio_8Sequence___init__ = *((PyWrapperDescrObject *)wrapper)->d_base;
       __pyx_wrapperbase_8cutadapt_6_seqio_8Sequence___init__.doc = __pyx_doc_8cutadapt_6_seqio_8Sequence___init__;
@@ -5295,7 +4730,7 @@ PyMODINIT_FUNC PyInit__seqio(void)
   #endif
   #if CYTHON_COMPILING_IN_CPYTHON
   {
-    PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_8cutadapt_6_seqio_Sequence, "__getitem__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_8cutadapt_6_seqio_Sequence, "__getitem__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {
       __pyx_wrapperbase_8cutadapt_6_seqio_8Sequence_2__getitem__ = *((PyWrapperDescrObject *)wrapper)->d_base;
       __pyx_wrapperbase_8cutadapt_6_seqio_8Sequence_2__getitem__.doc = __pyx_doc_8cutadapt_6_seqio_8Sequence_2__getitem__;
@@ -5303,9 +4738,9 @@ PyMODINIT_FUNC PyInit__seqio(void)
     }
   }
   #endif
-  if (PyObject_SetAttrString(__pyx_m, "Sequence", (PyObject *)&__pyx_type_8cutadapt_6_seqio_Sequence) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetAttrString(__pyx_m, "Sequence", (PyObject *)&__pyx_type_8cutadapt_6_seqio_Sequence) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_8cutadapt_6_seqio_Sequence = &__pyx_type_8cutadapt_6_seqio_Sequence;
-  if (PyType_Ready(&__pyx_type_8cutadapt_6_seqio___pyx_scope_struct____iter__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_8cutadapt_6_seqio___pyx_scope_struct____iter__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_type_8cutadapt_6_seqio___pyx_scope_struct____iter__.tp_print = 0;
   __pyx_ptype_8cutadapt_6_seqio___pyx_scope_struct____iter__ = &__pyx_type_8cutadapt_6_seqio___pyx_scope_struct____iter__;
   /*--- Type import code ---*/
@@ -5317,11 +4752,11 @@ PyMODINIT_FUNC PyInit__seqio(void)
   #endif
 
   /* "cutadapt/_seqio.pyx":4
- * # cython: profile=False
+ * # cython: profile=False, emit_code_comments=False
  * from __future__ import print_function, division, absolute_import
  * from .xopen import xopen             # <<<<<<<<<<<<<<
+ * from .seqio import _shorten, FormatError, SequenceReader
  * 
- * # TODO
  */
   __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
@@ -5337,142 +4772,99 @@ PyMODINIT_FUNC PyInit__seqio(void)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "cutadapt/_seqio.pyx":10
- * # since we would get circular imports
+  /* "cutadapt/_seqio.pyx":5
+ * from __future__ import print_function, division, absolute_import
+ * from .xopen import xopen
+ * from .seqio import _shorten, FormatError, SequenceReader             # <<<<<<<<<<<<<<
+ * 
  * 
- * class FormatError(Exception):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Raised when an input file (FASTA or FASTQ) is malformatted.
  */
-  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyList_New(3); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_INCREF(__pyx_builtin_Exception);
-  __Pyx_GIVEREF(__pyx_builtin_Exception);
-  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_builtin_Exception);
-  __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_INCREF(__pyx_n_s_shorten);
+  __Pyx_GIVEREF(__pyx_n_s_shorten);
+  PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_shorten);
+  __Pyx_INCREF(__pyx_n_s_FormatError);
+  __Pyx_GIVEREF(__pyx_n_s_FormatError);
+  PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_FormatError);
+  __Pyx_INCREF(__pyx_n_s_SequenceReader);
+  __Pyx_GIVEREF(__pyx_n_s_SequenceReader);
+  PyList_SET_ITEM(__pyx_t_2, 2, __pyx_n_s_SequenceReader);
+  __pyx_t_1 = __Pyx_Import(__pyx_n_s_seqio, __pyx_t_2, 1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_3 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_2, __pyx_n_s_FormatError, __pyx_n_s_FormatError, (PyObject *) NULL, __pyx_n_s_cutadapt__seqio, __pyx_kp_s_Raised_when_an_input_file_FASTA); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_4 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_FormatError, __pyx_t_2, __pyx_t_3, NULL, 0, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_4);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_FormatError, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-
-  /* "cutadapt/_seqio.pyx":16
- * 
- * 
- * def _shorten(s, n=100):             # <<<<<<<<<<<<<<
- * 	"""Shorten string s to at most n characters, appending "..." if necessary."""
- * 	if s is None:
- */
-  __pyx_t_2 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_1_shorten, NULL, __pyx_n_s_cutadapt__seqio); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_1, __pyx_n_s_shorten); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_shorten, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_1, __pyx_n_s_FormatError); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_FormatError, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_1, __pyx_n_s_SequenceReader); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_shorten, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_SequenceReader, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_seqio.pyx":88
+  /* "cutadapt/_seqio.pyx":75
  * 
  * 
- * class FastqReader(object):             # <<<<<<<<<<<<<<
+ * class FastqReader(SequenceReader):             # <<<<<<<<<<<<<<
  * 	"""
  * 	Reader for FASTQ files. Does not support multi-line FASTQ files.
  */
-  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SequenceReader); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_INCREF(__pyx_builtin_object);
-  __Pyx_GIVEREF(__pyx_builtin_object);
-  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_builtin_object);
-  __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GIVEREF(__pyx_t_1);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1);
+  __pyx_t_1 = 0;
+  __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_3 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_2, __pyx_n_s_FastqReader, __pyx_n_s_FastqReader, (PyObject *) NULL, __pyx_n_s_cutadapt__seqio, __pyx_kp_s_Reader_for_FASTQ_files_Does_not); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_2, __pyx_n_s_FastqReader, __pyx_n_s_FastqReader, (PyObject *) NULL, __pyx_n_s_cutadapt__seqio, __pyx_kp_s_Reader_for_FASTQ_files_Does_not); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
 
-  /* "cutadapt/_seqio.pyx":92
+  /* "cutadapt/_seqio.pyx":79
  * 	Reader for FASTQ files. Does not support multi-line FASTQ files.
  * 	"""
- * 	_close_on_exit = False             # <<<<<<<<<<<<<<
- * 
- * 	def __init__(self, file, sequence_class=Sequence):
- */
-  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_close_on_exit, Py_False) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 92; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_seqio.pyx":94
- * 	_close_on_exit = False
- * 
  * 	def __init__(self, file, sequence_class=Sequence):             # <<<<<<<<<<<<<<
  * 		"""
  * 		file is a filename or a file-like object.
  */
-  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_1__init__, 0, __pyx_n_s_FastqReader___init, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__13)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_1__init__, 0, __pyx_n_s_FastqReader___init, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__9)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_4);
-  if (!__Pyx_CyFunction_InitDefaults(__pyx_t_4, sizeof(__pyx_defaults), 1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!__Pyx_CyFunction_InitDefaults(__pyx_t_4, sizeof(__pyx_defaults), 1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_INCREF(((PyObject *)__pyx_ptype_8cutadapt_6_seqio_Sequence));
   __Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_t_4)->__pyx_arg_sequence_class = ((PyObject *)__pyx_ptype_8cutadapt_6_seqio_Sequence);
   __Pyx_GIVEREF(__pyx_ptype_8cutadapt_6_seqio_Sequence);
-  __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_4, __pyx_pf_8cutadapt_6_seqio_11FastqReader_11__defaults__);
-  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_init, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_4, __pyx_pf_8cutadapt_6_seqio_11FastqReader_5__defaults__);
+  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_init, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "cutadapt/_seqio.pyx":106
+  /* "cutadapt/_seqio.pyx":88
  * 		self.delivers_qualities = True
  * 
  * 	def __iter__(self):             # <<<<<<<<<<<<<<
  * 		"""
  * 		Yield Sequence objects
  */
-  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_3__iter__, 0, __pyx_n_s_FastqReader___iter, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__15)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_3__iter__, 0, __pyx_n_s_FastqReader___iter, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__11)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_4);
-  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_iter, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_iter, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  /* "cutadapt/_seqio.pyx":158
- * 			raise FormatError("FASTQ file ended prematurely")
+  /* "cutadapt/_seqio.pyx":75
  * 
- * 	def close(self):             # <<<<<<<<<<<<<<
- * 		if self._close_on_exit and self._file is not None:
- * 			self._file.close()
- */
-  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_6close, 0, __pyx_n_s_FastqReader_close, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__17)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_4);
-  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_close, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-
-  /* "cutadapt/_seqio.pyx":163
- * 			self._file = None
  * 
- * 	def __enter__(self):             # <<<<<<<<<<<<<<
- * 		if self._file is None:
- * 			raise ValueError("I/O operation on closed FastqReader")
- */
-  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_8__enter__, 0, __pyx_n_s_FastqReader___enter, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__19)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_4);
-  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_enter, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-
-  /* "cutadapt/_seqio.pyx":168
- * 		return self
- * 
- * 	def __exit__(self, *args):             # <<<<<<<<<<<<<<
- * 		self.close()
- */
-  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_10__exit__, 0, __pyx_n_s_FastqReader___exit, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__21)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_4);
-  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_exit, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-
-  /* "cutadapt/_seqio.pyx":88
- * 
- * 
- * class FastqReader(object):             # <<<<<<<<<<<<<<
+ * class FastqReader(SequenceReader):             # <<<<<<<<<<<<<<
  * 	"""
  * 	Reader for FASTQ files. Does not support multi-line FASTQ files.
  */
-  __pyx_t_4 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_FastqReader, __pyx_t_2, __pyx_t_3, NULL, 0, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_FastqReader, __pyx_t_2, __pyx_t_3, NULL, 0, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_4);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_FastqReader, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_FastqReader, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -5480,7 +4872,7 @@ PyMODINIT_FUNC PyInit__seqio(void)
 
   /* "cutadapt/_seqio.pyx":1
  * # kate: syntax Python;             # <<<<<<<<<<<<<<
- * # cython: profile=False
+ * # cython: profile=False, emit_code_comments=False
  * from __future__ import print_function, division, absolute_import
  */
   __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
@@ -5540,7 +4932,32 @@ static PyObject *__Pyx_GetBuiltinName(PyObject *name) {
             "name '%.200s' is not defined", PyString_AS_STRING(name));
 #endif
     }
-    return result;
+    return result;
+}
+
+static void __Pyx_RaiseArgtupleInvalid(
+    const char* func_name,
+    int exact,
+    Py_ssize_t num_min,
+    Py_ssize_t num_max,
+    Py_ssize_t num_found)
+{
+    Py_ssize_t num_expected;
+    const char *more_or_less;
+    if (num_found < num_min) {
+        num_expected = num_min;
+        more_or_less = "at least";
+    } else {
+        num_expected = num_max;
+        more_or_less = "at most";
+    }
+    if (exact) {
+        more_or_less = "exactly";
+    }
+    PyErr_Format(PyExc_TypeError,
+                 "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)",
+                 func_name, more_or_less, num_expected,
+                 (num_expected == 1) ? "" : "s", num_found);
 }
 
 static void __Pyx_RaiseDoubleKeywordsError(
@@ -5657,229 +5074,6 @@ bad:
     return -1;
 }
 
-static void __Pyx_RaiseArgtupleInvalid(
-    const char* func_name,
-    int exact,
-    Py_ssize_t num_min,
-    Py_ssize_t num_max,
-    Py_ssize_t num_found)
-{
-    Py_ssize_t num_expected;
-    const char *more_or_less;
-    if (num_found < num_min) {
-        num_expected = num_min;
-        more_or_less = "at least";
-    } else {
-        num_expected = num_max;
-        more_or_less = "at most";
-    }
-    if (exact) {
-        more_or_less = "exactly";
-    }
-    PyErr_Format(PyExc_TypeError,
-                 "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)",
-                 func_name, more_or_less, num_expected,
-                 (num_expected == 1) ? "" : "s", num_found);
-}
-
-#if CYTHON_USE_PYLONG_INTERNALS
-  #include "longintrepr.h"
-#endif
-
-#if CYTHON_COMPILING_IN_CPYTHON
-static PyObject* __Pyx_PyInt_SubtractObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) {
-    #if PY_MAJOR_VERSION < 3
-    if (likely(PyInt_CheckExact(op1))) {
-        const long b = intval;
-        long x;
-        long a = PyInt_AS_LONG(op1);
-            x = (long)((unsigned long)a - b);
-            if (likely((x^a) >= 0 || (x^~b) >= 0))
-                return PyInt_FromLong(x);
-            return PyLong_Type.tp_as_number->nb_subtract(op1, op2);
-    }
-    #endif
-    #if CYTHON_USE_PYLONG_INTERNALS && PY_MAJOR_VERSION >= 3
-    if (likely(PyLong_CheckExact(op1))) {
-        const long b = intval;
-        long a, x;
-        const PY_LONG_LONG llb = intval;
-        PY_LONG_LONG lla, llx;
-        const digit* digits = ((PyLongObject*)op1)->ob_digit;
-        const Py_ssize_t size = Py_SIZE(op1);
-        if (likely(__Pyx_sst_abs(size) <= 1)) {
-            a = likely(size) ? digits[0] : 0;
-            if (size == -1) a = -a;
-        } else {
-            switch (size) {
-                case -2:
-                    if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
-                        a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
-                        break;
-                    } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) {
-                        lla = -(PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
-                        goto long_long;
-                    }
-                case 2:
-                    if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
-                        a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
-                        break;
-                    } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) {
-                        lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
-                        goto long_long;
-                    }
-                case -3:
-                    if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
-                        a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
-                        break;
-                    } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) {
-                        lla = -(PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
-                        goto long_long;
-                    }
-                case 3:
-                    if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
-                        a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
-                        break;
-                    } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) {
-                        lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
-                        goto long_long;
-                    }
-                case -4:
-                    if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
-                        a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
-                        break;
-                    } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) {
-                        lla = -(PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
-                        goto long_long;
-                    }
-                case 4:
-                    if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
-                        a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
-                        break;
-                    } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) {
-                        lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
-                        goto long_long;
-                    }
-                default: return PyLong_Type.tp_as_number->nb_subtract(op1, op2);
-            }
-        }
-                x = a - b;
-            return PyLong_FromLong(x);
-        long_long:
-                llx = lla - llb;
-            return PyLong_FromLongLong(llx);
-    }
-    #endif
-    if (PyFloat_CheckExact(op1)) {
-        const long b = intval;
-        double a = PyFloat_AS_DOUBLE(op1);
-            double result;
-            PyFPE_START_PROTECT("subtract", return NULL)
-            result = ((double)a) - (double)b;
-            PyFPE_END_PROTECT(result)
-            return PyFloat_FromDouble(result);
-    }
-    return (inplace ? PyNumber_InPlaceSubtract : PyNumber_Subtract)(op1, op2);
-}
-#endif
-
-static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice(PyObject* obj,
-        Py_ssize_t cstart, Py_ssize_t cstop,
-        PyObject** _py_start, PyObject** _py_stop, PyObject** _py_slice,
-        int has_cstart, int has_cstop, CYTHON_UNUSED int wraparound) {
-#if CYTHON_COMPILING_IN_CPYTHON
-    PyMappingMethods* mp;
-#if PY_MAJOR_VERSION < 3
-    PySequenceMethods* ms = Py_TYPE(obj)->tp_as_sequence;
-    if (likely(ms && ms->sq_slice)) {
-        if (!has_cstart) {
-            if (_py_start && (*_py_start != Py_None)) {
-                cstart = __Pyx_PyIndex_AsSsize_t(*_py_start);
-                if ((cstart == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad;
-            } else
-                cstart = 0;
-        }
-        if (!has_cstop) {
-            if (_py_stop && (*_py_stop != Py_None)) {
-                cstop = __Pyx_PyIndex_AsSsize_t(*_py_stop);
-                if ((cstop == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad;
-            } else
-                cstop = PY_SSIZE_T_MAX;
-        }
-        if (wraparound && unlikely((cstart < 0) | (cstop < 0)) && likely(ms->sq_length)) {
-            Py_ssize_t l = ms->sq_length(obj);
-            if (likely(l >= 0)) {
-                if (cstop < 0) {
-                    cstop += l;
-                    if (cstop < 0) cstop = 0;
-                }
-                if (cstart < 0) {
-                    cstart += l;
-                    if (cstart < 0) cstart = 0;
-                }
-            } else {
-                if (PyErr_ExceptionMatches(PyExc_OverflowError))
-                    PyErr_Clear();
-                else
-                    goto bad;
-            }
-        }
-        return ms->sq_slice(obj, cstart, cstop);
-    }
-#endif
-    mp = Py_TYPE(obj)->tp_as_mapping;
-    if (likely(mp && mp->mp_subscript))
-#endif
-    {
-        PyObject* result;
-        PyObject *py_slice, *py_start, *py_stop;
-        if (_py_slice) {
-            py_slice = *_py_slice;
-        } else {
-            PyObject* owned_start = NULL;
-            PyObject* owned_stop = NULL;
-            if (_py_start) {
-                py_start = *_py_start;
-            } else {
-                if (has_cstart) {
-                    owned_start = py_start = PyInt_FromSsize_t(cstart);
-                    if (unlikely(!py_start)) goto bad;
-                } else
-                    py_start = Py_None;
-            }
-            if (_py_stop) {
-                py_stop = *_py_stop;
-            } else {
-                if (has_cstop) {
-                    owned_stop = py_stop = PyInt_FromSsize_t(cstop);
-                    if (unlikely(!py_stop)) {
-                        Py_XDECREF(owned_start);
-                        goto bad;
-                    }
-                } else
-                    py_stop = Py_None;
-            }
-            py_slice = PySlice_New(py_start, py_stop, Py_None);
-            Py_XDECREF(owned_start);
-            Py_XDECREF(owned_stop);
-            if (unlikely(!py_slice)) goto bad;
-        }
-#if CYTHON_COMPILING_IN_CPYTHON
-        result = mp->mp_subscript(obj, py_slice);
-#else
-        result = PyObject_GetItem(obj, py_slice);
-#endif
-        if (!_py_slice) {
-            Py_DECREF(py_slice);
-        }
-        return result;
-    }
-    PyErr_Format(PyExc_TypeError,
-        "'%.200s' object is unsliceable", Py_TYPE(obj)->tp_name);
-bad:
-    return NULL;
-}
-
 static void __Pyx_RaiseArgumentTypeInvalid(const char* name, PyObject *obj, PyTypeObject *type) {
     PyErr_Format(PyExc_TypeError,
         "Argument '%.200s' has incorrect type (expected %.200s, got %.200s)",
@@ -5986,8 +5180,12 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
 }
 #else
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
-    PyObject* args = PyTuple_Pack(1, arg);
-    return (likely(args)) ? __Pyx_PyObject_Call(func, args, NULL) : NULL;
+    PyObject *result;
+    PyObject *args = PyTuple_Pack(1, arg);
+    if (unlikely(!args)) return NULL;
+    result = __Pyx_PyObject_Call(func, args, NULL);
+    Py_DECREF(args);
+    return result;
 }
 #endif
 
@@ -6672,72 +5870,6 @@ static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bas
     return (PyObject*) metaclass;
 }
 
-static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name,
-                                           PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) {
-    PyObject *ns;
-    if (metaclass) {
-        PyObject *prep = __Pyx_PyObject_GetAttrStr(metaclass, __pyx_n_s_prepare);
-        if (prep) {
-            PyObject *pargs = PyTuple_Pack(2, name, bases);
-            if (unlikely(!pargs)) {
-                Py_DECREF(prep);
-                return NULL;
-            }
-            ns = PyObject_Call(prep, pargs, mkw);
-            Py_DECREF(prep);
-            Py_DECREF(pargs);
-        } else {
-            if (unlikely(!PyErr_ExceptionMatches(PyExc_AttributeError)))
-                return NULL;
-            PyErr_Clear();
-            ns = PyDict_New();
-        }
-    } else {
-        ns = PyDict_New();
-    }
-    if (unlikely(!ns))
-        return NULL;
-    if (unlikely(PyObject_SetItem(ns, __pyx_n_s_module, modname) < 0)) goto bad;
-    if (unlikely(PyObject_SetItem(ns, __pyx_n_s_qualname, qualname) < 0)) goto bad;
-    if (unlikely(doc && PyObject_SetItem(ns, __pyx_n_s_doc, doc) < 0)) goto bad;
-    return ns;
-bad:
-    Py_DECREF(ns);
-    return NULL;
-}
-static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases,
-                                      PyObject *dict, PyObject *mkw,
-                                      int calculate_metaclass, int allow_py2_metaclass) {
-    PyObject *result, *margs;
-    PyObject *owned_metaclass = NULL;
-    if (allow_py2_metaclass) {
-        owned_metaclass = PyObject_GetItem(dict, __pyx_n_s_metaclass);
-        if (owned_metaclass) {
-            metaclass = owned_metaclass;
-        } else if (likely(PyErr_ExceptionMatches(PyExc_KeyError))) {
-            PyErr_Clear();
-        } else {
-            return NULL;
-        }
-    }
-    if (calculate_metaclass && (!metaclass || PyType_Check(metaclass))) {
-        metaclass = __Pyx_CalculateMetaclass((PyTypeObject*) metaclass, bases);
-        Py_XDECREF(owned_metaclass);
-        if (unlikely(!metaclass))
-            return NULL;
-        owned_metaclass = metaclass;
-    }
-    margs = PyTuple_Pack(3, name, bases, dict);
-    if (unlikely(!margs)) {
-        result = NULL;
-    } else {
-        result = PyObject_Call(metaclass, margs, mkw);
-        Py_DECREF(margs);
-    }
-    Py_XDECREF(owned_metaclass);
-    return result;
-}
-
 static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) {
     PyObject* fake_module;
     PyTypeObject* cached_type = NULL;
@@ -7342,6 +6474,72 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, Py
     Py_INCREF(dict);
 }
 
+static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name,
+                                           PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) {
+    PyObject *ns;
+    if (metaclass) {
+        PyObject *prep = __Pyx_PyObject_GetAttrStr(metaclass, __pyx_n_s_prepare);
+        if (prep) {
+            PyObject *pargs = PyTuple_Pack(2, name, bases);
+            if (unlikely(!pargs)) {
+                Py_DECREF(prep);
+                return NULL;
+            }
+            ns = PyObject_Call(prep, pargs, mkw);
+            Py_DECREF(prep);
+            Py_DECREF(pargs);
+        } else {
+            if (unlikely(!PyErr_ExceptionMatches(PyExc_AttributeError)))
+                return NULL;
+            PyErr_Clear();
+            ns = PyDict_New();
+        }
+    } else {
+        ns = PyDict_New();
+    }
+    if (unlikely(!ns))
+        return NULL;
+    if (unlikely(PyObject_SetItem(ns, __pyx_n_s_module, modname) < 0)) goto bad;
+    if (unlikely(PyObject_SetItem(ns, __pyx_n_s_qualname, qualname) < 0)) goto bad;
+    if (unlikely(doc && PyObject_SetItem(ns, __pyx_n_s_doc, doc) < 0)) goto bad;
+    return ns;
+bad:
+    Py_DECREF(ns);
+    return NULL;
+}
+static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases,
+                                      PyObject *dict, PyObject *mkw,
+                                      int calculate_metaclass, int allow_py2_metaclass) {
+    PyObject *result, *margs;
+    PyObject *owned_metaclass = NULL;
+    if (allow_py2_metaclass) {
+        owned_metaclass = PyObject_GetItem(dict, __pyx_n_s_metaclass);
+        if (owned_metaclass) {
+            metaclass = owned_metaclass;
+        } else if (likely(PyErr_ExceptionMatches(PyExc_KeyError))) {
+            PyErr_Clear();
+        } else {
+            return NULL;
+        }
+    }
+    if (calculate_metaclass && (!metaclass || PyType_Check(metaclass))) {
+        metaclass = __Pyx_CalculateMetaclass((PyTypeObject*) metaclass, bases);
+        Py_XDECREF(owned_metaclass);
+        if (unlikely(!metaclass))
+            return NULL;
+        owned_metaclass = metaclass;
+    }
+    margs = PyTuple_Pack(3, name, bases, dict);
+    if (unlikely(!margs)) {
+        result = NULL;
+    } else {
+        result = PyObject_Call(metaclass, margs, mkw);
+        Py_DECREF(margs);
+    }
+    Py_XDECREF(owned_metaclass);
+    return result;
+}
+
 static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
     int start = 0, mid = 0, end = count - 1;
     if (end >= 0 && code_line > entries[end].code_line) {
@@ -7522,6 +6720,10 @@ bad:
         return (target_type) value;\
     }
 
+#if CYTHON_USE_PYLONG_INTERNALS
+  #include "longintrepr.h"
+#endif
+
 static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
     const int neg_one = (int) -1, const_zero = (int) 0;
     const int is_unsigned = neg_one > const_zero;
@@ -8167,7 +7369,7 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
         #endif
         {
             if (value == Py_None)
-                ret = PyIter_Next(yf);
+                ret = Py_TYPE(yf)->tp_iternext(yf);
             else
                 ret = __Pyx_PyObject_CallMethod1(yf, __pyx_n_s_send, value);
         }
diff --git a/cutadapt/_seqio.pyx b/cutadapt/_seqio.pyx
index add0442..b687c0b 100644
--- a/cutadapt/_seqio.pyx
+++ b/cutadapt/_seqio.pyx
@@ -1,25 +1,8 @@
 # kate: syntax Python;
-# cython: profile=False
+# cython: profile=False, emit_code_comments=False
 from __future__ import print_function, division, absolute_import
 from .xopen import xopen
-
-# TODO
-# the following function and class cannot be imported from seqio.py
-# since we would get circular imports
-
-class FormatError(Exception):
-	"""
-	Raised when an input file (FASTA or FASTQ) is malformatted.
-	"""
-
-
-def _shorten(s, n=100):
-	"""Shorten string s to at most n characters, appending "..." if necessary."""
-	if s is None:
-		return None
-	if len(s) > n:
-		s = s[:n-3] + '...'
-	return s
+from .seqio import _shorten, FormatError, SequenceReader
 
 
 cdef class Sequence(object):
@@ -37,20 +20,23 @@ cdef class Sequence(object):
 		public str qualities
 		public str name2
 		public object match
+		public object match_info
 
-	def __init__(self, str name, str sequence, str qualities=None, str name2='',
-			match=None):
+	def __init__(self, str name, str sequence, str qualities=None, str name2='', match=None,
+				 match_info=None):
 		"""Set qualities to None if there are no quality values"""
 		self.name = name
 		self.sequence = sequence
 		self.qualities = qualities
 		self.name2 = name2
 		self.match = match
+		self.match_info = match_info
 		if qualities is not None and len(qualities) != len(sequence):
 			rname = _shorten(name)
-			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length of read ({2}) do not match".format(
-				rname, len(qualities), len(sequence)))
-
+			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length "
+				"of read ({2}) do not match".format(
+					rname, len(qualities), len(sequence)))
+	
 	def __getitem__(self, key):
 		"""slicing"""
 		return self.__class__(
@@ -58,7 +44,8 @@ cdef class Sequence(object):
 			self.sequence[key],
 			self.qualities[key] if self.qualities is not None else None,
 			self.name2,
-			self.match)
+			self.match,
+			self.match_info)
 
 	def __repr__(self):
 		qstr = ''
@@ -85,21 +72,16 @@ cdef class Sequence(object):
 		return (Sequence, (self.name, self.sequence, self.qualities, self.name2))
 
 
-class FastqReader(object):
+class FastqReader(SequenceReader):
 	"""
 	Reader for FASTQ files. Does not support multi-line FASTQ files.
 	"""
-	_close_on_exit = False
-
 	def __init__(self, file, sequence_class=Sequence):
 		"""
 		file is a filename or a file-like object.
 		If file is a filename, then .gz files are supported.
 		"""
-		if isinstance(file, basestring):
-			file = xopen(file)
-			self._close_on_exit = True
-		self._file = file
+		super(FastqReader, self).__init__(file)
 		self.sequence_class = sequence_class
 		self.delivers_qualities = True
 
@@ -154,16 +136,3 @@ class FastqReader(object):
 			i = (i + 1) % 4
 		if i != 0:
 			raise FormatError("FASTQ file ended prematurely")
-
-	def close(self):
-		if self._close_on_exit and self._file is not None:
-			self._file.close()
-			self._file = None
-
-	def __enter__(self):
-		if self._file is None:
-			raise ValueError("I/O operation on closed FastqReader")
-		return self
-
-	def __exit__(self, *args):
-		self.close()
diff --git a/cutadapt/_seqio.so b/cutadapt/_seqio.so
deleted file mode 100755
index d1e8af2..0000000
Binary files a/cutadapt/_seqio.so and /dev/null differ
diff --git a/cutadapt/adapters.py b/cutadapt/adapters.py
index 737da4b..f629c8f 100644
--- a/cutadapt/adapters.py
+++ b/cutadapt/adapters.py
@@ -11,39 +11,13 @@ from cutadapt.seqio import ColorspaceSequence, FastaReader
 
 # Constants for the find_best_alignment function.
 # The function is called with SEQ1 as the adapter, SEQ2 as the read.
+# TODO get rid of those constants, use strings instead
 BACK = align.START_WITHIN_SEQ2 | align.STOP_WITHIN_SEQ2 | align.STOP_WITHIN_SEQ1
 FRONT = align.START_WITHIN_SEQ2 | align.STOP_WITHIN_SEQ2 | align.START_WITHIN_SEQ1
 PREFIX = align.STOP_WITHIN_SEQ2
 SUFFIX = align.START_WITHIN_SEQ2
 ANYWHERE = align.SEMIGLOBAL
-
-
-def parse_adapter_name(seq):
-	"""
-	Parse an adapter given as 'name=adapt' into 'name' and 'adapt'.
-	"""
-	fields = seq.split('=', 1)
-	if len(fields) > 1:
-		name, seq = fields
-		name = name.strip()
-	else:
-		name = None
-	seq = seq.strip()
-	return name, seq
-
-
-def parse_adapter(sequence, where):
-	"""
-	Recognize anchored adapter sequences and return a corrected tuple
-	(sequence, where).
-	"""
-	if where == FRONT and sequence.startswith('^'):
-		return (sequence[1:], PREFIX)
-	if where == BACK and sequence.endswith('$'):
-		return (sequence[:-1], SUFFIX)
-	if where == BACK and sequence.endswith('...'):
-		return (sequence[:-3], PREFIX)
-	return (sequence, where)
+LINKED = 'linked'
 
 
 def parse_braces(sequence):
@@ -86,27 +60,102 @@ def parse_braces(sequence):
 	return result
 
 
-def gather_adapters(back, anywhere, front):
+class AdapterParser(object):
 	"""
-	Yield (name, seq, where) tuples from which Adapter instances can be built.
-	This generator deals with the notation for anchored 5'/3' adapters and also
-	understands the ``file:`` syntax for reading adapters from an external FASTA
-	file.
+	Factory for Adapter classes that all use the same parameters (error rate,
+	indels etc.). The given **kwargs will be passed to the Adapter constructors.
 	"""
-	for adapter_list, where in ((back, BACK), (anywhere, ANYWHERE), (front, FRONT)):
-		for seq in adapter_list:
-			if seq.startswith('file:'):
-				# read adapter sequences from a file
-				path = seq[5:]
-				with FastaReader(path) as fasta:
-					for record in fasta:
-						name = record.name.split(None, 1)[0]
-						seq, w = parse_adapter(record.sequence, where)
-						yield (name, seq, w)
-			else:
-				name, seq = parse_adapter_name(seq)
-				seq, w = parse_adapter(seq, where)
-				yield (name, seq, w)
+	def __init__(self, colorspace=False, **kwargs):
+		self.colorspace = colorspace
+		self.constructor_args = kwargs
+		self.adapter_class = ColorspaceAdapter if colorspace else Adapter
+
+	def parse(self, spec, name=None, cmdline_type='back'):
+		"""
+		Parse an adapter specification not using ``file:`` notation and return
+		an object of an appropriate Adapter class. The notation for anchored
+		5' and 3' adapters is supported. If the name parameter is None, then
+		an attempt is made to extract the name from the specification
+		(If spec is 'name=ADAPTER', name will be 'name'.)
+
+		cmdline_type -- describes which commandline parameter was used (``-a``
+		is 'back', ``-b`` is 'anywhere', and ``-g`` is 'front').
+		"""
+		if name is None:
+			name, spec = self._extract_name(spec)
+		sequence = spec
+		types = dict(back=BACK, front=FRONT, anywhere=ANYWHERE)
+		if cmdline_type not in types:
+			raise ValueError('cmdline_type cannot be {0!r}'.format(cmdline_type))
+		where = types[cmdline_type]
+		if where == FRONT and spec.startswith('^'):  # -g ^ADAPTER
+			sequence, where = spec[1:], PREFIX
+		elif where == BACK:
+			sequence1, middle, sequence2 = spec.partition('...')
+			if middle == '...':
+				if not sequence1:  # -a ...ADAPTER
+					sequence = sequence1[3:]
+				elif not sequence2:  # -a ADAPTER...
+					sequence, where = spec[:-3], PREFIX
+				else:  # -a ADAPTER1...ADAPTER2
+					if self.colorspace:
+						raise NotImplementedError('Using linked adapters in colorspace is not supported')
+					if sequence1.startswith('^') or sequence2.endswith('$'):
+						raise NotImplementedError('Using "$" or "^" when '
+							'specifying a linked adapter is not supported')
+					return LinkedAdapter(sequence1, sequence2, name=name,
+						**self.constructor_args)
+			elif spec.endswith('$'):   # -a ADAPTER$
+				sequence, where = spec[:-1], SUFFIX
+		if not sequence:
+			raise ValueError("The adapter sequence is empty.")
+
+		return self.adapter_class(sequence, where, name=name, **self.constructor_args)
+
+	def parse_with_file(self, spec, cmdline_type='back'):
+		"""
+		Parse an adapter specification and yield appropriate Adapter classes.
+		This works like the parse() function above, but also supports the
+		``file:`` notation for reading adapters from an external FASTA
+		file. Since a file can contain multiple adapters, this
+		function is a generator.
+		"""
+		if spec.startswith('file:'):
+			# read adapter sequences from a file
+			with FastaReader(spec[5:]) as fasta:
+				for record in fasta:
+					name = record.name.split(None, 1)[0]
+					yield self.parse(record.sequence, name, cmdline_type)
+		else:
+			name, spec = self._extract_name(spec)
+			yield self.parse(spec, name, cmdline_type)
+
+	def _extract_name(self, spec):
+		"""
+		Parse an adapter specification given as 'name=adapt' into 'name' and 'adapt'.
+		"""
+		fields = spec.split('=', 1)
+		if len(fields) > 1:
+			name, spec = fields
+			name = name.strip()
+		else:
+			name = None
+		spec = spec.strip()
+		return name, spec
+
+	def parse_multi(self, back, anywhere, front):
+		"""
+		Parse all three types of commandline options that can be used to
+		specify adapters. back, anywhere and front are lists of strings,
+		corresponding to the respective commandline types (-a, -b, -g).
+
+		Return a list of appropriate Adapter classes.
+		"""
+		adapters = []
+		for specs, cmdline_type in (back, 'back'), (anywhere, 'anywhere'), (front, 'front'):
+			for spec in specs:
+				adapters.extend(self.parse_with_file(spec, cmdline_type))
+		return adapters
 
 
 class Match(object):
@@ -128,6 +177,9 @@ class Match(object):
 		# indels, this may be different from the number of characters
 		# in the read.
 		self.length = self.astop - self.astart
+		assert self.length > 0
+		assert self.errors / self.length <= self.adapter.max_error_rate
+		assert self.length - self.errors > 0
 
 	def __str__(self):
 		return 'Match(astart={0}, astop={1}, rstart={2}, rstop={3}, matches={4}, errors={5})'.format(
@@ -166,9 +218,32 @@ class Match(object):
 			return self.read.sequence[:self.rstart]
 		else:
 			return self.read.sequence[self.rstop:]
+	
+	def get_info_record(self):
+		seq = self.read.sequence
+		qualities = self.read.qualities
+		info = (
+			self.read.name,
+			self.errors,
+			self.rstart,
+			self.rstop,
+			seq[0:self.rstart],
+			seq[self.rstart:self.rstop],
+			seq[self.rstop:],
+			self.adapter.name
+		)
+		if qualities:
+			info += (
+				qualities[0:self.rstart],
+				qualities[self.rstart:self.rstop],
+				qualities[self.rstop:]
+			)
+		else:
+			info += ('','','')
+		
+		return info
 
-
-def generate_adapter_name(_start=[1]):
+def _generate_adapter_name(_start=[1]):
 	name = str(_start[0])
 	_start[0] += 1
 	return name
@@ -202,12 +277,12 @@ class Adapter(object):
 	name -- optional name of the adapter. If not provided, the name is set to a
 		unique number.
 	"""
-	def __init__(self, sequence, where, max_error_rate, min_overlap=3,
-			read_wildcards=False, adapter_wildcards=True,
-			name=None, indels=True):
+	def __init__(self, sequence, where, max_error_rate=0.1, min_overlap=3,
+			read_wildcards=False, adapter_wildcards=True, name=None, indels=True):
 		self.debug = False
-		self.name = generate_adapter_name() if name is None else name
+		self.name = _generate_adapter_name() if name is None else name
 		self.sequence = parse_braces(sequence.upper().replace('U', 'T'))
+		assert len(self.sequence) > 0
 		self.where = where
 		self.max_error_rate = max_error_rate
 		self.min_overlap = min(min_overlap, len(self.sequence))
@@ -409,3 +484,86 @@ class ColorspaceAdapter(Adapter):
 
 	def __repr__(self):
 		return '<ColorspaceAdapter(sequence={0!r}, where={1})>'.format(self.sequence, self.where)
+
+
+class LinkedMatch(object):
+	"""
+	Represent a match of a LinkedAdapter.
+
+	TODO
+	It shouldn’t be necessary to have both a Match and a LinkedMatch class.
+	"""
+	def __init__(self, front_match, back_match, adapter):
+		self.front_match = front_match
+		self.back_match = back_match
+		self.adapter = adapter
+		assert front_match is not None
+
+
+class LinkedAdapter(object):
+	"""
+	"""
+	def __init__(self, front_sequence, back_sequence,
+			front_anchored=True, back_anchored=False, name=None, **kwargs):
+		"""
+		kwargs are passed on to individual Adapter constructors
+		"""
+		assert front_anchored and not back_anchored
+		where1 = PREFIX if front_anchored else FRONT
+		where2 = SUFFIX if back_anchored else BACK
+		self.front_anchored = front_anchored
+		self.back_anchored = back_anchored
+
+		# The following attributes are needed for the report
+		self.where = LINKED
+		self.name = _generate_adapter_name() if name is None else name
+		self.front_adapter = Adapter(front_sequence, where=where1, name=None, **kwargs)
+		self.back_adapter = Adapter(back_sequence, where=where2, name=None, **kwargs)
+
+	def enable_debug(self):
+		self.front_adapter.enable_debug()
+		self.back_adapter.enable_debug()
+
+	def match_to(self, read):
+		"""
+		Match the linked adapters against the given read. If the 'front' adapter
+		is not found, the 'back' adapter is not searched for.
+		"""
+		front_match = self.front_adapter.match_to(read)
+		if front_match is None:
+			return None
+		# TODO use match.trimmed() instead as soon as that does not update
+		# statistics anymore
+		read = read[front_match.rstop:]
+		back_match = self.back_adapter.match_to(read)
+		return LinkedMatch(front_match, back_match, self)
+
+	def trimmed(self, match):
+		front_trimmed = self.front_adapter.trimmed(match.front_match)
+		if match.back_match:
+			return self.back_adapter.trimmed(match.back_match)
+		else:
+			return front_trimmed
+
+	# Lots of forwarders (needed for the report). I’m sure this can be done
+	# in a better way.
+
+	@property
+	def lengths_front(self):
+		return self.front_adapter.lengths_front
+
+	@property
+	def lengths_back(self):
+		return self.back_adapter.lengths_back
+
+	@property
+	def errors_front(self):
+		return self.front_adapter.errors_front
+
+	@property
+	def errors_back(self):
+		return self.back_adapter.errors_back
+
+	@property
+	def adjacent_bases(self):
+		return self.back_adapter.adjacent_bases
diff --git a/cutadapt/filters.py b/cutadapt/filters.py
index 0407363..3ab1e04 100644
--- a/cutadapt/filters.py
+++ b/cutadapt/filters.py
@@ -209,7 +209,7 @@ class Demultiplexer(object):
 	depending on which adapter matches. Files are created when the first read
 	is written to them.
 	"""
-	def __init__(self, path_template, untrimmed_path, fileformat, colorspace):
+	def __init__(self, path_template, untrimmed_path, colorspace, qualities):
 		"""
 		path_template must contain the string '{name}', which will be replaced
 		with the name of the adapter to form the final output path.
@@ -223,8 +223,8 @@ class Demultiplexer(object):
 		self.writers = dict()
 		self.written = 0
 		self.written_bp = [0, 0]
-		self.fileformat = fileformat
 		self.colorspace = colorspace
+		self.qualities = qualities
 
 	def __call__(self, read1, read2=None):
 		if read2 is None:
@@ -232,7 +232,7 @@ class Demultiplexer(object):
 			if read1.match is None:
 				if self.untrimmed_writer is None and self.untrimmed_path is not None:
 					self.untrimmed_writer = seqio.open(self.untrimmed_path,
-						mode='w', fileformat=self.fileformat, colorspace=self.colorspace)
+						mode='w', colorspace=self.colorspace, qualities=self.qualities)
 				if self.untrimmed_writer is not None:
 					self.written += 1
 					self.written_bp[0] += len(read1)
@@ -241,7 +241,7 @@ class Demultiplexer(object):
 				name = read1.match.adapter.name
 				if name not in self.writers:
 					self.writers[name] = seqio.open(self.template.replace('{name}', name),
-						mode='w', fileformat=self.fileformat, colorspace=self.colorspace)
+						mode='w', colorspace=self.colorspace, qualities=self.qualities)
 				self.written += 1
 				self.written_bp[0] += len(read1)
 				self.writers[name].write(read1)
diff --git a/cutadapt/modifiers.py b/cutadapt/modifiers.py
index bc96b30..af4944d 100644
--- a/cutadapt/modifiers.py
+++ b/cutadapt/modifiers.py
@@ -7,7 +7,7 @@ need to be stored, and as a class with a __call__ method if there are parameters
 """
 from __future__ import print_function, division, absolute_import
 import re
-from cutadapt.qualtrim import quality_trim_index
+from cutadapt.qualtrim import quality_trim_index, nextseq_trim_index
 from cutadapt.compat import maketrans
 
 
@@ -32,12 +32,13 @@ class AdapterCutter(object):
 		self.rest_writer = rest_writer
 		self.action = action
 		self.with_adapters = 0
+		self.keep_match_info = self.info_file is not None
 
 	def _best_match(self, read):
 		"""
 		Find the best matching adapter in the given read.
 
-		Return either an Match instance or None if there are no matches.
+		Return either a Match instance or None if there are no matches.
 		"""
 		best = None
 		for adapter in self.adapters:
@@ -50,7 +51,7 @@ class AdapterCutter(object):
 				best = match
 		return best
 
-	def _write_info(self, read, matches):
+	def _write_info(self, read):
 		"""
 		Write to the info, wildcard and rest files.
 		# TODO
@@ -65,26 +66,9 @@ class AdapterCutter(object):
 			print(match.wildcards(), read.name, file=self.wildcard_file)
 
 		if self.info_file:
-			if match:
-				for m in matches:
-					seq = m.read.sequence
-					qualities = m.read.qualities
-					if qualities is None:
-						qualities = ''
-					print(
-						m.read.name,
-						m.errors,
-						m.rstart,
-						m.rstop,
-						seq[0:m.rstart],
-						seq[m.rstart:m.rstop],
-						seq[m.rstop:],
-						m.adapter.name,
-						qualities[0:m.rstart],
-						qualities[m.rstart:m.rstop],
-						qualities[m.rstop:],
-						sep='\t', file=self.info_file
-					)
+			if read.match_info:
+				for m in read.match_info:
+					print(*m, sep='\t', file=self.info_file)
 			else:
 				seq = read.sequence
 				qualities = read.qualities if read.qualities is not None else ''
@@ -112,18 +96,15 @@ class AdapterCutter(object):
 			if match is None:
 				# nothing found
 				break
-			assert match.length > 0
-			assert match.errors / match.length <= match.adapter.max_error_rate
-			assert match.length - match.errors > 0
 			matches.append(match)
 			trimmed_read = match.adapter.trimmed(match)
-
-		trimmed_read.match = matches[-1] if matches else None
-		self._write_info(trimmed_read, matches)
-
+		
 		if not matches:
+			trimmed_read.match = None
+			trimmed_read.match_info = None
+			self._write_info(trimmed_read)
 			return trimmed_read
-
+		
 		if __debug__:
 			assert len(trimmed_read) < len(read), "Trimmed read isn't shorter than original"
 
@@ -148,8 +129,12 @@ class AdapterCutter(object):
 			assert len(trimmed_read.sequence) == len(read)
 		elif self.action is None:
 			trimmed_read = read
-			trimmed_read.match = matches[-1]
-
+		
+		trimmed_read.match = matches[-1]
+		if self.keep_match_info:
+			trimmed_read.match_info = [match.get_info_record() for match in matches]
+		self._write_info(trimmed_read)
+		
 		self.with_adapters += 1
 		return trimmed_read
 
@@ -250,6 +235,18 @@ def PrimerTrimmer(read):
 	return read
 
 
+class NextseqQualityTrimmer(object):
+	def __init__(self, cutoff, base):
+		self.cutoff = cutoff
+		self.base = base
+		self.trimmed_bases = 0
+
+	def __call__(self, read):
+		stop = nextseq_trim_index(read, self.cutoff, self.base)
+		self.trimmed_bases += len(read) - stop
+		return read[:stop]
+
+
 class QualityTrimmer(object):
 	def __init__(self, cutoff_front, cutoff_back, base):
 		self.cutoff_front = cutoff_front
diff --git a/cutadapt/qualtrim.py b/cutadapt/qualtrim.py
index 37ebb47..ea79132 100644
--- a/cutadapt/qualtrim.py
+++ b/cutadapt/qualtrim.py
@@ -35,7 +35,36 @@ def quality_trim_index(qualities, cutoff, base=33):
 			max_i = i
 	return max_i
 
+
+def nextseq_trim_index(sequence, cutoff, base=33):
+	"""
+	Variant of the above quality trimming routine that works on NextSeq data.
+	With Illumina NextSeq, bases are encoded with two colors. 'No color' (a
+	dark cycle) usually means that a 'G' was sequenced, but that also occurs
+	when sequencing falls off the end of the fragment. The read then contains
+	a run of high-quality G bases in the end.
+
+	This routine works as the one above, but counts qualities belonging to 'G'
+	bases as being equal to cutoff - 1.
+	"""
+	bases = sequence.sequence
+	qualities = sequence.qualities
+	s = 0
+	max_qual = 0
+	max_i = len(qualities)
+	for i in reversed(xrange(max_i)):
+		q = ord(qualities[i]) - base
+		if bases[i] == 'G':
+			q = cutoff - 1
+		s += cutoff - q
+		if s < 0:
+			break
+		if s > max_qual:
+			max_qual = s
+			max_i = i
+	return max_i
+
 try:
-	from cutadapt._qualtrim import quality_trim_index
+	from cutadapt._qualtrim import quality_trim_index, nextseq_trim_index
 except:
 	pass
diff --git a/cutadapt/report.py b/cutadapt/report.py
index 32f8d03..35b3641 100644
--- a/cutadapt/report.py
+++ b/cutadapt/report.py
@@ -8,7 +8,7 @@ import sys
 from collections import namedtuple
 from contextlib import contextmanager
 import textwrap
-from .adapters import BACK, FRONT, PREFIX, SUFFIX, ANYWHERE
+from .adapters import BACK, FRONT, PREFIX, SUFFIX, ANYWHERE, LINKED
 from .modifiers import QualityTrimmer, AdapterCutter
 from .filters import (NoFilter, PairedNoFilter, TooShortReadFilter, TooLongReadFilter,
 	DiscardTrimmedFilter, DiscardUntrimmedFilter, Demultiplexer, NContentFilter)
@@ -85,7 +85,8 @@ ADAPTER_TYPES = {
 	FRONT: "regular 5'",
 	PREFIX: "anchored 5'",
 	SUFFIX: "anchored 3'",
-	ANYWHERE: "variable 5'/3'"
+	ANYWHERE: "variable 5'/3'",
+	LINKED: "linked",
 }
 
 
@@ -229,7 +230,7 @@ def print_report(stats, adapters_pair):
 			total_back = sum(adapter.lengths_back.values())
 			total = total_front + total_back
 			where = adapter.where
-			assert where == ANYWHERE or (where in (BACK, SUFFIX) and total_front == 0) or (where in (FRONT, PREFIX) and total_back == 0)
+			assert where in (ANYWHERE, LINKED) or (where in (BACK, SUFFIX) and total_front == 0) or (where in (FRONT, PREFIX) and total_back == 0)
 
 			if stats.paired:
 				extra = 'First read: ' if which_in_pair == 0 else 'Second read: '
@@ -238,9 +239,17 @@ def print_report(stats, adapters_pair):
 
 			print("=" * 3, extra + "Adapter", adapter.name, "=" * 3)
 			print()
-			print("Sequence: {0}; Type: {1}; Length: {2}; Trimmed: {3} times.".
-				format(adapter.sequence, ADAPTER_TYPES[adapter.where],
-					len(adapter.sequence), total))
+			if where == LINKED:
+				print("Sequence: {0}...{1}; Type: linked; Length: {2}+{3}; Trimmed: {4} times; Half matches: {5}".
+					format(adapter.front_adapter.sequence,
+						adapter.back_adapter.sequence,
+						len(adapter.front_adapter.sequence),
+						len(adapter.back_adapter.sequence),
+						total_front, total_back))
+			else:
+				print("Sequence: {0}; Type: {1}; Length: {2}; Trimmed: {3} times.".
+					format(adapter.sequence, ADAPTER_TYPES[adapter.where],
+						len(adapter.sequence), total))
 			if total == 0:
 				print()
 				continue
@@ -254,6 +263,20 @@ def print_report(stats, adapters_pair):
 				print()
 				print("Overview of removed sequences (3' or within)")
 				print_histogram(adapter.lengths_back, len(adapter), stats.n, adapter.max_error_rate, adapter.errors_back)
+			elif where == LINKED:
+				print()
+				print_error_ranges(len(adapter.front_adapter), adapter.front_adapter.max_error_rate)
+				print_error_ranges(len(adapter.back_adapter), adapter.back_adapter.max_error_rate)
+				print("Overview of removed sequences at 5' end")
+				print_histogram(adapter.front_adapter.lengths_front,
+					len(adapter.front_adapter), stats.n,
+					adapter.front_adapter.max_error_rate,
+					adapter.front_adapter.errors_front)
+				print()
+				print("Overview of removed sequences at 3' end")
+				print_histogram(adapter.back_adapter.lengths_back,
+					len(adapter.back_adapter), stats.n,
+					adapter.back_adapter.max_error_rate, adapter.back_adapter.errors_back)
 			elif where in (FRONT, PREFIX):
 				print()
 				print_error_ranges(len(adapter), adapter.max_error_rate)
diff --git a/cutadapt/scripts/cutadapt.py b/cutadapt/scripts/cutadapt.py
index bfc3c57..7a7b0af 100755
--- a/cutadapt/scripts/cutadapt.py
+++ b/cutadapt/scripts/cutadapt.py
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 # kate: word-wrap off; remove-trailing-spaces all;
 #
-# Copyright (c) 2010-2015 Marcel Martin <marcel.martin at scilifelab.se>
+# Copyright (c) 2010-2016 Marcel Martin <marcel.martin at scilifelab.se>
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,7 @@
 
 """
 cutadapt version %version
-Copyright (C) 2010-2015 Marcel Martin <marcel.martin at scilifelab.se>
+Copyright (C) 2010-2016 Marcel Martin <marcel.martin at scilifelab.se>
 
 cutadapt removes adapter sequences from high-throughput sequencing reads.
 
@@ -72,18 +72,17 @@ import textwrap
 
 from cutadapt import seqio, __version__
 from cutadapt.xopen import xopen
-from cutadapt.adapters import (Adapter, ColorspaceAdapter, gather_adapters,
-	BACK, FRONT, PREFIX, SUFFIX, ANYWHERE)
+from cutadapt.adapters import AdapterParser
 from cutadapt.modifiers import (LengthTagModifier, SuffixRemover, PrefixSuffixAdder,
 	DoubleEncoder, ZeroCapper, PrimerTrimmer, QualityTrimmer, UnconditionalCutter,
-	NEndTrimmer, AdapterCutter)
+	NEndTrimmer, AdapterCutter, NextseqQualityTrimmer)
 from cutadapt.filters import (NoFilter, PairedNoFilter, Redirector, PairedRedirector,
 	LegacyPairedRedirector, TooShortReadFilter, TooLongReadFilter,
 	Demultiplexer, NContentFilter, DiscardUntrimmedFilter, DiscardTrimmedFilter)
 from cutadapt.report import Statistics, print_report, redirect_standard_output
 from cutadapt.compat import next
 
-logger = logging.getLogger(__name__)
+logger = logging.getLogger()
 
 class CutadaptOptionParser(OptionParser):
 	def get_usage(self):
@@ -146,6 +145,19 @@ def process_paired_reads(paired_reader, modifiers1, modifiers2, filters):
 	return Statistics(n=n, total_bp1=total1_bp, total_bp2=total2_bp)
 
 
+def setup_logging(stdout=False, quiet=False):
+	"""
+	Attach handler to the global logger object
+	"""
+	# Due to backwards compatibility, logging output is sent to standard output
+	# instead of standard error if the -o option is used.
+	stream_handler = logging.StreamHandler(sys.stdout if stdout else sys.stderr)
+	stream_handler.setFormatter(logging.Formatter('%(message)s'))
+	stream_handler.setLevel(logging.ERROR if quiet else logging.INFO)
+	logger.setLevel(logging.INFO)
+	logger.addHandler(stream_handler)
+
+
 def get_option_parser():
 	parser = CutadaptOptionParser(usage=__doc__, version=__version__)
 
@@ -153,54 +165,50 @@ def get_option_parser():
 		help="Print debugging information.")
 	parser.add_option("-f", "--format",
 		help="Input file format; can be either 'fasta', 'fastq' or 'sra-fastq'. "
-			"Ignored when reading csfasta/qual files (default: auto-detect "
-			"from file name extension).")
-
-	group = OptionGroup(parser, "Options that influence how the adapters are found",
-		description="Each of the three parameters -a, -b, -g can be used "
-			"multiple times and in any combination to search for an entire set of "
-			"adapters of possibly different types. Only the best matching "
-			"adapter is trimmed from each read (but see the --times option). "
-			"Instead of giving an adapter directly, you can also write "
-			"file:FILE and the adapter sequences will be read from the given "
-			"FASTA FILE.")
+			"Ignored when reading csfasta/qual files. Default: auto-detect "
+			"from file name extension.")
+
+	group = OptionGroup(parser, "Finding adapters:",
+		description="Parameters -a, -g, -b specify adapters to be removed from "
+			"each read (or from the first read in a pair if data is paired). "
+			"If specified multiple times, only the best matching adapter is "
+			"trimmed (but see the --times option). When the special notation "
+			"'file:FILE' is used, adapter sequences are read from the given "
+			"FASTA file.")
 	group.add_option("-a", "--adapter", action="append", default=[], metavar="ADAPTER",
 		dest="adapters",
-		help="Sequence of an adapter that was ligated to the 3' end. The "
-			"adapter itself and anything that follows is trimmed. If the "
-			"adapter sequence ends with the '$' character, the adapter is "
-			"anchored to the end of the read and only found if it is a "
-			"suffix of the read.")
+		help="Sequence of an adapter ligated to the 3' end (paired data: of the "
+			"first read). The adapter and subsequent bases are trimmed. If a "
+			"'$' character is appended ('anchoring'), the adapter is only "
+			"found if it is a suffix of the read.")
 	group.add_option("-g", "--front", action="append", default=[], metavar="ADAPTER",
-		help="Sequence of an adapter that was ligated to the 5' end. If the "
-		"adapter sequence starts with the character '^', the adapter is "
-		"'anchored'. An anchored adapter must appear in its entirety at the "
-		"5' end of the read (it is a prefix of the read). A non-anchored adapter may "
-		"appear partially at the 5' end, or it may occur within the read. If it is "
-		"found within a read, the sequence preceding the adapter is also trimmed. "
-		"In all cases, the adapter itself is trimmed.")
+		help="Sequence of an adapter ligated to the 5' end (paired data: of the "
+			"first read). The adapter and any preceding bases are trimmed. "
+			"Partial matches at the 5' end are allowed. If a '^' character is "
+			"prepended ('anchoring'), the adapter is only found if it is a "
+			"prefix of the read.")
 	group.add_option("-b", "--anywhere", action="append", default=[], metavar="ADAPTER",
-		help="Sequence of an adapter that was ligated to the 5' or 3' end. If "
-			"the adapter is found within the read or overlapping the 3' end of "
-			"the read, the behavior is the same as for the -a option. If the "
-			"adapter overlaps the 5' end (beginning of the read), the initial "
-			"portion of the read matching the adapter is trimmed, but anything "
-			"that follows is kept.")
+		help="Sequence of an adapter that may be ligated to the 5' or 3' end "
+			"(paired data: of the first read). Both types of matches as "
+			"described under -a und -g are allowed. If the first base of the "
+			"read is part of the match, the behavior is as with -g, otherwise "
+			"as with -a. This option is mostly for rescuing failed library "
+			"preparations - do not use if you know which end your adapter was "
+			"ligated to!")
 	group.add_option("-e", "--error-rate", type=float, default=0.1,
 		help="Maximum allowed error rate (no. of errors divided by the length "
-			"of the matching region) (default: %default)")
+			"of the matching region). Default: %default")
 	group.add_option("--no-indels", action='store_false', dest='indels', default=True,
-		help="Do not allow indels in the alignments (allow only mismatches). "
-			"(default: allow both mismatches and indels)")
+		help="Allow only mismatches in alignments. "
+			"Default: allow both mismatches and indels")
 	group.add_option("-n", "--times", type=int, metavar="COUNT", default=1,
-		help="Remove up to COUNT adapters from each read (default: %default)")
-	group.add_option("-O", "--overlap", type=int, metavar="LENGTH", default=3,
-		help="Minimum overlap length. If the overlap between the read and the "
-			"adapter is shorter than LENGTH, the read is not modified. "
-			"This reduces the no. of bases trimmed purely due to short random "
-			"adapter matches (default: %default).")
+		help="Remove up to COUNT adapters from each read. Default: %default")
+	group.add_option("-O", "--overlap", type=int, metavar="MINLENGTH", default=3,
+		help="If the overlap between the read and the adapter is shorter than "
+			"MINLENGTH, the read is not modified. Reduces the no. of bases "
+			"trimmed due to random adapter matches. Default: %default")
 	group.add_option("--match-read-wildcards", action="store_true", default=False,
-		help="Allow IUPAC wildcards in reads (default: %default).")
+		help="Interpret IUPAC wildcards in reads. Default: %default")
 	group.add_option("-N", "--no-match-adapter-wildcards", action="store_false",
 		default=True, dest='match_adapter_wildcards',
 		help="Do not interpret IUPAC wildcards in adapters.")
@@ -213,16 +221,19 @@ def get_option_parser():
 
 	group = OptionGroup(parser, "Additional read modifications")
 	group.add_option("-u", "--cut", action='append', default=[], type=int, metavar="LENGTH",
-		help="Remove LENGTH bases from the beginning or end of each read. "
-			"If LENGTH is positive, bases are removed from the beginning of each read. "
-			"If LENGTH is negative, bases are removed from the end of each read. "
-			"This option can be specified twice if the LENGTHs have different signs.")
+		help="Remove bases from each read (first read only if paired). "
+			"If LENGTH is positive, remove bases from the beginning. "
+			"If LENGTH is negative, remove bases from the end. "
+			"Can be used twice if LENGTHs have different signs.")
 	group.add_option("-q", "--quality-cutoff", default=None, metavar="[5'CUTOFF,]3'CUTOFF",
-		help="Trim low-quality bases from 5' and/or 3' ends of reads before "
-			"adapter removal. If one value is given, only the 3' end is trimmed. "
-			"If two comma-separated cutoffs are given, the 5' end is trimmed with "
-			"the first cutoff, the 3' end with the second. See documentation for "
-			"the algorithm. (default: no trimming)")
+		help="Trim low-quality bases from 5' and/or 3' ends of each read before "
+			"adapter removal. Applied to both reads if data is paired. If one "
+			"value is given, only the 3' end is trimmed. If two "
+			"comma-separated cutoffs are given, the 5' end is trimmed with "
+			"the first cutoff, the 3' end with the second.")
+	group.add_option("--nextseq-trim", type=int, default=None, metavar="3'CUTOFF",
+		help="NextSeq-specific quality trimming (each read). Trims also dark "
+			"cycles appearing as high-quality G bases (EXPERIMENTAL).")
 	group.add_option("--quality-base", type=int, default=33,
 		help="Assume that quality values in FASTQ are encoded as ascii(quality "
 			"+ QUALITY_BASE). This needs to be set to 64 for some old Illumina "
@@ -242,7 +253,7 @@ def get_option_parser():
 			"to correct fields like 'length=123'.")
 	parser.add_option_group(group)
 
-	group = OptionGroup(parser, "Options for filtering of processed reads")
+	group = OptionGroup(parser, "Filtering of processed reads")
 	group.add_option("--discard-trimmed", "--discard", action='store_true', default=False,
 		help="Discard reads that contain an adapter. Also use -O to avoid "
 			"discarding too many randomly matching reads!")
@@ -251,26 +262,26 @@ def get_option_parser():
 	group.add_option("-m", "--minimum-length", type=int, default=0, metavar="LENGTH",
 		help="Discard trimmed reads that are shorter than LENGTH. Reads that "
 			"are too short even before adapter removal are also discarded. In "
-			"colorspace, an initial primer is not counted (default: 0).")
+			"colorspace, an initial primer is not counted. Default: 0")
 	group.add_option("-M", "--maximum-length", type=int, default=sys.maxsize, metavar="LENGTH",
 		help="Discard trimmed reads that are longer than LENGTH. "
 			"Reads that are too long even before adapter removal "
 			"are also discarded. In colorspace, an initial primer "
-			"is not counted (default: no limit).")
+			"is not counted. Default: no limit")
 	group.add_option("--max-n", type=float, default=-1.0, metavar="COUNT",
 		help="Discard reads with too many N bases. If COUNT is an integer, it "
 			"is treated as the absolute number of N bases. If it is between 0 "
 			"and 1, it is treated as the proportion of N's allowed in a read.")
 	parser.add_option_group(group)
 
-	group = OptionGroup(parser, "Options that influence what gets output to where")
+	group = OptionGroup(parser, "Output")
 	group.add_option("--quiet", default=False, action='store_true',
-		help="Do not print a report at the end.")
+		help="Print only error messages.")
 	group.add_option("-o", "--output", metavar="FILE",
-		help="Write modified reads to FILE. FASTQ or FASTA format is chosen "
+		help="Write trimmed reads to FILE. FASTQ or FASTA format is chosen "
 			"depending on input. The summary report is sent to standard output. "
 			"Use '{name}' in FILE to demultiplex reads into multiple "
-			"files. (default: trimmed reads are written to standard output)")
+			"files. Default: write to standard output")
 	group.add_option("--info-file", metavar="FILE",
 		help="Write information about each read and its adapter matches into FILE. "
 			"See the documentation for the file format.")
@@ -283,13 +294,13 @@ def get_option_parser():
 			"alignment, this will often not be accurate.")
 	group.add_option("--too-short-output", metavar="FILE",
 		help="Write reads that are too short (according to length specified by "
-		"-m) to FILE. (default: discard reads)")
+		"-m) to FILE. Default: discard reads")
 	group.add_option("--too-long-output", metavar="FILE",
 		help="Write reads that are too long (according to length specified by "
-		"-M) to FILE. (default: discard reads)")
+		"-M) to FILE. Default: discard reads")
 	group.add_option("--untrimmed-output", default=None, metavar="FILE",
-		help="Write reads that do not contain the adapter to FILE. (default: "
-			"output to same file as trimmed reads)")
+		help="Write reads that do not contain the adapter to FILE. Default: "
+			"output to same file as trimmed reads")
 	parser.add_option_group(group)
 
 	group = OptionGroup(parser, "Colorspace options")
@@ -307,8 +318,8 @@ def get_option_parser():
 			"-t, --strip-f3 and -y '/1'.")
 	group.add_option("--no-zero-cap", dest='zero_cap', action='store_false',
 		help="Do not change negative quality values to zero in colorspace "
-			"data. By default, they are changed to zero since many tools have "
-			"problems with negative qualities.")
+			"data. By default, they are since many tools have problems with "
+			"negative qualities.")
 	group.add_option("--zero-cap", "-z", action='store_true',
 		help="Change negative quality values to zero. This is enabled "
 		"by default when -c/--colorspace is also enabled. Use the above option "
@@ -317,7 +328,8 @@ def get_option_parser():
 	parser.add_option_group(group)
 
 	group = OptionGroup(parser, "Paired-end options", description="The "
-		"-A/-G/-B/-U options work like their -a/-b/-g/-u counterparts.")
+		"-A/-G/-B/-U options work like their -a/-b/-g/-u counterparts, but "
+		"are applied to the second read in each pair.")
 	group.add_option("-A", dest='adapters2', action='append', default=[], metavar='ADAPTER',
 		help="3' adapter to be removed from second read in a pair.")
 	group.add_option("-G", dest='front2', action='append', default=[], metavar='ADAPTER',
@@ -325,7 +337,7 @@ def get_option_parser():
 	group.add_option("-B", dest='anywhere2', action='append', default=[], metavar='ADAPTER',
 		help="5'/3 adapter to be removed from second read in a pair.")
 	group.add_option("-U", dest='cut2', action='append', default=[], type=int, metavar="LENGTH",
-		help="Remove LENGTH bases from the beginning or end of each second read (see --cut).")
+		help="Remove LENGTH bases from second read in a pair (see --cut).")
 	group.add_option("-p", "--paired-output", metavar="FILE",
 		help="Write second read in a pair to FILE.")
 	# Setting the default for pair_filter to None allows us to find out whether
@@ -334,14 +346,14 @@ def get_option_parser():
 		choices=("any", "both"),
 		help="Which of the reads in a paired-end read have to match the "
 			"filtering criterion in order for it to be filtered. "
-			"Default: any.")
+			"Default: any")
 	group.add_option("--interleaved", action='store_true', default=False,
 		help="Read and write interleaved paired-end reads.")
 	group.add_option("--untrimmed-paired-output", metavar="FILE",
 		help="Write second read in a pair to this FILE when no adapter "
 			"was found in the first read. Use this option together with "
-			"--untrimmed-output when trimming paired-end reads. (Default: output "
-			"to same file as trimmed reads.)")
+			"--untrimmed-output when trimming paired-end reads. Default: output "
+			"to same file as trimmed reads")
 	group.add_option("--too-short-paired-output", metavar="FILE", default=None,
 		help="Write second read in a pair to this file if pair is too short. "
 			"Use together with --too-short-output.")
@@ -361,11 +373,14 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 	default_outfile is the file to which trimmed reads are sent if the ``-o``
 	parameter is not used.
 	"""
-	logging.basicConfig(level=logging.INFO, format='%(message)s')  #  %(levelname)s
 	parser = get_option_parser()
 	if cmdlineargs is None:
 		cmdlineargs = sys.argv[1:]
 	options, args = parser.parse_args(args=cmdlineargs)
+	# Setup logging only if there are not already any handlers (can happen when
+	# this function is being called externally such as from unit tests)
+	if not logging.root.handlers:
+		setup_logging(stdout=bool(options.output), quiet=options.quiet)
 
 	if len(args) == 0:
 		parser.error("At least one parameter needed: name of a FASTA or FASTQ file.")
@@ -438,7 +453,6 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 				fileformat=options.format, interleaved=options.interleaved)
 	except (seqio.UnknownFileType, IOError) as e:
 		parser.error(e)
-	fileformat = 'fastq' if reader.delivers_qualities else 'fasta'
 
 	if options.quality_cutoff is not None:
 		cutoffs = options.quality_cutoff.split(',')
@@ -457,8 +471,9 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 	else:
 		cutoffs = None
 
-	open_writer = functools.partial(seqio.open, mode='w', fileformat=fileformat,
-		colorspace=options.colorspace, interleaved=options.interleaved)
+	open_writer = functools.partial(seqio.open, mode='w',
+		qualities=reader.delivers_qualities, colorspace=options.colorspace,
+		interleaved=options.interleaved)
 
 	if options.pair_filter is None:
 		options.pair_filter = 'any'
@@ -503,7 +518,7 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 		if options.discard_untrimmed:
 			untrimmed = None
 		demultiplexer = Demultiplexer(options.output, untrimmed,
-			fileformat=fileformat, colorspace=options.colorspace)
+			qualities=reader.delivers_qualities, colorspace=options.colorspace)
 		filters.append(demultiplexer)
 	else:
 		# Set up the remaining filters to deal with --discard-trimmed,
@@ -563,35 +578,34 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 			parser.error('IUPAC wildcards not supported in colorspace')
 		options.match_adapter_wildcards = False
 
-	ADAPTER_CLASS = ColorspaceAdapter if options.colorspace else Adapter
+	adapter_parser = AdapterParser(
+		colorspace=options.colorspace,
+		max_error_rate=options.error_rate,
+		min_overlap=options.overlap,
+		read_wildcards=options.match_read_wildcards,
+		adapter_wildcards=options.match_adapter_wildcards,
+		indels=options.indels)
+
 	try:
-		# TODO refactor this a bit
-		def collect(back, anywhere, front):
-			adapters = []
-			for name, seq, where in gather_adapters(back, anywhere, front):
-				if not seq:
-					parser.error("The adapter sequence is empty.")
-				adapter = ADAPTER_CLASS(seq, where, options.error_rate,
-					options.overlap, options.match_read_wildcards,
-					options.match_adapter_wildcards, name=name, indels=options.indels)
-				if options.debug:
-					adapter.enable_debug()
-				adapters.append(adapter)
-			return adapters
-
-		adapters = collect(options.adapters, options.anywhere, options.front)
-		adapters2 = collect(options.adapters2, options.anywhere2, options.front2)
+		adapters = adapter_parser.parse_multi(options.adapters, options.anywhere, options.front)
+		adapters2 = adapter_parser.parse_multi(options.adapters2, options.anywhere2, options.front2)
 	except IOError as e:
 		if e.errno == errno.ENOENT:
 			parser.error(e)
 		raise
+	except ValueError as e:
+		parser.error(e)
+	if options.debug:
+		for adapter in adapters + adapters2:
+			adapter.enable_debug()
 
 	if not adapters and not adapters2 and not cutoffs and \
+			options.nextseq_trim is None and \
 			options.cut == [] and options.cut2 == [] and \
 			options.minimum_length == 0 and \
 			options.maximum_length == sys.maxsize and \
 			quality_filename is None and \
-			options.max_n == -1:
+			options.max_n == -1 and not options.trim_n:
 		parser.error("You need to provide at least one adapter sequence.")
 
 	# Create the single-end processing pipeline (a list of "modifiers")
@@ -605,6 +619,9 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 			if cut != 0:
 				modifiers.append(UnconditionalCutter(cut))
 
+	if options.nextseq_trim is not None:
+		modifiers.append(NextseqQualityTrimmer(options.nextseq_trim, options.quality_base))
+
 	if cutoffs:
 		modifiers.append(QualityTrimmer(cutoffs[0], cutoffs[1], options.quality_base))
 	if adapters:
@@ -657,11 +674,6 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 			adapter_cutter2 = None
 		modifiers2.extend(modifiers_both)
 
-	# Due to backwards compatibility, from here on logging output needs to be
-	# sent to standard output instead of standard error if the -o option is used.
-	if options.output:
-		logger.root.handlers = []
-		logging.basicConfig(level=logging.INFO, format='%(message)s', stream=sys.stdout)
 	logger.info("This is cutadapt %s with Python %s", __version__, platform.python_version())
 	logger.info("Command line parameters: %s", " ".join(cmdlineargs))
 	logger.info("Trimming %s adapter%s with at most %.1f%% errors in %s mode ...",
@@ -670,7 +682,7 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 		{ False: 'single-end', 'first': 'paired-end legacy', 'both': 'paired-end' }[paired])
 
 	if paired == 'first' and (modifiers_both or cutoffs):
-		logger.warn('\n'.join(textwrap.wrap('WARNING: Requested read '
+		logger.warning('\n'.join(textwrap.wrap('WARNING: Requested read '
 			'modifications are applied only to the first '
 			'read since backwards compatibility mode is enabled. '
 			'To modify both reads, also use any of the -A/-B/-G/-U options. '
diff --git a/cutadapt/seqio.py b/cutadapt/seqio.py
index e8ebd33..28d6722 100644
--- a/cutadapt/seqio.py
+++ b/cutadapt/seqio.py
@@ -10,8 +10,8 @@ TODO
 from __future__ import print_function, division, absolute_import
 import sys
 from os.path import splitext
-from cutadapt.xopen import xopen
-from cutadapt.compat import zip, basestring
+from .xopen import xopen
+from .compat import zip, basestring
 
 __author__ = "Marcel Martin"
 
@@ -34,33 +34,37 @@ def _shorten(s, n=100):
 class Sequence(object):
 	"""qualities is a string and it contains the qualities encoded as ascii(qual+33)."""
 
-	def __init__(self, name, sequence, qualities=None, name2='', match=None):
+	def __init__(self, name, sequence, qualities=None, name2='', match=None, match_info=None):
 		"""Set qualities to None if there are no quality values"""
 		self.name = name
 		self.sequence = sequence
 		self.qualities = qualities
 		self.name2 = name2
 		self.match = match
+		self.match_info = match_info
+		self.original_length = len(sequence)
 		if qualities is not None:
 			if len(qualities) != len(sequence):
 				rname = _shorten(name)
-				raise FormatError("In read named {0!r}: Length of quality sequence ({1}) and length of read ({2}) do not match".format(
-					rname, len(qualities), len(sequence)))
-
+				raise FormatError("In read named {0!r}: Length of quality sequence ({1}) and "
+					"length of read ({2}) do not match".format(rname, len(qualities), len(sequence)))
+	
 	def __getitem__(self, key):
 		"""slicing"""
 		return self.__class__(
 			self.name,
 			self.sequence[key],
 			self.qualities[key] if self.qualities is not None else None,
-		    self.name2,
-		    self.match)
+			self.name2,
+			self.match,
+			self.match_info)
 
 	def __repr__(self):
 		qstr = ''
 		if self.qualities is not None:
 			qstr = ', qualities={0!r}'.format(_shorten(self.qualities))
-		return '<Sequence(name={0!r}, sequence={1!r}{2})>'.format(_shorten(self.name), _shorten(self.sequence), qstr)
+		return '<Sequence(name={0!r}, sequence={1!r}{2})>'.format(
+			_shorten(self.name), _shorten(self.sequence), qstr)
 
 	def __len__(self):
 		return len(self.sequence)
@@ -74,6 +78,34 @@ class Sequence(object):
 		return not self.__eq__(other)
 
 
+class SequenceReader(object):
+	"""Read possibly compressed files containing sequences"""
+	_close_on_exit = False
+
+	def __init__(self, file):
+		"""
+		file is a path or a file-like object. In both cases, the file may
+		be compressed (.gz, .bz2, .xz).
+		"""
+		if isinstance(file, basestring):
+			file = xopen(file)
+			self._close_on_exit = True
+		self._file = file
+
+	def close(self):
+		if self._close_on_exit and self._file is not None:
+			self._file.close()
+			self._file = None
+
+	def __enter__(self):
+		if self._file is None:
+			raise ValueError("I/O operation on closed SequenceReader")
+		return self
+
+	def __exit__(self, *args):
+		self.close()
+
+
 try:
 	from ._seqio import Sequence
 except ImportError:
@@ -81,7 +113,7 @@ except ImportError:
 
 
 class ColorspaceSequence(Sequence):
-	def __init__(self, name, sequence, qualities, primer=None, name2='', match=None):
+	def __init__(self, name, sequence, qualities, primer=None, name2='', match=None, match_info=None):
 		# In colorspace, the first character is the last nucleotide of the primer base
 		# and the second character encodes the transition from the primer base to the
 		# first real base of the read.
@@ -95,7 +127,7 @@ class ColorspaceSequence(Sequence):
 			raise FormatError("In read named {0!r}: length of colorspace quality "
 				"sequence ({1}) and length of read ({2}) do not match (primer "
 				"is: {3!r})".format(rname, len(qualities), len(sequence), self.primer))
-		super(ColorspaceSequence, self).__init__(name, sequence, qualities, name2, match)
+		super(ColorspaceSequence, self).__init__(name, sequence, qualities, name2, match, match_info)
 		if not self.primer in ('A', 'C', 'G', 'T'):
 			raise FormatError("Primer base is {0!r} in read {1!r}, but it "
 				"should be one of A, C, G, T.".format(
@@ -105,7 +137,8 @@ class ColorspaceSequence(Sequence):
 		qstr = ''
 		if self.qualities is not None:
 			qstr = ', qualities={0!r}'.format(_shorten(self.qualities))
-		return '<ColorspaceSequence(name={0!r}, primer={1!r}, sequence={2!r}{3})>'.format(_shorten(self.name), self.primer, _shorten(self.sequence), qstr)
+		return '<ColorspaceSequence(name={0!r}, primer={1!r}, sequence={2!r}{3})>'.format(
+			_shorten(self.name), self.primer, _shorten(self.sequence), qstr)
 
 	def __getitem__(self, key):
 		return self.__class__(
@@ -114,7 +147,8 @@ class ColorspaceSequence(Sequence):
 			self.qualities[key] if self.qualities is not None else None,
 			self.primer,
 			self.name2,
-			self.match)
+			self.match,
+			self.match_info)
 
 
 def sra_colorspace_sequence(name, sequence, qualities, name2):
@@ -152,23 +186,18 @@ class FileWithPrependedLine(object):
 		self._file.close()
 
 
-class FastaReader(object):
+class FastaReader(SequenceReader):
 	"""
 	Reader for FASTA files.
 	"""
-	_close_on_exit = False
-
 	def __init__(self, file, keep_linebreaks=False, sequence_class=Sequence):
 		"""
-		file is a filename or a file-like object.
-		If file is a filename, then it is passed to xopen().
+		file is a path or a file-like object. In both cases, the file may
+		be compressed (.gz, .bz2, .xz).
 
 		keep_linebreaks -- whether to keep newline characters in the sequence
 		"""
-		if isinstance(file, basestring):
-			file = xopen(file)
-			self._close_on_exit = True
-		self._file = file
+		super(FastaReader, self).__init__(file)
 		self.sequence_class = sequence_class
 		self.delivers_qualities = False
 		self._delimiter = '\n' if keep_linebreaks else ''
@@ -200,43 +229,24 @@ class FastaReader(object):
 		if name is not None:
 			yield self.sequence_class(name, self._delimiter.join(seq), None)
 
-	def close(self):
-		if self._close_on_exit and self._file is not None:
-			self._file.close()
-			self._file = None
-
-	def __enter__(self):
-		if self._file is None:
-			raise ValueError("I/O operation on closed FastaReader")
-		return self
-
-	def __exit__(self, *args):
-		self.close()
-
 
 class ColorspaceFastaReader(FastaReader):
 	def __init__(self, file, keep_linebreaks=False):
 		super(ColorspaceFastaReader, self).__init__(file, keep_linebreaks, sequence_class=ColorspaceSequence)
 
 
-class FastqReader(object):
+class FastqReader(SequenceReader):
 	"""
 	Reader for FASTQ files. Does not support multi-line FASTQ files.
 	"""
-	_close_on_exit = False
-
 	def __init__(self, file, sequence_class=Sequence): # TODO could be a class attribute
 		"""
-		file is a filename or a file-like object.
-		If file is a filename, then .gz files are supported.
+		file is a path or a file-like object. compressed files are supported.
 
 		The sequence_class should be a class such as Sequence or
 		ColorspaceSequence.
 		"""
-		if isinstance(file, basestring):
-			file = xopen(file)
-			self._close_on_exit = True
-		self._file = file
+		super(FastqReader, self).__init__(file)
 		self.sequence_class = sequence_class
 		self.delivers_qualities = True
 
@@ -245,17 +255,20 @@ class FastqReader(object):
 		Return tuples: (name, sequence, qualities).
 		qualities is a string and it contains the unmodified, encoded qualities.
 		"""
+		i = 3
 		for i, line in enumerate(self._file):
 			if i % 4 == 0:
 				if not line.startswith('@'):
-					raise FormatError("Line {0} in FASTQ file is expected to start with '@', but found {1!r}".format(i+1, line[:10]))
+					raise FormatError("Line {0} in FASTQ file is expected to start with '@', "
+						"but found {1!r}".format(i+1, line[:10]))
 				name = line.strip()[1:]
 			elif i % 4 == 1:
 				sequence = line.strip()
 			elif i % 4 == 2:
 				line = line.strip()
 				if not line.startswith('+'):
-					raise FormatError("Line {0} in FASTQ file is expected to start with '+', but found {1!r}".format(i+1, line[:10]))
+					raise FormatError("Line {0} in FASTQ file is expected to start with '+', "
+						"but found {1!r}".format(i+1, line[:10]))
 				if len(line) > 1:
 					if line[1:] != name:
 						raise FormatError(
@@ -270,23 +283,12 @@ class FastqReader(object):
 			elif i % 4 == 3:
 				qualities = line.rstrip('\n\r')
 				yield self.sequence_class(name, sequence, qualities, name2=name2)
-
-	def close(self):
-		if self._close_on_exit and self._file is not None:
-			self._file.close()
-			self._file = None
-
-	def __enter__(self):
-		if self._file is None:
-			raise ValueError("I/O operation on closed FastqReader")
-		return self
-
-	def __exit__(self, *args):
-		self.close()
+		if i % 4 != 3:
+			raise FormatError("FASTQ file ended prematurely")
 
 
 try:
-	from ._seqio import FastqReader, FormatError
+	from ._seqio import FastqReader
 except ImportError:
 	pass
 
@@ -329,11 +331,13 @@ class FastaQualReader(object):
 			conv[str(i)] = chr(i + 33)
 		for fastaread, qualread in zip(self.fastareader, self.qualreader):
 			if fastaread.name != qualread.name:
-				raise FormatError("The read names in the FASTA and QUAL file do not match ({0!r} != {1!r})".format(fastaread.name, qualread.name))
+				raise FormatError("The read names in the FASTA and QUAL file "
+					"do not match ({0!r} != {1!r})".format(fastaread.name, qualread.name))
 			try:
 				qualities = ''.join([conv[value] for value in qualread.sequence.split()])
 			except KeyError as e:
-				raise FormatError("Within read named {0!r}: Found invalid quality value {1}".format(fastaread.name, e))
+				raise FormatError("Within read named {0!r}: Found invalid quality "
+					"value {1}".format(fastaread.name, e))
 			assert fastaread.name == qualread.name
 			yield self.sequence_class(fastaread.name, fastaread.sequence, qualities)
 
@@ -355,15 +359,16 @@ class ColorspaceFastaQualReader(FastaQualReader):
 
 def sequence_names_match(r1, r2):
 	"""
-	Check whether the sequences r1 and r2 have identical names (ignoring /1 and
-	/2 suffixes).
+	Check whether the sequences r1 and r2 have identical names, ignoring a
+	suffix of '1' or '2'. Some old paired-end reads have names that end in '/1'
+	and '/2'. Also, the fastq-dump tool (used for converting SRA files to FASTQ)
+	appends a .1 and .2 to paired-end reads if option -I is used.
 	"""
 	name1 = r1.name.split(None, 1)[0]
 	name2 = r2.name.split(None, 1)[0]
-	if name1[-2:-1] == '/':
-		name1 = name1[:-2]
-	if name2[-2:-1] == '/':
-		name2 = name2[:-2]
+	if name1[-1:] in '12' and name2[-1:] in '12':
+		name1 = name1[:-1]
+		name2 = name2[:-1]
 	return name1 == name2
 
 
@@ -392,14 +397,16 @@ class PairedSequenceReader(object):
 				# End of file 1. Make sure that file 2 is also at end.
 				try:
 					next(it2)
-					raise FormatError("Reads are improperly paired. There are more reads in file 2 than in file 1.")
+					raise FormatError("Reads are improperly paired. There are more reads in "
+						"file 2 than in file 1.")
 				except StopIteration:
 					pass
 				break
 			try:
 				r2 = next(it2)
 			except StopIteration:
-				raise FormatError("Reads are improperly paired. There are more reads in file 1 than in file 2.")
+				raise FormatError("Reads are improperly paired. There are more reads in "
+					"file 1 than in file 2.")
 			if not sequence_names_match(r1, r2):
 				raise FormatError("Reads are improperly paired. Read name '{0}' "
 					"in file 1 does not match '{1}' in file 2.".format(r1.name, r2.name))
@@ -446,24 +453,45 @@ class InterleavedSequenceReader(object):
 	def __exit__(self, *args):
 		self.close()
 
+class FileWriter(object):
+	def __init__(self, file):
+		if isinstance(file, str):
+			self._file = xopen(file, 'w')
+			self._close_on_exit = True
+		else:
+			self._file = file
+			self._close_on_exit = False
+	
+	def close(self):
+		if self._close_on_exit:
+			self._file.close()
+	
+	def __enter__(self):
+		if self._file.closed:
+			raise ValueError("I/O operation on closed file")
+		return self
+
+	def __exit__(self, *args):
+		self.close()
+
+class SingleRecordWriter(object):
+	"""Public interface to single-record files"""
+	def write(self, record):
+		raise NotImplementedError()
 
-class FastaWriter(object):
+class FastaWriter(FileWriter, SingleRecordWriter):
 	"""
 	Write FASTA-formatted sequences to a file.
 	"""
-	_close_on_exit = False
 
 	def __init__(self, file, line_length=None):
 		"""
 		If line_length is not None, the lines will
 		be wrapped after line_length characters.
 		"""
+		FileWriter.__init__(self, file)
 		self.line_length = line_length if line_length != 0 else None
-		if isinstance(file, str):
-			file = xopen(file, 'w')
-			self._close_on_exit = True
-		self._file = file
-
+	
 	def write(self, name_or_seq, sequence=None):
 		"""Write an entry to the the FASTA file.
 
@@ -482,6 +510,7 @@ class FastaWriter(object):
 			sequence = name_or_seq.sequence
 		else:
 			name = name_or_seq
+		
 		if self.line_length is not None:
 			print('>{0}'.format(name), file=self._file)
 			for i in range(0, len(sequence), self.line_length):
@@ -491,27 +520,13 @@ class FastaWriter(object):
 		else:
 			print('>{0}'.format(name), sequence, file=self._file, sep='\n')
 
-	def close(self):
-		if self._close_on_exit:
-			self._file.close()
-
-	def __enter__(self):
-		if self._file.closed:
-			raise ValueError("I/O operation on closed file")
-		return self
-
-	def __exit__(self, *args):
-		self.close()
-
-
 class ColorspaceFastaWriter(FastaWriter):
 	def write(self, record):
 		name = record.name
 		sequence = record.primer + record.sequence
 		super(ColorspaceFastaWriter, self).write(name, sequence)
 
-
-class FastqWriter(object):
+class FastqWriter(FileWriter, SingleRecordWriter):
 	"""
 	Write sequences with qualities in FASTQ format.
 
@@ -521,14 +536,6 @@ class FastqWriter(object):
 	+
 	QUALITIS
 	"""
-	_close_on_exit = False
-
-	def __init__(self, file):
-		if isinstance(file, str):
-			file = xopen(file, "w")
-			self._close_on_exit = True
-		self._file = file
-
 	def write(self, record):
 		"""
 		Write a Sequence record to the the FASTQ file.
@@ -543,19 +550,6 @@ class FastqWriter(object):
 		print("@{0:s}\n{1:s}\n+\n{2:s}".format(
 			name, sequence, qualities), file=self._file)
 
-	def close(self):
-		if self._close_on_exit:
-			self._file.close()
-
-	def __enter__(self):
-		if self._file.closed:
-			raise ValueError("I/O operation on closed file")
-		return self
-
-	def __exit__(self, *args):
-		self.close()
-
-
 class ColorspaceFastqWriter(FastqWriter):
 	def write(self, record):
 		name = record.name
@@ -563,20 +557,13 @@ class ColorspaceFastqWriter(FastqWriter):
 		qualities = record.qualities
 		super(ColorspaceFastqWriter, self).writeseq(name, sequence, qualities)
 
-
-class PairedSequenceWriter(object):
-	def __init__(self, file1, file2, colorspace=False, fileformat='fastq'):
-		self._writer1 = open(file1, colorspace=colorspace, fileformat=fileformat, mode='w')
-		self._writer2 = open(file2, colorspace=colorspace, fileformat=fileformat, mode='w')
-
+class PairRecordWriter(object):
+	"""Public interface to paired-record files"""
 	def write(self, read1, read2):
-		self._writer1.write(read1)
-		self._writer2.write(read2)
-
+		raise NotImplementedError()
 	def close(self):
-		self._writer1.close()
-		self._writer2.close()
-
+		raise NotImplementedError()
+	
 	def __enter__(self):
 		# TODO do not allow this twice
 		return self
@@ -584,13 +571,27 @@ class PairedSequenceWriter(object):
 	def __exit__(self, *args):
 		self.close()
 
+class PairedSequenceWriter(PairRecordWriter):
+	def __init__(self, file1, file2, colorspace=False, fileformat='fastq', qualities=None):
+		self._writer1 = open(file1, colorspace=colorspace, fileformat=fileformat, mode='w',
+			qualities=qualities)
+		self._writer2 = open(file2, colorspace=colorspace, fileformat=fileformat, mode='w',
+			qualities=qualities)
 
-class InterleavedSequenceWriter(object):
+	def write(self, read1, read2):
+		self._writer1.write(read1)
+		self._writer2.write(read2)
+
+	def close(self):
+		self._writer1.close()
+		self._writer2.close()
+
+class InterleavedSequenceWriter(PairRecordWriter):
 	"""
 	Write paired-end reads to an interleaved FASTA or FASTQ file
 	"""
-	def __init__(self, file, colorspace=False, fileformat='fastq'):
-		self._writer = open(file, colorspace=colorspace, fileformat=fileformat, mode='w')
+	def __init__(self, file, colorspace=False, fileformat='fastq', qualities=None):
+		self._writer = open(file, colorspace=colorspace, fileformat=fileformat, mode='w', qualities=qualities)
 
 	def write(self, read1, read2):
 		self._writer.write(read1)
@@ -599,43 +600,45 @@ class InterleavedSequenceWriter(object):
 	def close(self):
 		self._writer.close()
 
-	def __enter__(self):
-		return self
-
-	def __exit__(self, *args):
-		self.close()
-
-
 class UnknownFileType(Exception):
 	"""
 	Raised when open could not autodetect the file type.
 	"""
 
 
-def open(file1, file2=None, qualfile=None,
-	colorspace=False, fileformat=None, interleaved=False, mode='r'):
+def open(file1, file2=None, qualfile=None, colorspace=False, fileformat=None,
+	interleaved=False, mode='r', qualities=None):
 	"""
-	Open sequence file in FASTA or FASTQ format. Parameters file1, file2 and
-	qualfile can be paths to regular or compressed files or file-like objects.
-	
-	If only file1 is provided and interleaved is True, an
-	InterleavedSequenceReader (for paired-end reads) is returned. If only file1 is provided and interleaved is False, a FastaReader
-	or FastqReader (for single-end reads) is returned. If file2 is also
-	provided, a PairedSequenceReader is returned. If qualfile is given, a
-	FastaQualReader from file1 and qualfile is returned. One of file2 and
-	qualfile must always be None (no paired-end data is supported when reading
-	qualfiles).
-
-	If the colorspace parameter is set to True, the returned readers are
-	ColorspaceFastaReader, ColorspaceFastqReader or ColorspaceFastaQualReader
-	instead.
-
-	If possible, file format is autodetected by inspecting the file name:
-	.fasta/.fa, .fastq/.fq and some other extensions are allowed. If the
-	file name is not available (when reading from standard input), the file is
-	read and the file type determined from the content. The autodetection can
-	be skipped by setting fileformat to one of 'fasta', 'fastq', 'sra-fastq'.
-	Colorspace is not auto-detected and must always be requested explicitly.
+	Open sequence files in FASTA or FASTQ format for reading or writing. This is
+	a factory that returns an instance of one of the ...Reader or ...Writer
+	classes also defined in this module.
+
+	file1, file2, qualfile -- Paths to regular or compressed files or file-like
+		objects. Use file1 if data is single-end. If also file2 is provided,
+		sequences are paired. If qualfile is given, then file1 must be a FASTA
+		file and sequences are single-end. One of file2 and qualfile must always
+		be None (no paired-end data is supported when reading qualfiles).
+
+	mode -- Either 'r' for reading or 'w' for writing.
+
+	interleaved -- If True, then file1 contains interleaved paired-end data.
+		file2 and qualfile must be None in this case.
+
+	colorspace -- If True, instances of the Colorspace... classes
+		are returned.
+
+	fileformat -- If set to None, file format is autodetected from the file name
+		extension. Set to 'fasta', 'fastq', or 'sra-fastq' to not auto-detect.
+		Colorspace is not auto-detected and must always be requested explicitly.
+
+	qualities -- When mode is 'w' and fileformat is None, this can be set to
+		True or False to specify whether the written sequences will have quality
+		values. This is is used in two ways:
+		* If the output format cannot be determined (unrecognized extension
+		  etc), no exception is raised, but fasta or fastq format is chosen
+		  appropriately.
+		* When False (no qualities available), an exception is raised when the
+		  auto-detected output format is FASTQ.
 	"""
 	if mode not in ('r', 'w'):
 		raise ValueError("Mode must be 'r' or 'w'")
@@ -647,13 +650,13 @@ def open(file1, file2=None, qualfile=None,
 		if mode == 'r':
 			return PairedSequenceReader(file1, file2, colorspace, fileformat)
 		else:
-			return PairedSequenceWriter(file1, file2, colorspace, fileformat)
+			return PairedSequenceWriter(file1, file2, colorspace, fileformat, qualities)
 
 	if interleaved:
 		if mode == 'r':
 			return InterleavedSequenceReader(file1, colorspace, fileformat)
 		else:
-			return InterleavedSequenceWriter(file1, colorspace, fileformat)
+			return InterleavedSequenceWriter(file1, colorspace, fileformat, qualities)
 
 	if qualfile is not None:
 		if mode == 'w':
@@ -663,65 +666,91 @@ def open(file1, file2=None, qualfile=None,
 			return ColorspaceFastaQualReader(file1, qualfile)
 		else:
 			return FastaQualReader(file1, qualfile)
-	# read from FASTA or FASTQ
+
+	# All the multi-file things have been dealt with, delegate rest to the
+	# single-file function.
+	return _seqopen1(file1, colorspace=colorspace, fileformat=fileformat,
+		mode=mode, qualities=qualities)
+
+
+def _seqopen1(file, colorspace=False, fileformat=None, mode='r', qualities=None):
+	"""
+	Open a single sequence file. See description above.
+	"""
 	if mode == 'r':
 		fastq_handler = ColorspaceFastqReader if colorspace else FastqReader
 		fasta_handler = ColorspaceFastaReader if colorspace else FastaReader
-	else:
+	elif mode == 'w':
 		fastq_handler = ColorspaceFastqWriter if colorspace else FastqWriter
 		fasta_handler = ColorspaceFastaWriter if colorspace else FastaWriter
+	else:
+		raise ValueError("Mode must be 'r' or 'w'")
 
-	if fileformat is not None:  # explict file format given
+	if fileformat:  # Explict file format given
 		fileformat = fileformat.lower()
 		if fileformat == 'fasta':
-			return fasta_handler(file1)
+			return fasta_handler(file)
 		elif fileformat == 'fastq':
-			return fastq_handler(file1)
+			return fastq_handler(file)
 		elif fileformat == 'sra-fastq' and colorspace:
 			if mode == 'w':
 				raise NotImplementedError('Writing to sra-fastq not supported')
-			return SRAColorspaceFastqReader(file1)
+			return SRAColorspaceFastqReader(file)
 		else:
 			raise UnknownFileType("File format {0!r} is unknown (expected "
 				"'sra-fastq' (only for colorspace), 'fasta' or 'fastq').".format(fileformat))
 
-	if mode == 'w':
-		raise NotImplementedError('autodetection of file type for output files not implemented')
-
-	# Try to detect the file format
+	# Detect file format
 	name = None
-	if file1 == "-":
-		file1 = sys.stdin
-	elif isinstance(file1, basestring):
-		name = file1
-	elif hasattr(file1, "name"):  # file1 seems to be an open file-like object
-		name = file1.name
-
-	if name is not None:
-		if name.endswith('.gz'):
-			name = name[:-3]
-		elif name.endswith('.xz'):
-			name = name[:-3]
-		elif name.endswith('.bz2'):
-			name = name[:-4]
+	if file == "-":
+		file = sys.stdin if mode == 'r' else sys.stdout
+	elif isinstance(file, basestring):
+		name = file
+	elif hasattr(file, "name"):  # seems to be an open file-like object
+		name = file.name
+
+	if name:
+		for ext in ('.gz', '.xz', '.bz2'):
+			if name.endswith(ext):
+				name = name[:-len(ext)]
+				break
 		name, ext = splitext(name)
 		ext = ext.lower()
 		if ext in ['.fasta', '.fa', '.fna', '.csfasta', '.csfa']:
-			return fasta_handler(file1)
+			format = 'fasta'
 		elif ext in ['.fastq', '.fq'] or (ext == '.txt' and name.endswith('_sequence')):
-			return fastq_handler(file1)
+			format = 'fastq'
+		elif mode == 'w' and qualities is True:
+			# Format not recognized, but know we want to write reads with qualities
+			format = 'fastq'
+		elif mode == 'w' and qualities is False:
+			# Same, but we know that we want to write reads without qualities
+			format = 'fasta'
 		else:
 			raise UnknownFileType("Could not determine whether file {0!r} is FASTA "
-				"or FASTQ: file name extension {1!r} not recognized".format(file1, ext))
+				"or FASTQ: file name extension {1!r} not recognized".format(file, ext))
+		if format == 'fastq' and qualities is False:
+			raise ValueError("Output format cannot be FASTQ since no quality "
+				"values are available.")
+		if format == 'fastq':
+			return fastq_handler(file)
+		else:
+			return fasta_handler(file)
 
-	# No name available.
-	# autodetect type by reading from the file
-	for line in file1:
+	if mode == 'w':
+		if qualities is True:
+			return fastq_handler(file)
+		elif qualities is False:
+			return fasta_handler(file)
+		raise UnknownFileType('Cannot determine whether to write in FASTA or '
+			'FASTQ format')
+	# No name available. Try to autodetect type by reading from the file.
+	for line in file:
 		if line.startswith('#'):
 			# Skip comment lines (needed for csfasta)
 			continue
 		if line.startswith('>'):
-			return fasta_handler(FileWithPrependedLine(file1, line))
+			return fasta_handler(FileWithPrependedLine(file, line))
 		if line.startswith('@'):
-			return fastq_handler(FileWithPrependedLine(file1, line))
+			return fastq_handler(FileWithPrependedLine(file, line))
 	raise UnknownFileType("File is neither FASTQ nor FASTA.")
diff --git a/cutadapt/xopen.py b/cutadapt/xopen.py
index dffb2e4..c1b8c90 100644
--- a/cutadapt/xopen.py
+++ b/cutadapt/xopen.py
@@ -85,7 +85,8 @@ class GzipReader:
 		"""
 		retcode = self.process.poll()
 		if retcode is not None and retcode != 0:
-			raise EOFError("gzip process returned non-zero exit code {0}. Is the input file truncated or corrupt?".format(retcode))
+			raise EOFError("gzip process returned non-zero exit code {0}. Is the "
+				"input file truncated or corrupt?".format(retcode))
 
 	def read(self, *args):
 		data = self.process.stdout.read(*args)
@@ -100,10 +101,11 @@ class GzipReader:
 	def __exit__(self, *exc_info):
 		self.close()
 
+
 def xopen(filename, mode='r'):
 	"""
 	Replacement for the "open" function that can also open files that have
-	been compressed with gzip or bzip2. If the filename is '-', standard
+	been compressed with gzip, bzip2 or xz. If the filename is '-', standard
 	output (mode 'w') or input (mode 'r') is returned. If the filename ends
 	with .gz, the file is opened with a pipe to the gzip program. If that
 	does not work, then gzip.open() is used (the gzip module is slower than
@@ -150,11 +152,13 @@ def xopen(filename, mode='r'):
 			return bz2.BZ2File(filename, mode)
 	elif filename.endswith('.xz'):
 		if lzma is None:
-			raise ImportError("Cannot open xz files: The lzma module is not available (use Python 3.3 or newer)")
+			raise ImportError("Cannot open xz files: The lzma module is not available "
+				"(use Python 3.3 or newer)")
 		return lzma.open(filename, mode)
 	elif filename.endswith('.gz'):
 		if PY3:
 			if 't' in mode:
+				# gzip.open in Python 3.2 does not support modes 'rt' and 'wt''
 				return io.TextIOWrapper(gzip.open(filename, mode[0]))
 			else:
 				if 'r' in mode:
diff --git a/doc/colorspace.rst b/doc/colorspace.rst
index 9b60078..fc9c599 100644
--- a/doc/colorspace.rst
+++ b/doc/colorspace.rst
@@ -98,10 +98,31 @@ Bowtie
 ------
 
 Quality values of colorspace reads are sometimes negative. Bowtie gets
-confused and prints this message:
+confused and prints this message::
 
     Encountered a space parsing the quality string for read xyz
 
 BWA also has a problem with such data. Cutadapt therefore converts
 negative quality values to zero in colorspace data. Use the option
 ``--no-zero-cap`` to turn this off.
+
+.. _sra-fastq:
+
+Sequence Read Archive
+---------------------
+
+The Sequence Read Archive provides files in a special "SRA" file format. When
+the ``fastq-dump`` program from the sra-toolkit package is used to convert
+these ``.sra`` files to FASTQ format, colorspace reads will get an extra
+quality value in the beginning of each read. You may get an error like this::
+
+    cutadapt: error: In read named 'xyz': length of colorspace quality
+    sequence (36) and length of read (35) do not match (primer is: 'T')
+
+To make cutadapt ignore the extra quality base, add ``--format=sra-fastq`` to
+your command-line, as in this example::
+
+    cutadapt -c --format=sra-fastq -a CGCCTTGGCCG sra.fastq > trimmed.fastq
+
+When you use ``--format=sra-fastq``, the spurious quality value will be removed
+from all reads in the file.
diff --git a/doc/conf.py b/doc/conf.py
index 981d1f3..bca116e 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -46,7 +46,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'cutadapt'
-copyright = u'2010-2014, Marcel Martin'
+copyright = u'2010-2016, Marcel Martin'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
diff --git a/doc/guide.rst b/doc/guide.rst
index f17c10d..d5d7fe6 100644
--- a/doc/guide.rst
+++ b/doc/guide.rst
@@ -134,6 +134,7 @@ Adapter type                                        Command-line option
 :ref:`Anchored 3' adapter <anchored-3adapters>`     ``-a ADAPTER$``
 :ref:`Anchored 5' adapter <anchored-5adapters>`     ``-g ^ADAPTER``
 :ref:`5' or 3' (both possible) <anywhere-adapters>` ``-b ADAPTER``
+:ref:`Linked adapter <linked-adapters>`              ``-a ADAPTER1...ADAPTER2``
 =================================================== ===========================
 
 Here is an illustration of the allowed adapter locations relative to the read
@@ -290,6 +291,20 @@ Using ``-a ADAPTER$`` will result in::
 Only the middle read is trimmed at all.
 
 
+.. _linked-adapters:
+
+Linked adapters
+---------------
+
+This is a combination of a 5' and a 3' adapter. Use ``-a ADAPTER1...ADAPTER2``
+to search for a linked adapter. ADAPTER1 is interpreted as an anchored 5'
+adapter, which is searched for first. Only if ADAPTER1 is found will then
+ADAPTER2 be searched for,  which is a regular 3' adapter.
+
+This feature is experimental and will probably break when used in combination
+with some other options, such as ``--info-file``, ``--mask-adapter``.
+
+
 .. _anywhere-adapters:
 
 5' or 3' adapters
@@ -385,6 +400,32 @@ Insertions and deletions can be disallowed by using the option
 See also the :ref:`section on details of the alignment algorithm <algorithm>`.
 
 
+Multiple adapter occurrences within a single read
+-------------------------------------------------
+
+If a single read contains multiple copies of the same adapter, the basic rule is
+that the leftmost match is used for both 5' and 3' adapters. For example, when
+searching for a 3' adapter in ::
+
+    cccccADAPTERgggggADAPTERttttt
+
+the read will be trimmed to ::
+
+    ccccc
+
+When the adapter is a 5' adapter instead, the read will be trimmed to ::
+
+    gggggADAPTERttttt
+
+The above applies when both occurrences of the adapter are *exact* matches, and
+it also applies when both occurrences of the adapter are *inexact* matches (that
+is, it has at least one indel or mismatch). However, if one match is exact, but
+the other is inexact, then the exact match wins, even if it is not the leftmost
+one! The reason for this behavior is that cutadapt searches for exact matches
+first and, to improve performance, skips the error-tolerant matching step if an
+exact match was found.
+
+
 Reducing random matches
 -----------------------
 
@@ -393,8 +434,8 @@ short matches can occur by chance, leading to erroneously trimmed bases. For
 example, roughly 25% of all reads end with a base that is identical to the
 first base of the adapter. To reduce the number of falsely trimmed bases,
 the alignment algorithm requires that at least *three bases* match between
-adapter and read. The minimum overlap length can be changed with the
-``--overlap``(short: ``-O``) parameter. Shorter matches are simply
+adapter and read. The minimum overlap length can be changed with the parameter
+``--overlap`` (or its short version ``-O``). Shorter matches are simply
 ignored, and the bases are not trimmed.
 
 Requiring at least three bases to match is quite conservative. Even if no
@@ -405,7 +446,7 @@ overlap length of 3, only about 0.07 bases are lost per read.
 
 When choosing an appropriate minimum overlap length, take into account that
 true adapter matches are also lost when the overlap length is higher than
-1, reducing cutadapt's sensitivity.
+zero, reducing cutadapt's sensitivity.
 
 
 .. _wildcards:
@@ -687,6 +728,18 @@ and::
 
     @my_read/2 another comment
 
+This is an example for *improperly paired* read names::
+
+    @my_read/1;1
+
+and::
+
+    @my_read/2;1
+
+Since the ``/1`` and ``/2`` are ignored only if the occur at the end of the read
+name, and since the ``;1`` is considered to be part of the read name, these
+reads will not be considered to be propely paired.
+
 As soon as you start to use one of the filtering options that discard reads, it
 is mandatory you process both files at the same time to make sure that the
 output files are kept synchronized: If a read is removed from one of the files,
diff --git a/doc/ideas.rst b/doc/ideas.rst
index 794be2c..b5fa9d7 100644
--- a/doc/ideas.rst
+++ b/doc/ideas.rst
@@ -24,14 +24,15 @@ improvements.
 - instead of trimming, convert adapter to lowercase
 - warn when given adapter sequence contains non-IUPAC characters
 - try multithreading again, this time use os.pipe() or 0mq
-
+- extensible file type detection
+- the --times setting should be an attribute of Adapter
 
 Specifying adapters
 -------------------
 
-The idea is to deprecate the ``-b`` and ``-g`` parameters. Only ``-a`` is used
-with a special syntax for each adapter type. This makes it a bit easier to add
-new adapter types in the feature.
+The idea is to deprecate the ``-b``,  ``-g`` and ``-u`` parameters. Only ``-a``
+is used with a special syntax for each adapter type. This makes it a bit easier
+to add new adapter types in the feature.
 
 .. csv-table::
 
@@ -40,7 +41,9 @@ new adapter types in the feature.
     front,``-g ADAPTER``,``-a ADAPTER...``
     prefix,``-g ^ADAPTER``,``-a ^ADAPTER...`` (or have anchoring by default?)
     anywhere,``-b ADAPTER``, ``-a ...ADAPTER...`` ???
-    paired,(not implemented),``-a ADAPTER...ADAPTER`` or ``-a ^ADAPTER...ADAPTER``
+    unconditional,``-u +10``,``-a 10...`` (collides with colorspace)
+    unconditional,``-u -10``,``-a ...10$``
+    linked,(not implemented),``-a ADAPTER...ADAPTER`` or ``-a ^ADAPTER...ADAPTER``
 
 Or add only ``-a ADAPTER...`` as an alias for ``-g ^ADAPTER`` and
 ``-a ...ADAPTER`` as an alias for ``-a ADAPTER``.
@@ -98,4 +101,3 @@ Available/used letters for command-line options
 * Remaining characters: All uppercase letters except A, B, G, M, N, O, U
 * Lowercase letters: i, j, k, l, s, w
 * Planned/reserved: Q (paired-end quality trimming), j (multithreading)
-
diff --git a/doc/installation.rst b/doc/installation.rst
index fa349de..305d910 100644
--- a/doc/installation.rst
+++ b/doc/installation.rst
@@ -20,7 +20,18 @@ to install a newer version. You can then run the program like this::
 If you want to avoid typing the full path, add the directory
 ``$HOME/.local/bin`` to your ``$PATH`` environment variable.
 
-If the above does not work, keep reading.
+
+Installation with conda
+-----------------------
+
+Alternatively, cutadapt is also available as a conda package from the
+`bioconda channel <https://bioconda.github.io/>`_. If you do not have conda,
+`install miniconda <http://conda.pydata.org/miniconda.html>`_ first.
+Then install cutadapt like this::
+
+    conda install -c bioconda cutadapt
+
+If neither `pip` nor `conda` installation works, keep reading.
 
 
 Dependencies
@@ -28,12 +39,12 @@ Dependencies
 
 Cutadapt requires this software to be installed:
 
-* One of Python 2.6, 2.7, 3.3 or 3.4. Python 2.7 is a bit faster than the other
-  versions.
+* One of Python 2.6, 2.7, 3.3, 3.4 or 3.5. Python 2.7 is a bit faster than the
+  other versions.
 * A C compiler.
 
 Under Ubuntu, you may need to install the packages ``build-essential`` and
-``python-dev``.
+``python-dev`` (or ``python3-dev``).
 
 
 Installation
@@ -55,8 +66,8 @@ appropriate package is called ``python-dev`` in Ubuntu (or ``python3-dev``
 for Python 3).
 
 
-System-wide installation
-------------------------
+System-wide installation (root required)
+----------------------------------------
 
 If you have root access, then you can install cutadapt system-wide by running::
 
@@ -69,19 +80,48 @@ If you want to upgrade from an older version, use this command instead::
     sudo pip install --upgrade cutadapt
 
 
-Use without installation
-------------------------
+Uninstalling
+------------
+
+Type  ::
+
+    pip uninstall cutadapt
+
+and confirm with ``y`` to remove the package. Under some circumstances, multiple
+versions may be installed at the same time. Repeat the above command until you
+get an error message in order to make sure that all versions are removed.
+
+
+Shared installation (on a cluster)
+----------------------------------
+
+If you have a larger installation and want to provide cutadapt as a module
+that can be loaded and unloaded (with the Lmod system, for example), we
+recommend that you create a virtual environment and 'pip install' cutadapt into
+it. These instructions work on our SLURM cluster that uses the Lmod system
+(replace ``1.9.1`` with the actual version you want to use)::
 
-Build the C extension module (you can try to skip this step -- a
-compiled version of the module for Linux x86\_64 is already included)::
+    BASE=/software/cutadapt-1.9.1
+    virtualenv $BASE/venv
+    $BASE/venv/bin/pip install --install-option="--install-scripts=$BASE/bin" cutadapt==1.9.1
 
-    python setup.py build_ext -i
+The ``install-option`` part is important. It ensures that a second, separate
+``bin/`` directory is created (``/software/cutadapt-1.9.1/bin/``) that *only*
+contains the ``cutadapt`` script and nothing else. To make cutadapt available to
+the users, that directory (``$BASE/bin``) needs to be added to the ``$PATH``.
 
-Then simply run the script from where it is, similar to this::
+Make sure you *do not* add the ``bin/`` directory within the ``venv`` directory
+to the ``$PATH``! Otherwise, a user trying to run ``python`` who also has the
+cutadapt module loaded would get the python from the virtual environment,
+which leads to confusing error messages.
 
-    bin/cutadapt --help
+A simple module file for the Lmod system matching the above example could look
+like this::
 
-If you get any errors, first try to explicitly request a specific Python
-version by running cutadapt like this::
+    conflict("cutadapt")
+    whatis("adapter trimming tool")
+    prepend_path("PATH", "/software/cutadapt-1.9.1/bin")
 
-    python2.7 bin/cutadapt --help
+Please note that there is no need to “activate” the virtual environment:
+Activation merely adds the ``bin/`` directory to the ``$PATH``, so the
+``prepend_path`` directive is equivalent to activating the virtual environment.
diff --git a/setup.py b/setup.py
index b8ce553..1a2d235 100644
--- a/setup.py
+++ b/setup.py
@@ -8,18 +8,27 @@ Cython is run when
 """
 import sys
 import os.path
+
 from distutils.core import setup, Extension
 from distutils.version import LooseVersion
+from distutils.command.sdist import sdist as _sdist
+from distutils.command.build_ext import build_ext as _build_ext
 
-from cutadapt import __version__
-
-MIN_CYTHON_VERSION = '0.17'
+MIN_CYTHON_VERSION = '0.24'
 
 if sys.version_info < (2, 6):
 	sys.stdout.write("At least Python 2.6 is required.\n")
 	sys.exit(1)
 
 
+# set __version__
+with open(os.path.join(os.path.dirname(__file__), 'cutadapt', '__init__.py')) as f:
+	for line in f:
+		if line.startswith('__version__'):
+			exec(line)
+			break
+
+
 def out_of_date(extensions):
 	"""
 	Check whether any pyx source is newer than the corresponding generated
@@ -62,17 +71,10 @@ def no_cythonize(extensions, **_ignore):
 				sfile = path + ext
 			sources.append(sfile)
 		extension.sources[:] = sources
-	return extensions
-
 
-def cythonize_if_necessary(extensions):
-	if '--cython' in sys.argv:
-		sys.argv.remove('--cython')
-	elif out_of_date(extensions):
-		sys.stdout.write('At least one C source file is missing or out of date.\n')
-	else:
-		return no_cythonize(extensions)
 
+def check_cython_version():
+	"""Exit if Cython was not found or is too old"""
 	try:
 		from Cython import __version__ as cyversion
 	except ImportError:
@@ -86,16 +88,38 @@ def cythonize_if_necessary(extensions):
 			"', but at least version " + str(MIN_CYTHON_VERSION) + " is required.\n")
 		sys.exit(1)
 
-	from Cython.Build import cythonize
-	return cythonize(extensions)
-
 
 extensions = [
 	Extension('cutadapt._align', sources=['cutadapt/_align.pyx']),
 	Extension('cutadapt._qualtrim', sources=['cutadapt/_qualtrim.pyx']),
 	Extension('cutadapt._seqio', sources=['cutadapt/_seqio.pyx']),
 ]
-extensions = cythonize_if_necessary(extensions)
+
+
+class build_ext(_build_ext):
+	def run(self):
+		# If we encounter a PKG-INFO file, then this is likely a .tar.gz/.zip
+		# file retrieved from PyPI that already includes the pre-cythonized
+		# extension modules, and then we do not need to run cythonize().
+		if os.path.exists('PKG-INFO'):
+			no_cythonize(extensions)
+		else:
+			# Otherwise, this is a 'developer copy' of the code, and then the
+			# only sensible thing is to require Cython to be installed.
+			check_cython_version()
+			from Cython.Build import cythonize
+			self.extensions = cythonize(self.extensions)
+		_build_ext.run(self)
+
+
+class sdist(_sdist):
+	def run(self):
+		# Make sure the compiled Cython files in the distribution are up-to-date
+		from Cython.Build import cythonize
+		check_cython_version()
+		cythonize(extensions)
+		_sdist.run(self)
+
 
 setup(
 	name = 'cutadapt',
@@ -105,6 +129,7 @@ setup(
 	url = 'https://cutadapt.readthedocs.org/',
 	description = 'trim adapters from high-throughput sequencing reads',
 	license = 'MIT',
+	cmdclass = {'sdist': sdist, 'build_ext': build_ext},
 	ext_modules = extensions,
 	packages = ['cutadapt', 'cutadapt.scripts'],
 	scripts = ['bin/cutadapt'],
diff --git a/tests/cut/linked.fasta b/tests/cut/linked.fasta
new file mode 100644
index 0000000..c010e80
--- /dev/null
+++ b/tests/cut/linked.fasta
@@ -0,0 +1,10 @@
+>r1 5' adapter and 3' adapter
+CCCCCCCCCC
+>r5 only 5' adapter
+CCCCCCCCCCGGGGGGG
+>r3 5' adapter, partial 3' adapter
+CCCGGCCCCC
+>r4 only 3' adapter
+GGGGGGGGGGCCCCCCCCCCTTTTTTTTTTGGGGGGG
+>r2 without any adapter
+GGGGGGGGGGGGGGGGGGG
diff --git a/tests/cut/nextseq.fastq b/tests/cut/nextseq.fastq
new file mode 100644
index 0000000..fad6929
--- /dev/null
+++ b/tests/cut/nextseq.fastq
@@ -0,0 +1,8 @@
+ at NS500350:251:HLM7JBGXX:1:11101:12075:1120 1:N:0:TACAGC
+GATCGGAAGAGCACACGTCTGAACTCCAGTCACTACAGCATCTCGTATTCCGTCTTCTGCTTGAAAAAAAA
++
+AAAAAEEEEEEAEEEEAEAEEEEEEAEEEEEEEEEEEEEEE///E/EE////AAEE/E//////EEEEEEE
+ at NS500350:251:HLM7JBGXX:1:11101:22452:1121 1:N:0:TACAGC
+GATCGGAAGAGCACACGTCTGAACTCCAGTCACTACAGCATCGCGTATGCCGTCTTATGCTTGAAAAAAAAA
++
+AAAAAEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE/////E/EE//E6///E//A//E//EEEEEEEE
diff --git a/tests/cut/small.fasta b/tests/cut/small.fasta
new file mode 100644
index 0000000..dde4ba1
--- /dev/null
+++ b/tests/cut/small.fasta
@@ -0,0 +1,6 @@
+>prefix:1_13_573/1
+CGTCCGAANTAGCTACCACCCTGA
+>prefix:1_13_1259/1
+AGCCGCTANGACGGGTTGGCCC
+>prefix:1_13_1440/1
+CAAGATCTNCCCTGCCACATTGCCCTAGTTAAAC
diff --git a/tests/data/linked.fasta b/tests/data/linked.fasta
new file mode 100644
index 0000000..5d21f89
--- /dev/null
+++ b/tests/data/linked.fasta
@@ -0,0 +1,10 @@
+>r1 5' adapter and 3' adapter
+AAAAAAAAAACCCCCCCCCCTTTTTTTTTTGGGGGGG
+>r5 only 5' adapter
+AAAAAAAAAACCCCCCCCCCGGGGGGG
+>r3 5' adapter, partial 3' adapter
+AAAAAAAAAACCCGGCCCCCTTTTT
+>r4 only 3' adapter
+GGGGGGGGGGCCCCCCCCCCTTTTTTTTTTGGGGGGG
+>r2 without any adapter
+GGGGGGGGGGGGGGGGGGG
diff --git a/tests/data/nextseq.fastq b/tests/data/nextseq.fastq
new file mode 100644
index 0000000..0b6acc1
--- /dev/null
+++ b/tests/data/nextseq.fastq
@@ -0,0 +1,8 @@
+ at NS500350:251:HLM7JBGXX:1:11101:12075:1120 1:N:0:TACAGC
+GATCGGAAGAGCACACGTCTGAACTCCAGTCACTACAGCATCTCGTATTCCGTCTTCTGCTTGAAAAAAAAAAAGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
++
+AAAAAEEEEEEAEEEEAEAEEEEEEAEEEEEEEEEEEEEEE///E/EE////AAEE/E//////EEEEEEE6///////E6EEA/AEAEAE6EEEEEEEEEEEEAEAA/E/EEEEA//EEEEEAEAEE/EEEAEEEE<E/AEEEEE/EEE
+ at NS500350:251:HLM7JBGXX:1:11101:22452:1121 1:N:0:TACAGC
+GATCGGAAGAGCACACGTCTGAACTCCAGTCACTACAGCATCGCGTATGCCGTCTTATGCTTGAAAAAAAAAAAGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
++
+AAAAAEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE/////E/EE//E6///E//A//E//EEEEEEEE6//EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE<EEEEEEEE
diff --git a/tests/testadapters.py b/tests/testadapters.py
index 60d55ea..4d3147b 100644
--- a/tests/testadapters.py
+++ b/tests/testadapters.py
@@ -3,14 +3,14 @@ from __future__ import print_function, division, absolute_import
 from nose.tools import raises, assert_raises
 
 from cutadapt.seqio import Sequence
-from cutadapt.adapters import (Adapter, Match, ColorspaceAdapter, FRONT,
-	BACK, parse_braces)
+from cutadapt.adapters import (Adapter, Match, ColorspaceAdapter, FRONT, BACK,
+	parse_braces, LinkedAdapter)
 
 def test_issue_52():
 	adapter = Adapter(
 		sequence='GAACTCCAGTCACNNNNN',
 		where=BACK,
-		max_error_rate=0.1,
+		max_error_rate=0.12,
 		min_overlap=5,
 		read_wildcards=False,
 		adapter_wildcards=True)
@@ -86,3 +86,40 @@ def test_parse_braces_fail():
 	for expression in ['{', '}', '{}', '{5', '{1}', 'A{-7}', 'A{', 'A{1', 'N{7', 'AN{7', 'A{4{}',
 			'A{4}{3}', 'A{b}', 'A{6X}', 'A{X6}']:
 		assert_raises(ValueError, lambda: parse_braces(expression))
+
+
+def test_linked_adapter():
+	linked_adapter = LinkedAdapter('AAAA', 'TTTT')
+	sequence = Sequence(name='seq', sequence='AAAACCCCCTTTT')
+	match = linked_adapter.match_to(sequence)
+	trimmed = linked_adapter.trimmed(match)
+	assert trimmed.name == 'seq'
+	assert trimmed.sequence == 'CCCCC'
+
+
+def test_info_record():
+	adapter = Adapter(
+		sequence='GAACTCCAGTCACNNNNN',
+		where=BACK,
+		max_error_rate=0.12,
+		min_overlap=5,
+		read_wildcards=False,
+		adapter_wildcards=True,
+		name="Foo")
+	read = Sequence(name="abc", sequence='CCCCAGAACTACAGTCCCGGC')
+	am = Match(astart=0, astop=17, rstart=5, rstop=21, matches=15, errors=2, front=None, 
+		adapter=adapter, read=read)
+	print(am.get_info_record())
+	assert am.get_info_record() == (
+		"abc",
+		2,
+		5,
+		21,
+		'CCCCA',
+		'GAACTACAGTCCCGGC',
+		'',
+		'Foo',
+		'', 
+		'', 
+		''
+	)
diff --git a/tests/testpaired.py b/tests/testpaired.py
index 9697e2c..51cc1d0 100644
--- a/tests/testpaired.py
+++ b/tests/testpaired.py
@@ -9,8 +9,8 @@ from .utils import run, files_equal, datapath, cutpath, redirect_stderr, tempora
 def run_paired(params, in1, in2, expected1, expected2):
 	if type(params) is str:
 		params = params.split()
-	with temporary_path("temp-paired.1.fastq") as p1:
-		with temporary_path("temp-paired.2.fastq") as p2:
+	with temporary_path('tmp1-' + expected1) as p1:
+		with temporary_path('tmp2-' + expected2) as p2:
 			params += ['-o', p1, '-p', p2]
 			params += [datapath(in1), datapath(in2)]
 			assert cutadapt.main(params) is None
@@ -21,17 +21,18 @@ def run_paired(params, in1, in2, expected1, expected2):
 def run_interleaved(params, inpath, expected):
 	if type(params) is str:
 		params = params.split()
-	with temporary_path("temp-interleaved.fastq") as tmp:
+	with temporary_path(expected) as tmp:
 		params += ['--interleaved', '-o', tmp, datapath(inpath)]
 		assert cutadapt.main(params) is None
 		assert files_equal(cutpath(expected), tmp)
 
 
 def run_interleaved2(params, inpath, expected1, expected2):
+	assert False  # unused function
 	if type(params) is str:
 		params = params.split()
-	with temporary_path("temp-paired.1.fastq") as p1:
-		with temporary_path("temp-paired.2.fastq") as p2:
+	with temporary_path('tmp1-' + expected1) as p1:
+		with temporary_path('tmp2-' + expected2) as p2:
 			params += ['--interleaved', '-o', p1, '-p', p2]
 		params += [datapath(inpath)]
 		assert cutadapt.main(params) is None
diff --git a/tests/testqualtrim.py b/tests/testqualtrim.py
new file mode 100644
index 0000000..173b264
--- /dev/null
+++ b/tests/testqualtrim.py
@@ -0,0 +1,14 @@
+# coding: utf-8
+from __future__ import print_function, division, absolute_import
+
+from cutadapt.seqio import Sequence
+from cutadapt.qualtrim import nextseq_trim_index
+
+def test_nextseq_trim():
+	s = Sequence('n', '', '')
+	assert nextseq_trim_index(s, cutoff=22) == 0
+	s = Sequence('n',
+		'TCTCGTATGCCGTCTTATGCTTGAAAAAAAAAAGGGGGGGGGGGGGGGGGNNNNNNNNNNNGGNGG',
+		'AA//EAEE//A6///E//A//EA/EEEEEEAEA//EEEEEEEEEEEEEEE###########EE#EA'
+	)
+	assert nextseq_trim_index(s, cutoff=22) == 33
diff --git a/tests/tests.py b/tests/tests.py
index 34b3c1a..241e169 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -8,9 +8,9 @@ import os
 import sys
 from nose.tools import raises
 from cutadapt.scripts import cutadapt
+from cutadapt.compat import StringIO
 from .utils import run, files_equal, datapath, cutpath, redirect_stderr, temporary_path
 
-
 def test_example():
 	run('-N -b ADAPTER', 'example.fa', 'example.fa')
 
@@ -353,3 +353,31 @@ def test_max_n():
 	run('--max-n 2', 'maxn2.fasta', 'maxn.fasta')
 	run('--max-n 0.2', 'maxn0.2.fasta', 'maxn.fasta')
 	run('--max-n 0.4', 'maxn0.4.fasta', 'maxn.fasta')
+
+
+def test_quiet_is_quiet():
+	captured_standard_output = StringIO()
+	captured_standard_error = StringIO()
+	try:
+		old_stdout = sys.stdout
+		old_stderr = sys.stderr
+		sys.stdout = captured_standard_output
+		sys.stderr = captured_standard_error
+		cutadapt.main(['-o', '/dev/null', '--quiet', '-a', 'XXXX', datapath('illumina.fastq.gz')])
+	finally:
+		sys.stdout = old_stdout
+		sys.stderr = old_stderr
+	assert captured_standard_output.getvalue() == ''
+	assert captured_standard_error.getvalue() == ''
+
+
+def test_nextseq():
+	run('--nextseq-trim 22', 'nextseq.fastq', 'nextseq.fastq')
+
+
+def test_linked():
+	run('-a AAAAAAAAAA...TTTTTTTTTT', 'linked.fasta', 'linked.fasta')
+
+
+def test_fasta():
+	run('-a TTAGACATATCTCCGTCG', 'small.fasta', 'small.fastq')
diff --git a/tests/testseqio.py b/tests/testseqio.py
index 7c49c96..ef8b0b6 100644
--- a/tests/testseqio.py
+++ b/tests/testseqio.py
@@ -9,7 +9,8 @@ from nose.tools import raises
 from tempfile import mkdtemp
 from cutadapt.seqio import (Sequence, ColorspaceSequence, FormatError,
 	FastaReader, FastqReader, FastaQualReader, InterleavedSequenceReader,
-	FastaWriter, FastqWriter, InterleavedSequenceWriter, open as openseq)
+	FastaWriter, FastqWriter, InterleavedSequenceWriter, open as openseq,
+	sequence_names_match)
 from cutadapt.compat import StringIO
 
 
@@ -153,6 +154,12 @@ class TestFastaQualReader:
 
 
 class TestSeqioOpen:
+	def setup(self):
+		self._tmpdir = mkdtemp()
+
+	def teardown(self):
+		shutil.rmtree(self._tmpdir)
+
 	def test_sequence_reader(self):
 		# test the autodetection
 		with openseq("tests/data/simple.fastq") as f:
@@ -176,6 +183,35 @@ class TestSeqioOpen:
 		reads = list(openseq(f))
 		assert reads == simple_fasta
 
+	def test_autodetect_fasta_format(self):
+		path = os.path.join(self._tmpdir, 'tmp.fasta')
+		with openseq(path, mode='w') as f:
+			assert isinstance(f, FastaWriter)
+			for seq in simple_fastq:
+				f.write(seq)
+		assert list(openseq(path)) == simple_fasta
+
+	def test_write_qualities_to_fasta(self):
+		path = os.path.join(self._tmpdir, 'tmp.fasta')
+		with openseq(path, mode='w', qualities=True) as f:
+			assert isinstance(f, FastaWriter)
+			for seq in simple_fastq:
+				f.write(seq)
+		assert list(openseq(path)) == simple_fasta
+
+	def test_autodetect_fastq_format(self):
+		path = os.path.join(self._tmpdir, 'tmp.fastq')
+		with openseq(path, mode='w') as f:
+			assert isinstance(f, FastqWriter)
+			for seq in simple_fastq:
+				f.write(seq)
+		assert list(openseq(path)) == simple_fastq
+
+	@raises(ValueError)
+	def test_fastq_qualities_missing(self):
+		path = os.path.join(self._tmpdir, 'tmp.fastq')
+		openseq(path, mode='w', qualities=False)
+
 
 class TestInterleavedReader:
 	def test(self):
@@ -299,3 +335,18 @@ class TestInterleavedWriter:
 			for read1, read2 in reads:
 				writer.write(read1, read2)
 		assert sio.getvalue() == '@A/1 comment\nTTA\n+\n##H\n at A/2 comment\nGCT\n+\nHH#\n at B/1\nCC\n+\nHH\n at B/2\nTG\n+\n#H\n'
+
+
+class TestPairedSequenceReader:
+	def test_sequence_names_match(self):
+		def match(name1, name2):
+			seq1 = Sequence(name1, 'ACGT')
+			seq2 = Sequence(name2, 'AACC')
+			return sequence_names_match(seq1, seq2)
+
+		assert match('abc', 'abc')
+		assert match('abc/1', 'abc/2')
+		assert match('abc.1', 'abc.2')
+		assert match('abc1', 'abc2')
+		assert not match('abc', 'xyz')
+
diff --git a/tests/utils.py b/tests/utils.py
index c4828a2..473e598 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -39,7 +39,7 @@ def files_equal(path1, path2):
 def run(params, expected, inpath, inpath2=None):
 	if type(params) is str:
 		params = params.split()
-	with temporary_path('tmp.fastaq') as tmp_fastaq:
+	with temporary_path(expected) as tmp_fastaq:
 		params += ['-o', tmp_fastaq ] # TODO not parallelizable
 		params += [ datapath(inpath) ]
 		if inpath2:

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/python-cutadapt.git



More information about the debian-med-commit mailing list