Allow overriding default quotation mark
diff --git a/Makefile b/Makefile
index 9030ab2..76e3516 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@
 	python make_unicode_categories.py $< $@
 
 pyjson5.cpp: pyjson5.pyx $(wildcard src/*.pyx)
-	python -m cython -o $@ $<
+	python -m cython -f -o $@ $<
 
 sdist: pyjson5.cpp ${FILES}
 	rm -f -- dist/pyjson5-*.tar.gz
diff --git a/src/_constants.pyx b/src/_constants.pyx
index c1edb56..eba4878 100644
--- a/src/_constants.pyx
+++ b/src/_constants.pyx
@@ -13,3 +13,7 @@
     'latin_1', 'latin-1', 'iso-8859-1', 'iso8859-1',
     8859, '8859', 'cp819', 'latin', 'latin1', 'l1',
 ))
+
+cdef object TEST_DECIMAL = Decimal('47.11')
+cdef object TEST_FLOAT = 47.11
+cdef object TEST_INT = 4711
diff --git a/src/_encoder.pyx b/src/_encoder.pyx
index b2807cc..c196f34 100644
--- a/src/_encoder.pyx
+++ b/src/_encoder.pyx
@@ -9,7 +9,7 @@
 
     if length > 0:
         writer.reserve(writer, 2 + length)
-        writer.append_c(writer, <char> b'"')
+        writer.append_c(writer, <char> PyUnicode_1BYTE_DATA((<Options> writer.options).quotationmark)[0])
         while True:
             if UCSString is UCS1String:
                 sublength = length
@@ -76,7 +76,7 @@
             length -= 1
             if length <= 0:
                 break
-        writer.append_c(writer, <char> b'"')
+        writer.append_c(writer, <char> PyUnicode_1BYTE_DATA((<Options> writer.options).quotationmark)[0])
     else:
         writer.append_s(writer, b'""', 2)
 
@@ -125,7 +125,7 @@
         string = <char*> sub_writer.obj
 
         writer.reserve(writer, 2 + length)
-        writer.append_c(writer, <char> b'"')
+        writer.append_c(writer, <char> PyUnicode_1BYTE_DATA((<Options> writer.options).quotationmark)[0])
         for index in range(length):
             c = string[index]
             if c not in b'\\"':
@@ -134,7 +134,7 @@
                 writer.append_s(writer, b'\\\\', 2)
             else:
                 writer.append_s(writer, b'\\u0022', 6)
-        writer.append_c(writer, <char> b'"')
+        writer.append_c(writer, <char> PyUnicode_1BYTE_DATA((<Options> writer.options).quotationmark)[0])
     finally:
         if sub_writer.obj is not NULL:
             ObjectFree(sub_writer.obj)
@@ -281,9 +281,9 @@
     cdef const char *string = PyUnicode_AsUTF8AndSize(stringified, &length)
 
     writer.reserve(writer, 2 + length)
-    writer.append_c(writer, <char> b'"')
+    writer.append_c(writer, <char> PyUnicode_1BYTE_DATA((<Options> writer.options).quotationmark)[0])
     writer.append_s(writer, string, length)
-    writer.append_c(writer, <char> b'"')
+    writer.append_c(writer, <char> PyUnicode_1BYTE_DATA((<Options> writer.options).quotationmark)[0])
 
     return True
 
diff --git a/src/_encoder_options.pyx b/src/_encoder_options.pyx
index 70b44f4..daff41e 100644
--- a/src/_encoder_options.pyx
+++ b/src/_encoder_options.pyx
@@ -6,6 +6,7 @@
 cdef object DEFAULT_FLOATFORMAT = '%.6e'
 cdef object DEFAULT_DECIMALFORMAT = '%s'
 cdef object DEFAULT_MAPPINGTYPES = (Mapping,)
+cdef object DEFAULT_QUOTATIONMARK = '"'
 
 
 cdef object _options_ascii(object datum, boolean expect_ascii=True):
@@ -34,12 +35,13 @@
 
 cdef _options_from_ascii(Options self):
     return ', '.join(filter(bool, (
+        _option_from_ascii('quotationmark', self.quotationmark, DEFAULT_QUOTATIONMARK),
         _option_from_ascii('tojson', self.tojson, None),
         _option_from_ascii('posinfinity', self.posinfinity, DEFAULT_POSINFINITY),
         _option_from_ascii('neginfinity', self.neginfinity, DEFAULT_NEGINFINITY),
         _option_from_ascii('intformat', self.intformat, DEFAULT_INTFORMAT),
-        _option_from_ascii('floatformat', self.floatformat, DEFAULT_DECIMALFORMAT),
-        _option_from_ascii('decimalformat', self.decimalformat, DEFAULT_FLOATFORMAT),
+        _option_from_ascii('floatformat', self.floatformat, DEFAULT_FLOATFORMAT),
+        _option_from_ascii('decimalformat', self.decimalformat, DEFAULT_DECIMALFORMAT),
         _option_from_ascii('nan', self.nan, DEFAULT_NAN),
     )))
 
@@ -54,6 +56,9 @@
 
     Parameters
     ----------
+    quotationmark : str|None
+        * **str**: One character string that is used to surround strings.
+        * **None**: Use default: ``'"'``.
     tojson : str|False|None
         * **str:** A special method to call on objects to return a custom JSON encoded string. Must return ASCII data!
         * **False:** No such member exists. (Default.)
@@ -88,6 +93,9 @@
         * **False:** There are no objects. Any object will be encoded as list of keys as in list(obj).
         * **None:** Use default: ``[collections.abc.Mapping]``.
     '''
+    cdef readonly unicode quotationmark
+    '''The creation argument ``quotationmark``.
+    '''
     cdef readonly unicode tojson
     '''The creation argument ``tojson``.
     ``None`` if ``False`` was specified.
@@ -150,11 +158,15 @@
         return self.__repr__()
 
     def __cinit__(self, *,
+                  quotationmark=None,
                   tojson=None, posinfinity=None, neginfinity=None, nan=None,
                   decimalformat=None, intformat=None, floatformat=None,
                   mappingtypes=None):
         cdef object cls
+        cdef object ex
 
+        if quotationmark is None:
+            quotationmark = DEFAULT_QUOTATIONMARK
         if tojson is None:
             tojson = DEFAULT_TOJSON
         if posinfinity is None:
@@ -172,6 +184,7 @@
         if mappingtypes is None:
             mappingtypes = DEFAULT_MAPPINGTYPES
 
+        self.quotationmark = _options_ascii(quotationmark)
         self.tojson = _options_ascii(tojson, False)
         self.posinfinity = _options_ascii(posinfinity)
         self.neginfinity = _options_ascii(neginfinity)
@@ -180,6 +193,27 @@
         self.decimalformat = _options_ascii(decimalformat)
         self.nan = _options_ascii(nan)
 
+        if self.quotationmark is None or PyUnicode_GET_LENGTH(self.quotationmark) != 1:
+            raise TypeError('quotationmark must be one ASCII character.')
+
+        if intformat is not None:
+            try:
+                intformat % TEST_INT
+            except Exception as ex:
+                raise ValueError('intformat is not a valid format string') from ex
+
+        if floatformat is not None:
+            try:
+                floatformat % TEST_FLOAT
+            except Exception as ex:
+                raise ValueError('floatformat is not a valid format string') from ex
+
+        if decimalformat is not None:
+            try:
+                decimalformat % TEST_DECIMAL
+            except Exception as ex:
+                raise ValueError('decimalformat is not a valid format string') from ex
+
         if mappingtypes is False:
             self.mappingtypes = ()
         else:
@@ -208,6 +242,7 @@
     elif not kw:
         return arg
 
+    PyDict_SetDefault(kw, 'quotationmark', (<Options> arg).quotationmark)
     PyDict_SetDefault(kw, 'tojson', (<Options> arg).tojson)
     PyDict_SetDefault(kw, 'posinfinity', (<Options> arg).posinfinity)
     PyDict_SetDefault(kw, 'neginfinity', (<Options> arg).neginfinity)
diff --git a/src/_exports.pyx b/src/_exports.pyx
index d04cf77..084d049 100644
--- a/src/_exports.pyx
+++ b/src/_exports.pyx
@@ -286,7 +286,7 @@
         will be valid JSON data (as of RFC8259).
 
         The result is always ASCII. All characters outside of the ASCII range
-        are encoded.
+        are escaped.
 
         The result safe to use in an HTML template, e.g.
         ``<a onclick='alert({{ encode(url) }})'>show message</a>``.