Squashed 'third_party/pycrc/' content from commit cb91196b9

Change-Id: Iaed6f7d683e3c11395f10f0724f973363aad2cdb
git-subtree-dir: third_party/pycrc
git-subtree-split: cb91196b920d1f892c05941ed470c7a80cba7596
diff --git a/pycrc/__init__.py b/pycrc/__init__.py
new file mode 100644
index 0000000..e0749e4
--- /dev/null
+++ b/pycrc/__init__.py
@@ -0,0 +1,3 @@
+progname = "pycrc"
+version = "0.9.1"
+url = 'https://pycrc.org'
diff --git a/pycrc/__main__.py b/pycrc/__main__.py
new file mode 100644
index 0000000..cefc3bb
--- /dev/null
+++ b/pycrc/__main__.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+#  pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+#  Copyright (c) 2006-2017  Thomas Pircher  <tehpeh-web@tty1.net>
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to
+#  deal in the Software without restriction, including without limitation the
+#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+#  sell copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+#  IN THE SOFTWARE.
+
+from pycrc.main import main
+import sys
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/pycrc/algorithms.py b/pycrc/algorithms.py
new file mode 100644
index 0000000..3ebcebd
--- /dev/null
+++ b/pycrc/algorithms.py
@@ -0,0 +1,235 @@
+#  pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+#  Copyright (c) 2006-2017  Thomas Pircher  <tehpeh-web@tty1.net>
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to
+#  deal in the Software without restriction, including without limitation the
+#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+#  sell copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+#  IN THE SOFTWARE.
+
+
+"""
+CRC algorithms implemented in Python.
+If you want to study the Python implementation of the CRC routines, then this
+is a good place to start from.
+
+The algorithms Bit by Bit, Bit by Bit Fast and Table-Driven are implemented.
+
+This module can also be used as a library from within Python.
+
+Examples
+========
+
+This is an example use of the different algorithms:
+
+    from pycrc.algorithms import Crc
+
+    crc = Crc(width = 16, poly = 0x8005,
+            reflect_in = True, xor_in = 0x0000,
+            reflect_out = True, xor_out = 0x0000)
+    print("{0:#x}".format(crc.bit_by_bit("123456789")))
+    print("{0:#x}".format(crc.bit_by_bit_fast("123456789")))
+    print("{0:#x}".format(crc.table_driven("123456789")))
+"""
+
+class Crc(object):
+    """
+    A base class for CRC routines.
+    """
+    # pylint: disable=too-many-instance-attributes
+
+    def __init__(self, width, poly, reflect_in, xor_in, reflect_out, xor_out, table_idx_width=None, slice_by=1):
+        """The Crc constructor.
+
+        The parameters are as follows:
+            width
+            poly
+            reflect_in
+            xor_in
+            reflect_out
+            xor_out
+        """
+        # pylint: disable=too-many-arguments
+
+        self.width = width
+        self.poly = poly
+        self.reflect_in = reflect_in
+        self.xor_in = xor_in
+        self.reflect_out = reflect_out
+        self.xor_out = xor_out
+        self.tbl_idx_width = table_idx_width
+        self.slice_by = slice_by
+
+        self.msb_mask = 0x1 << (self.width - 1)
+        self.mask = ((self.msb_mask - 1) << 1) | 1
+        if self.tbl_idx_width != None:
+            self.tbl_width = 1 << self.tbl_idx_width
+        else:
+            self.tbl_idx_width = 8
+            self.tbl_width = 1 << self.tbl_idx_width
+
+        self.direct_init = self.xor_in
+        self.nondirect_init = self.__get_nondirect_init(self.xor_in)
+        if self.width < 8:
+            self.crc_shift = 8 - self.width
+        else:
+            self.crc_shift = 0
+
+
+    def __get_nondirect_init(self, init):
+        """
+        return the non-direct init if the direct algorithm has been selected.
+        """
+        crc = init
+        for dummy_i in range(self.width):
+            bit = crc & 0x01
+            if bit:
+                crc ^= self.poly
+            crc >>= 1
+            if bit:
+                crc |= self.msb_mask
+        return crc & self.mask
+
+
+    def reflect(self, data, width):
+        """
+        reflect a data word, i.e. reverts the bit order.
+        """
+        # pylint: disable=no-self-use
+
+        res = data & 0x01
+        for dummy_i in range(width - 1):
+            data >>= 1
+            res = (res << 1) | (data & 0x01)
+        return res
+
+
+    def bit_by_bit(self, in_data):
+        """
+        Classic simple and slow CRC implementation.  This function iterates bit
+        by bit over the augmented input message and returns the calculated CRC
+        value at the end.
+        """
+        # If the input data is a string, convert to bytes.
+        if isinstance(in_data, str):
+            in_data = bytearray(in_data, 'utf-8')
+
+        reg = self.nondirect_init
+        for octet in in_data:
+            if self.reflect_in:
+                octet = self.reflect(octet, 8)
+            for i in range(8):
+                topbit = reg & self.msb_mask
+                reg = ((reg << 1) & self.mask) | ((octet >> (7 - i)) & 0x01)
+                if topbit:
+                    reg ^= self.poly
+
+        for i in range(self.width):
+            topbit = reg & self.msb_mask
+            reg = ((reg << 1) & self.mask)
+            if topbit:
+                reg ^= self.poly
+
+        if self.reflect_out:
+            reg = self.reflect(reg, self.width)
+        return (reg ^ self.xor_out) & self.mask
+
+
+    def bit_by_bit_fast(self, in_data):
+        """
+        This is a slightly modified version of the bit-by-bit algorithm: it
+        does not need to loop over the augmented bits, i.e. the Width 0-bits
+        wich are appended to the input message in the bit-by-bit algorithm.
+        """
+        # If the input data is a string, convert to bytes.
+        if isinstance(in_data, str):
+            in_data = bytearray(in_data, 'utf-8')
+
+        reg = self.direct_init
+        for octet in in_data:
+            if self.reflect_in:
+                octet = self.reflect(octet, 8)
+            for i in range(8):
+                topbit = reg & self.msb_mask
+                if octet & (0x80 >> i):
+                    topbit ^= self.msb_mask
+                reg <<= 1
+                if topbit:
+                    reg ^= self.poly
+            reg &= self.mask
+        if self.reflect_out:
+            reg = self.reflect(reg, self.width)
+        return reg ^ self.xor_out
+
+
+    def gen_table(self):
+        """
+        This function generates the CRC table used for the table_driven CRC
+        algorithm.  The Python version cannot handle tables of an index width
+        other than 8.  See the generated C code for tables with different sizes
+        instead.
+        """
+        table_length = 1 << self.tbl_idx_width
+        tbl = [[0 for i in range(table_length)] for j in range(self.slice_by)]
+        for i in range(table_length):
+            reg = i
+            if self.reflect_in:
+                reg = self.reflect(reg, self.tbl_idx_width)
+            reg = reg << (self.width - self.tbl_idx_width + self.crc_shift)
+            for dummy_j in range(self.tbl_idx_width):
+                if reg & (self.msb_mask << self.crc_shift) != 0:
+                    reg = (reg << 1) ^ (self.poly << self.crc_shift)
+                else:
+                    reg = (reg << 1)
+            if self.reflect_in:
+                reg = self.reflect(reg >> self.crc_shift, self.width) << self.crc_shift
+            tbl[0][i] = (reg >> self.crc_shift) & self.mask
+
+        for j in range(1, self.slice_by):
+            for i in range(table_length):
+                tbl[j][i] = (tbl[j - 1][i] >> 8) ^ tbl[0][tbl[j - 1][i] & 0xff]
+        return tbl
+
+
+    def table_driven(self, in_data):
+        """
+        The Standard table_driven CRC algorithm.
+        """
+        # pylint: disable = line-too-long
+
+        # If the input data is a string, convert to bytes.
+        if isinstance(in_data, str):
+            in_data = bytearray(in_data, 'utf-8')
+
+        tbl = self.gen_table()
+
+        if not self.reflect_in:
+            reg = self.direct_init << self.crc_shift
+            for octet in in_data:
+                tblidx = ((reg >> (self.width - self.tbl_idx_width + self.crc_shift)) ^ octet) & 0xff
+                reg = ((reg << (self.tbl_idx_width - self.crc_shift)) ^ (tbl[0][tblidx] << self.crc_shift)) & (self.mask << self.crc_shift)
+            reg = reg >> self.crc_shift
+        else:
+            reg = self.reflect(self.direct_init, self.width)
+            for octet in in_data:
+                tblidx = (reg ^ octet) & 0xff
+                reg = ((reg >> self.tbl_idx_width) ^ tbl[0][tblidx]) & self.mask
+            reg = self.reflect(reg, self.width) & self.mask
+
+        if self.reflect_out:
+            reg = self.reflect(reg, self.width)
+        return reg ^ self.xor_out
+
diff --git a/pycrc/codegen.py b/pycrc/codegen.py
new file mode 100644
index 0000000..4079cc0
--- /dev/null
+++ b/pycrc/codegen.py
@@ -0,0 +1,1559 @@
+#  pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+#  Copyright (c) 2017  Thomas Pircher  <tehpeh-web@tty1.net>
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to
+#  deal in the Software without restriction, including without limitation the
+#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+#  sell copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+#  IN THE SOFTWARE.
+
+
+"""
+use as follows:
+
+    import pycrc.codegen as cg
+    import pycrc.opt as opt
+    opt = opt.Options()
+    print(cg.CodeGen(opt, '', [
+        'if (a == b) {',
+        cg.CodeGen(opt, 4*' ', ['print("a equals b\\n");']),
+        '}',
+        ]))
+"""
+
+import pycrc.symtable
+import pycrc.expr as expr
+
+
+class CodeGen(object):
+    """
+    The symbol table class.
+    """
+    def __init__(self, opt, indent, content = []):
+        """
+        The class constructor.
+        """
+        self.opt = opt
+        self.sym = pycrc.symtable.SymbolTable(opt)
+        self.indent = indent
+        self.content = content
+
+    def gen(self, indent = ''):
+        """
+        Return an array of strings.
+        """
+        out = []
+        if self.indent is None:
+            indent = ''
+        else:
+            indent += self.indent
+        for item in self.content:
+            if isinstance(item, str):
+                out.append(indent + item)
+            else:
+                out += item.gen(indent)
+        return out
+
+    def __str__(self):
+        """
+        Stringify the object.
+        """
+        return '\n'.join([l.rstrip() for l in self.gen()])
+
+
+class Conditional(CodeGen):
+    """
+    A conditional block of code.
+    """
+    def __init__(self, opt, indent, condition, content):
+        """
+        The class constructor.
+        """
+        super(Conditional, self).__init__(opt, indent)
+        if condition:
+            self.content = content
+
+
+class Conditional2(CodeGen):
+    """
+    A conditional block of code with an else block.
+    """
+    def __init__(self, opt, indent, condition, content_true, content_false):
+        """
+        The class constructor.
+        """
+        super(Conditional2, self).__init__(opt, indent)
+        if condition:
+            self.content = content_true
+        else:
+            self.content = content_false
+
+
+class Comment(CodeGen):
+    """
+    A comment wrapper.
+    """
+    def __init__(self, opt, indent, content):
+        """
+        The class constructor.
+        """
+        super(Comment, self).__init__(opt, indent)
+        self.content = [
+                '/**',
+                CodeGen(opt, indent + ' * ', content),
+                ' */'
+                ]
+
+
+class ParamBlock(CodeGen):
+    """
+    Print the parameters of the model.
+    """
+    def __init__(self, opt, indent, algorithm = False):
+        """
+        The class constructor.
+        """
+        super(ParamBlock, self).__init__(opt, indent)
+        self.content = [
+                '- {0:13s} = {1}'.format('Width', self.sym['crc_width']),
+                '- {0:13s} = {1}'.format('Poly', self.sym['crc_poly']),
+                '- {0:13s} = {1}'.format('XorIn', self.sym['crc_xor_in']),
+                '- {0:13s} = {1}'.format('ReflectIn', self.sym['crc_reflect_in']),
+                '- {0:13s} = {1}'.format('XorOut', self.sym['crc_xor_out']),
+                '- {0:13s} = {1}'.format('ReflectOut', self.sym['crc_reflect_out']),
+                Conditional(opt, '', algorithm,
+                    ['- {0:13s} = {1}'.format('Algorithm', self.sym['crc_algorithm'])]),
+                Conditional(opt, '', opt.slice_by > 1,
+                    ['- {0:13s} = {1}'.format('SliceBy', opt.slice_by)]),
+                ]
+
+
+
+class File(CodeGen):
+    """
+    Generate the file output.
+    """
+    def __init__(self, opt, indent):
+        """
+        The class constructor.
+        """
+        super(File, self).__init__(opt, indent)
+        self.content = [
+                Comment(opt, '', [
+                    '\\file',
+                    'Functions and types for CRC checks.',
+                    '',
+                    'Generated on {datetime}'.format(**self.sym),
+                    'by {program_version}, {program_url}'.format(**self.sym),
+                    'using the configuration:',
+                    ParamBlock(opt, ' ', algorithm = True),
+                    Conditional(opt, '', opt.action == opt.action_generate_h, [
+                        '',
+                        'This file defines the functions {crc_init_function}(), ' \
+                                '{crc_update_function}() and {crc_finalize_function}().'.format(**self.sym),
+                        '',
+                        'The {crc_init_function}() function returns the inital \c crc value and must be called'.format(**self.sym),
+                        'before the first call to {crc_update_function}().'.format(**self.sym),
+                        'Similarly, the {crc_finalize_function}() function must be called after the last call'.format(**self.sym),
+                        'to {crc_update_function}(), before the \c crc is being used.'.format(**self.sym),
+                        'is being used.',
+                        '',
+                        'The {crc_update_function}() function can be called any number of times (including zero'.format(**self.sym),
+                        'times) in between the {crc_init_function}() and {crc_finalize_function}() calls.'.format(**self.sym),
+                        '',
+                        'This pseudo-code shows an example usage of the API:',
+                        '\code{.c}',
+                        Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
+                            '{cfg_t} cfg = '.format(**self.sym) + '{',
+                            Conditional(self.opt, 4*' ', self.opt.width is None, [
+                                '0,      // width',
+                                ]),
+                            Conditional(self.opt, 4*' ', self.opt.poly is None, [
+                                '0,      // poly',
+                                ]),
+                            Conditional(self.opt, 4*' ', self.opt.reflect_in is None, [
+                                '0,      // reflect_in',
+                                ]),
+                            Conditional(self.opt, 4*' ', self.opt.xor_in is None, [
+                                '0,      // xor_in',
+                                ]),
+                            Conditional(self.opt, 4*' ', self.opt.reflect_out is None, [
+                                '0,      // reflect_out',
+                                ]),
+                            Conditional(self.opt, 4*' ', self.opt.xor_out is None, [
+                                '0,      // xor_out',
+                                ]),
+                            Conditional(self.opt, 4*' ', self.opt.width is None, [
+                                '',
+                                '0,      // crc_mask',
+                                '0,      // msb_mask',
+                                '0,      // crc_shift',
+                                ]),
+                            '};',
+                            ]),
+                        '{crc_t} crc;'.format(**self.sym),
+                        'unsigned char data[MAX_DATA_LEN];',
+                        'size_t data_len;',
+                        '',
+                        Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
+                            '{crc_table_gen_function}(&cfg);'.format(**self.sym),
+                            ]),
+                        'crc = {0}({1});'.format(self.sym['crc_init_function'], '' if _use_constant_crc_init(self.sym) else '&cfg'),
+                        'while ((data_len = read_data(data, MAX_DATA_LEN)) > 0) {',
+                        CodeGen(self.opt, 4*' ', [
+                            'crc = {0}({1}crc, data, data_len);'.format(self.sym['crc_update_function'], '' if _use_cfg_in_crc_update(self.opt) else '&cfg, '),
+                            ]),
+                        '}',
+                        'crc = {0}({1}crc);'.format(self.sym['crc_finalize_function'], '' if _use_cfg_in_finalize(self.opt) else '&cfg, '),
+                        '\endcode',
+                        ]),
+                    ]),
+                ]
+        if opt.action == opt.action_generate_h:
+            self.content += self._header_file()
+        elif opt.action == opt.action_generate_c:
+            self.content += self._c_file()
+        elif opt.action == opt.action_generate_c_main:
+            self.content += self._c_file() + self._main_file()
+
+    def _header_file(self):
+        """
+        Add header content.
+        """
+        out = [
+                '#ifndef {header_protection}'.format(**self.sym),
+                '#define {header_protection}'.format(**self.sym),
+                '',
+                CodeGen(self.opt, '', _includes(self.opt)),
+                '#include <stdlib.h>',
+                Conditional(self.opt, '', self.opt.c_std != 'C89',
+                    ['#include <stdint.h>']),
+                Conditional(self.opt, '', _use_cfg(self.opt) and self.opt.c_std != 'C89',
+                    ['#include <stdbool.h>']),
+                '',
+                '#ifdef __cplusplus',
+                'extern "C" {',
+                '#endif',
+                '', '',
+                Comment(self.opt, '', [
+                    'The definition of the used algorithm.',
+                    '',
+                    'This is not used anywhere in the generated code, but it may be used by the',
+                    'application code to call algorithm-specific code, if desired.',
+                    ]),
+                '#define {0} 1'.format(_crc_algo_define(self.opt, self.sym)),
+                '', '',
+                Comment(self.opt, self.indent, [
+                    'The type of the CRC values.',
+                    '',
+                    'This type must be big enough to contain at least {cfg_width} bits.'.format(**self.sym),
+                    ]),
+                'typedef {underlying_crc_t} {crc_t};'.format(**self.sym),
+                Conditional(self.opt, '', _use_cfg(self.opt), [
+                    '', '',
+                    Comment(self.opt, self.indent, ['The configuration type of the CRC algorithm.']),
+                    'typedef struct {',
+                    Conditional(self.opt, 4*' ', self.opt.width is None,
+                        ['{0:24s}    {1}'.format('unsigned int width;',
+                            '/*!< The width of the polynomial */')]),
+                    Conditional(self.opt, 4*' ', self.opt.poly is None,
+                        ['{0:24s}    {1}'.format(self.sym['crc_t'] + ' poly;',
+                            '/*!< The CRC polynomial */')]),
+                    Conditional(self.opt, 4*' ', self.opt.reflect_in is None,
+                        ['{0:24s}    {1}'.format(self.sym['c_bool'] + ' reflect_in;',
+                            '/*!< Whether the input shall be reflected or not */')]),
+                    Conditional(self.opt, 4*' ', self.opt.xor_in is None,
+                        ['{0:24s}    {1}'.format(self.sym['crc_t'] + ' xor_in;',
+                            '/*!< The initial value of the register */')]),
+                    Conditional(self.opt, 4*' ', self.opt.reflect_out is None,
+                        ['{0:24s}    {1}'.format(self.sym['c_bool'] + ' reflect_out;',
+                            '/*!< Whether the output shall be reflected or not */')]),
+                    Conditional(self.opt, 4*' ', self.opt.xor_out is None,
+                        ['{0:24s}    {1}'.format(self.sym['crc_t'] + ' xor_out;',
+                            '/*!< The value which shall be XOR-ed to the final CRC value */')]),
+                    Conditional(self.opt, 4*' ', self.opt.width is None, [
+                        '',
+                        '/* internal parameters */',
+                        '{0:24s}    {1}'.format(self.sym['crc_t'] + ' msb_mask;', '/*!< a bitmask with the Most Significant Bit set to 1'),
+                        33*' ' + 'initialise as (crc_t)1u << (width - 1) */',
+                        '{0:24s}    {1}'.format(self.sym['crc_t'] + ' crc_mask;', '/*!< a bitmask with all width bits set to 1'),
+                        33*' ' + 'initialise as (cfg->msb_mask - 1) | cfg->msb_mask */',
+                        '{0:24s}    {1}'.format('unsigned int crc_shift;', '/*!< a shift count that is used when width < 8'),
+                        33*' ' + 'initialise as cfg->width < 8 ? 8 - cfg->width : 0 */',
+                        ]),
+                    '}} {cfg_t};'.format(**self.sym),
+                    ]),
+                Conditional(self.opt, '', _use_reflect_func(self.opt) and not _use_static_reflect_func(self.opt), [
+                    '', '',
+                    Comment(self.opt, '', [
+                        'Reflect all bits of a \\a data word of \\a data_len bytes.',
+                        '',
+                        '\\param[in] data     The data word to be reflected.',
+                        '\\param[in] data_len The width of \\a data expressed in number of bits.',
+                        '\\return             The reflected data.'
+                        ]),
+                    '{crc_t} {crc_reflect_function}({crc_t} data, size_t data_len);'.format(**self.sym),
+                    ]),
+                Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
+                    '', '',
+                    Comment(self.opt, '', [
+                        'Populate the private static crc table.',
+                        '',
+                        '\\param[in] cfg  A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+                        ]),
+                    'void {crc_table_gen_function}(const {cfg_t} *cfg);'.format(**self.sym),
+                    ]),
+                '', '',
+                Comment(self.opt, '', [
+                    'Calculate the initial crc value.',
+                    '',
+                    Conditional(self.opt, '', _use_cfg(self.opt), [
+                        '\\param[in] cfg  A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+                        ]),
+                    '\\return     The initial crc value.',
+                    ]),
+                Conditional2(self.opt, '', _use_constant_crc_init(self.sym), [
+                    Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+                        '#define {crc_init_function}()      ({crc_init_value})'.format(**self.sym),
+                        ], [
+                        'static inline {0}'.format(_crc_init_function_def(self.opt, self.sym)),
+                        '{',
+                        '    return {crc_init_value};'.format(**self.sym),
+                        '}',
+                        ]),
+                    ], [
+                    '{0};'.format(_crc_init_function_def(self.opt, self.sym)),
+                    ]),
+                '', '',
+                Comment(self.opt, '', [
+                    'Update the crc value with new data.',
+                    '',
+                    '\\param[in] crc      The current crc value.',
+                    Conditional(self.opt, '', not _use_cfg_in_crc_update(self.opt), [
+                        '\\param[in] cfg      A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+                        ]),
+                    '\\param[in] data     Pointer to a buffer of \\a data_len bytes.',
+                    '\\param[in] data_len Number of bytes in the \\a data buffer.',
+                    '\\return             The updated crc value.',
+                    ]),
+                '{0};'.format(_crc_update_function_def(self.opt, self.sym)),
+                '', '',
+                Comment(self.opt, '', [
+                    'Calculate the final crc value.',
+                    '',
+                    Conditional(self.opt, '', not _use_cfg_in_finalize(self.opt), [
+                        '\\param[in] cfg  A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+                        ]),
+                    '\\param[in] crc  The current crc value.',
+                    '\\return     The final crc value.',
+                    ]),
+                Conditional2(self.opt, '', _use_inline_crc_finalize(self.opt), [
+                    Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+                        '#define {0}(crc)      ({1})'.format(self.sym['crc_finalize_function'], _crc_final_value(self.opt, self.sym)),
+                        ], [
+                        'static inline {0}'.format(_crc_finalize_function_def(self.opt, self.sym)),
+                        '{',
+                        '    return {0};'.format(_crc_final_value(self.opt, self.sym)),
+                        '}',
+                        ]),
+                    ], [
+                    '{0};'.format(_crc_finalize_function_def(self.opt, self.sym)),
+                    ]),
+                '', '',
+                '#ifdef __cplusplus',
+                '}           /* closing brace for extern "C" */',
+                '#endif',
+                '',
+                '#endif      /* {header_protection} */'.format(**self.sym),
+                '',
+                ]
+        return out
+
+    def _c_file(self):
+        """
+        Add C file content.
+        """
+        out = [
+                CodeGen(self.opt, '', _includes(self.opt)),
+                '#include "{header_filename}"     /* include the header file generated with pycrc */'.format(**self.sym),
+                '#include <stdlib.h>',
+                Conditional(self.opt, '', self.opt.c_std != 'C89', [
+                    '#include <stdint.h>',
+                    Conditional(self.opt, '', self.opt.undefined_crc_parameters or \
+                            self.opt.algorithm == self.opt.algo_bit_by_bit or \
+                            self.opt.algorithm == self.opt.algo_bit_by_bit_fast, [
+                        '#include <stdbool.h>',
+                        ]),
+                    ]),
+                Conditional(self.opt, '', self.opt.slice_by > 1, [
+                    '#include <endian.h>',
+                    ]),
+                Conditional(self.opt, '', _use_reflect_func(self.opt) and _use_static_reflect_func(self.opt), [
+                    '',
+                    'static {crc_t} {crc_reflect_function}({crc_t} data, size_t data_len);'.format(**self.sym),
+                    ]),
+                '',
+                CodeGen(self.opt, '', _crc_table(self.opt, self.sym)),
+                CodeGen(self.opt, '', _crc_reflect_function_gen(self.opt, self.sym)),
+                CodeGen(self.opt, '', _crc_init_function_gen(self.opt, self.sym)),
+                CodeGen(self.opt, '', _crc_table_gen(self.opt, self.sym)),
+                CodeGen(self.opt, '', _crc_update_function_gen(self.opt, self.sym)),
+                CodeGen(self.opt, '', _crc_finalize_function_gen(self.opt, self.sym)),
+                '',
+                ]
+        return out
+
+    def _main_file(self):
+        """
+        Add main file content.
+        """
+        out = [
+                '',
+                '',
+                CodeGen(self.opt, '', _includes(self.opt)),
+                '#include <stdio.h>',
+                '#include <getopt.h>',
+                Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
+                    '#include <stdlib.h>',
+                    '#include <stdio.h>',
+                    '#include <ctype.h>',
+                    ]),
+                Conditional(self.opt, '', self.opt.c_std != 'C89', [
+                    '#include <stdbool.h>',
+                ]),
+                '#include <string.h>',
+                '',
+                'static char str[256] = "123456789";',
+                'static {c_bool} verbose = {c_false};'.format(**self.sym),
+                self._getopt_template(),
+                '',
+                '',
+                Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
+                    'static void print_params(const {cfg_t} *cfg)'.format(**self.sym),
+                    ], [
+                    'static void print_params(void)',
+                    ]),
+                '{',
+                CodeGen(self.opt, 4*' ', [
+                    'char format[20];',
+                    '',
+                    Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+                        'sprintf(format, "%%-16s = 0x%%0%dlx\\n", (unsigned int)({cfg_width} + 3) / 4);'.format(**self.sym),
+                        'printf("%-16s = %d\\n", "width", (unsigned int){cfg_width});'.format(**self.sym),
+                        'printf(format, "poly", (unsigned long int){cfg_poly});'.format(**self.sym),
+                        'printf("%-16s = %s\\n", "reflect_in", {0});'.format(self.sym['cfg_reflect_in'] + ' ? "true": "false"' if self.opt.reflect_in is None else ('"true"' if self.opt.reflect_in else '"false"')),
+                        'printf(format, "xor_in", (unsigned long int){cfg_xor_in});'.format(**self.sym),
+                        'printf("%-16s = %s\\n", "reflect_out", {0});'.format(self.sym['cfg_reflect_out'] + ' ? "true": "false"' if self.opt.reflect_out is None else ('"true"' if self.opt.reflect_out else '"false"')),
+                        'printf(format, "xor_out", (unsigned long int){cfg_xor_out});'.format(**self.sym),
+                        'printf(format, "crc_mask", (unsigned long int){cfg_mask});'.format(**self.sym),
+                        'printf(format, "msb_mask", (unsigned long int){cfg_msb_mask});'.format(**self.sym),
+                        ], [
+                        'snprintf(format, sizeof(format), "%%-16s = 0x%%0%dllx\\n", (unsigned int)({cfg_width} + 3) / 4);'.format(**self.sym),
+                        'printf("%-16s = %d\\n", "width", (unsigned int){cfg_width});'.format(**self.sym),
+                        'printf(format, "poly", (unsigned long long int){cfg_poly});'.format(**self.sym),
+                        'printf("%-16s = %s\\n", "reflect_in", {0});'.format(self.sym['cfg_reflect_in'] + ' ? "true": "false"' if self.opt.reflect_in is None else ('"true"' if self.opt.reflect_in else '"false"')),
+                        'printf(format, "xor_in", (unsigned long long int){cfg_xor_in});'.format(**self.sym),
+                        'printf("%-16s = %s\\n", "reflect_out", {0});'.format(self.sym['cfg_reflect_out'] + ' ? "true": "false"' if self.opt.reflect_out is None else ('"true"' if self.opt.reflect_out else '"false"')),
+                        'printf(format, "xor_out", (unsigned long long int){cfg_xor_out});'.format(**self.sym),
+                        'printf(format, "crc_mask", (unsigned long long int){cfg_mask});'.format(**self.sym),
+                        'printf(format, "msb_mask", (unsigned long long int){cfg_msb_mask});'.format(**self.sym),
+                        ]),
+                    ]),
+                '}',
+                '',
+                '',
+                Comment(self.opt, '', [
+                    'C main function.',
+                    '\\param[in] argc the number of arguments in \\a argv.',
+                    '\\param[in] argv a NULL-terminated array of pointers to the argument strings.',
+                    '\\retval 0 on success.',
+                    '\\retval >0 on error.',
+                    ]),
+                'int main(int argc, char *argv[])',
+                '{',
+                CodeGen(self.opt, 4*' ', [
+                    Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
+                        '{cfg_t} cfg = '.format(**self.sym) + '{',
+                        Conditional(self.opt, 4*' ', self.opt.width is None, [
+                            '0,      /* width */',
+                            ]),
+                        Conditional(self.opt, 4*' ', self.opt.poly is None, [
+                            '0,      /* poly */',
+                            ]),
+                        Conditional(self.opt, 4*' ', self.opt.reflect_in is None, [
+                            '0,      /* reflect_in */',
+                            ]),
+                        Conditional(self.opt, 4*' ', self.opt.xor_in is None, [
+                            '0,      /* xor_in */',
+                            ]),
+                        Conditional(self.opt, 4*' ', self.opt.reflect_out is None, [
+                            '0,      /* reflect_out */',
+                            ]),
+                        Conditional(self.opt, 4*' ', self.opt.xor_out is None, [
+                            '0,      /* xor_out */',
+                            ]),
+                        Conditional(self.opt, 4*' ', self.opt.width is None, [
+                            '',
+                            '0,      /* crc_mask */',
+                            '0,      /* msb_mask */',
+                            '0,      /* crc_shift */',
+                            ]),
+                        '};',
+                        ]),
+                    '{crc_t} crc;'.format(**self.sym),
+                    '',
+                    Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
+                        'get_config(argc, argv, &cfg);',
+                        ], [
+                        'get_config(argc, argv);',
+                        ]),
+                    Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
+                        '{crc_table_gen_function}(&cfg);'.format(**self.sym),
+                        ]),
+                    'crc = {0}({1});'.format(self.sym['crc_init_function'], '' if _use_constant_crc_init(self.sym) else '&cfg'),
+                    'crc = {0}({1}crc, (void *)str, strlen(str));'.format(self.sym['crc_update_function'], '' if _use_cfg_in_crc_update(self.opt) else '&cfg, '),
+                    'crc = {0}({1}crc);'.format(self.sym['crc_finalize_function'], '' if _use_cfg_in_finalize(self.opt) else '&cfg, '),
+                    '',
+                    'if (verbose) {',
+                    CodeGen(self.opt, 4*' ', [
+                        'print_params({0});'.format('&cfg' if self.opt.undefined_crc_parameters else ''),
+                        ]),
+                    '}',
+                    Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+                        'printf("0x%lx\\n", (unsigned long int)crc);',
+                        ], [
+                        'printf("0x%llx\\n", (unsigned long long int)crc);',
+                        ]),
+                    'return 0;',
+                    ]),
+                '}',
+                ]
+        return out
+
+    def _getopt_template(self):
+        """
+        Add getopt functions.
+        """
+        out = [
+                Conditional(self.opt, '', self.opt.reflect_in is None or self.opt.reflect_out is None, [
+                    '',
+                    '',
+                    'static {c_bool} atob(const char *str)'.format(**self.sym),
+                    '{',
+                    CodeGen(self.opt, 4*' ', [
+                        'if (!str) {',
+                        CodeGen(self.opt, 4*' ', [
+                            'return 0;',
+                            ]),
+                        '}',
+                        'if (isdigit(str[0])) {',
+                        CodeGen(self.opt, 4*' ', [
+                            'return ({c_bool})atoi(str);'.format(**self.sym),
+                            ]),
+                        '}',
+                        'if (tolower(str[0]) == \'t\') {',
+                        CodeGen(self.opt, 4*' ', [
+                            'return {c_true};'.format(**self.sym),
+                            ]),
+                        '}',
+                        'return {c_false};'.format(**self.sym),
+                        ]),
+                    '}',
+                    ]),
+                Conditional(self.opt, '', self.opt.poly is None or self.opt.xor_in is None or self.opt.xor_out is None, [
+                    '',
+                    '',
+                    'static crc_t xtoi(const char *str)',
+                    '{',
+                    CodeGen(self.opt, 4*' ', [
+                        'crc_t ret = 0;',
+                        '',
+                        'if (!str) {',
+                        CodeGen(self.opt, 4*' ', [
+                            'return 0;',
+                            ]),
+                        '}',
+                        'if (str[0] == \'0\' && tolower(str[1]) == \'x\') {',
+                        CodeGen(self.opt, 4*' ', [
+                            'str += 2;',
+                            'while (*str) {',
+                            CodeGen(self.opt, 4*' ', [
+                                'if (isdigit(*str))',
+                                CodeGen(self.opt, 4*' ', [
+                                    'ret = 16 * ret + *str - \'0\';',
+                                    ]),
+                                'else if (isxdigit(*str))',
+                                CodeGen(self.opt, 4*' ', [
+                                    'ret = 16 * ret + tolower(*str) - \'a\' + 10;',
+                                    ]),
+                                'else',
+                                CodeGen(self.opt, 4*' ', [
+                                    'return ret;',
+                                    ]),
+                                'str++;',
+                                ]),
+                            '}',
+                            ]),
+                        '} else if (isdigit(*str)) {',
+                        CodeGen(self.opt, 4*' ', [
+                            'while (*str) {',
+                            CodeGen(self.opt, 4*' ', [
+                                'if (isdigit(*str))',
+                                CodeGen(self.opt, 4*' ', [
+                                    'ret = 10 * ret + *str - \'0\';',
+                                    ]),
+                                'else',
+                                CodeGen(self.opt, 4*' ', [
+                                    'return ret;',
+                                    ]),
+                                'str++;',
+                                ]),
+                            '}',
+                            ]),
+                        '}',
+                        'return ret;',
+                        ]),
+                    '}',
+                    ]),
+                    '',
+                    '',
+                Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
+                    'static int get_config(int argc, char *argv[], {cfg_t} *cfg)'.format(**self.sym),
+                    ], [
+                    'static int get_config(int argc, char *argv[])',
+                    ]),
+                    '{',
+                    CodeGen(self.opt, 4*' ', [
+                        'int c;',
+                        'int option_index;',
+                        'static struct option long_options[] = {',
+                        CodeGen(self.opt, 4*' ', [
+                            Conditional(self.opt, '', self.opt.width is None, [
+                                '{"width",           1, 0, \'w\'},',
+                                ]),
+                            Conditional(self.opt, '', self.opt.poly is None, [
+                                '{"poly",            1, 0, \'p\'},',
+                                ]),
+                            Conditional(self.opt, '', self.opt.reflect_in is None, [
+                                '{"reflect-in",      1, 0, \'n\'},',
+                                ]),
+                            Conditional(self.opt, '', self.opt.xor_in is None, [
+                                '{"xor-in",          1, 0, \'i\'},',
+                                ]),
+                            Conditional(self.opt, '', self.opt.reflect_out is None, [
+                                '{"reflect-out",     1, 0, \'u\'},',
+                                ]),
+                            Conditional(self.opt, '', self.opt.xor_out is None, [
+                                '{"xor-out",         1, 0, \'o\'},',
+                                ]),
+                            '{"verbose",         0, 0, \'v\'},',
+                            '{"check-string",    1, 0, \'s\'},',
+                            Conditional(self.opt, '', self.opt.width is None, [
+                                '{"table-idx-with",  1, 0, \'t\'},',
+                                ]),
+                            '{0, 0, 0, 0}',
+                        ]),
+                        '};',
+                        '',
+                        'while (1) {',
+                        CodeGen(self.opt, 4*' ', [
+                            'option_index = 0;',
+                            '',
+                            'c = getopt_long(argc, argv, "w:p:n:i:u:o:s:vt", long_options, &option_index);',
+                            'if (c == -1)',
+                            CodeGen(self.opt, 4*' ', [
+                                'break;',
+                                ]),
+                            '',
+                            'switch (c) {',
+                            CodeGen(self.opt, 4*' ', [
+                                'case 0:',
+                                CodeGen(self.opt, 4*' ', [
+                                    'printf("option %s", long_options[option_index].name);',
+                                    'if (optarg)',
+                                    CodeGen(self.opt, 4*' ', [
+                                        'printf(" with arg %s", optarg);',
+                                        ]),
+                                    'printf("\\n");',
+                                    'break;',
+                                    ]),
+                                Conditional(self.opt, '', self.opt.width is None, [
+                                    'case \'w\':',
+                                    CodeGen(self.opt, 4*' ', [
+                                        'cfg->width = atoi(optarg);',
+                                        'break;',
+                                        ]),
+                                    ]),
+                                Conditional(self.opt, '', self.opt.poly is None, [
+                                    'case \'p\':',
+                                    CodeGen(self.opt, 4*' ', [
+                                        'cfg->poly = xtoi(optarg);',
+                                        'break;',
+                                        ]),
+                                    ]),
+                                Conditional(self.opt, '', self.opt.reflect_in is None, [
+                                    'case \'n\':',
+                                    CodeGen(self.opt, 4*' ', [
+                                        'cfg->reflect_in = atob(optarg);',
+                                        'break;',
+                                        ]),
+                                    ]),
+                                Conditional(self.opt, '', self.opt.xor_in is None, [
+                                    'case \'i\':',
+                                    CodeGen(self.opt, 4*' ', [
+                                        'cfg->xor_in = xtoi(optarg);',
+                                        'break;',
+                                        ]),
+                                    ]),
+                                Conditional(self.opt, '', self.opt.reflect_out is None, [
+                                    'case \'u\':',
+                                    CodeGen(self.opt, 4*' ', [
+                                        'cfg->reflect_out = atob(optarg);',
+                                        'break;',
+                                        ]),
+                                    ]),
+                                Conditional(self.opt, '', self.opt.xor_out is None, [
+                                    'case \'o\':',
+                                    CodeGen(self.opt, 4*' ', [
+                                            'cfg->xor_out = xtoi(optarg);',
+                                            'break;',
+                                            ]),
+                                    ]),
+                                'case \'s\':',
+                                CodeGen(self.opt, 4*' ', [
+                                    'memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str));',
+                                    'str[sizeof(str) - 1] = \'\\0\';',
+                                    'break;',
+                                    ]),
+                                'case \'v\':',
+                                CodeGen(self.opt, 4*' ', [
+                                    'verbose = {c_true};'.format(**self.sym),
+                                    'break;',
+                                    ]),
+                                Conditional(self.opt, '', self.opt.width is None, [
+                                    'case \'t\':',
+                                    CodeGen(self.opt, 4*' ', [
+                                        '/* ignore --table_idx_width option */',
+                                        'break;',
+                                        ]),
+                                    ]),
+                                'case \'?\':',
+                                CodeGen(self.opt, 4*' ', [
+                                    'return -1;',
+                                    ]),
+                                'case \':\':',
+                                CodeGen(self.opt, 4*' ', [
+                                    'fprintf(stderr, "missing argument to option %c\\n", c);',
+                                    'return -1;',
+                                    ]),
+                                'default:',
+                                CodeGen(self.opt, 4*' ', [
+                                    'fprintf(stderr, "unhandled option %c\\n", c);',
+                                    'return -1;',
+                                    ]),
+                                ]),
+                            '}',
+                            ]),
+                        '}',
+                        Conditional(self.opt, '', self.opt.width is None, [
+                            'cfg->msb_mask = (crc_t)1u << (cfg->width - 1);',
+                            'cfg->crc_mask = (cfg->msb_mask - 1) | cfg->msb_mask;',
+                            'cfg->crc_shift = cfg->width < 8 ? 8 - cfg->width : 0;',
+                            ]),
+                        '',
+                        Conditional(self.opt, '', self.opt.poly is None, [
+                            'cfg->poly &= {cfg_mask};'.format(**self.sym),
+                            ]),
+                        Conditional(self.opt, '', self.opt.xor_in is None, [
+                            'cfg->xor_in &= {cfg_mask};'.format(**self.sym),
+                            ]),
+                        Conditional(self.opt, '', self.opt.xor_out is None, [
+                            'cfg->xor_out &= {cfg_mask};'.format(**self.sym),
+                            ]),
+                        'return 0;',
+                    ]),
+                '}',
+                ]
+        return CodeGen(self.opt, '', out)
+
+
+def _includes(opt):
+    """
+    Return the #include directives for the user-defined list of include files.
+    """
+    includes = []
+    if opt.include_files is not None and len(opt.include_files) > 0:
+        for include_file in opt.include_files:
+            if include_file[0] == '"' or include_file[0] == '<':
+                includes.append('#include {0}'.format(include_file))
+            else:
+                includes.append('#include "{0}"'.format(include_file))
+    return includes
+
+
+def _crc_algo_define(opt, sym):
+    """
+    Get the the identifier for header files.
+    """
+    name = sym['crc_algorithm'].upper().replace('-', '_')
+    return 'CRC_ALGO_' + name
+
+
+def _use_cfg(opt):
+    """
+    Return True if a cfg_t structure is to be used.
+    """
+    return opt.undefined_crc_parameters
+
+
+def _use_constant_crc_init(sym):
+    """
+    Return True if the inintial value is constant.
+    """
+    return sym['crc_init_value'] is not None
+
+
+def _use_reflect_func(opt):
+    """
+    Return True if the reflect function is to be used.
+    """
+    if opt.reflect_out == None or opt.reflect_in == None:
+        return True
+    elif opt.algorithm == opt.algo_table_driven:
+        if opt.reflect_in != opt.reflect_out:
+            return True
+    elif opt.algorithm == opt.algo_bit_by_bit:
+        if opt.reflect_in:
+            return True
+        if opt.reflect_out:
+            return True
+    elif opt.algorithm == opt.algo_bit_by_bit_fast:
+        if opt.reflect_in:
+            return True
+        if opt.reflect_out:
+            return True
+    return False
+
+
+def _use_static_reflect_func(opt):
+    """
+    Whether a static reflect function is to be used.
+    """
+    if opt.algorithm == opt.algo_table_driven:
+        return False
+    elif opt.reflect_out is not None and opt.algorithm == opt.algo_bit_by_bit_fast:
+        return False
+    else:
+        return True
+
+
+def _use_crc_table_gen(opt):
+    """
+    Return True if the table generator function is to be generated.
+    """
+    if opt.algorithm == opt.algo_table_driven:
+        return opt.width is None or opt.poly is None or opt.reflect_in is None
+    else:
+        return False
+
+
+def _crc_init_function_def(opt, sym):
+    """
+    The definition for the init function.
+    """
+    if _use_constant_crc_init(sym):
+        return '{crc_t} {crc_init_function}(void)'.format(**sym)
+    else:
+        return '{crc_t} {crc_init_function}(const {cfg_t} *cfg)'.format(**sym)
+
+
+def _use_cfg_in_crc_update(opt):
+    """
+    Return True if the update function uses the cfg_t parameter.
+    """
+    if opt.algorithm in set([opt.algo_bit_by_bit, opt.algo_bit_by_bit_fast]):
+        if opt.width is not None and opt.poly is not None and opt.reflect_in is not None:
+            return True
+    elif opt.algorithm == opt.algo_table_driven:
+        if opt.width is not None and opt.reflect_in is not None:
+            return True
+    return False
+
+
+def _crc_update_function_def(opt, sym):
+    """
+    The definition of the update function.
+    """
+    if _use_cfg_in_crc_update(opt):
+        return '{crc_t} {crc_update_function}({crc_t} crc, const void *data, size_t data_len)'.format(**sym)
+    else:
+        return '{crc_t} {crc_update_function}(const {cfg_t} *cfg, {crc_t} crc, const void *data, size_t data_len)'.format(**sym)
+
+
+def _use_cfg_in_finalize(opt):
+    """
+    Return True if the cfg_t parameter is used in the finalize function.
+    """
+    if opt.algorithm == opt.algo_bit_by_bit:
+        if opt.width is not None and opt.poly is not None and opt.reflect_out is not None and opt.xor_out is not None:
+            return True
+    elif opt.algorithm == opt.algo_bit_by_bit_fast:
+        if opt.width is not None and opt.reflect_out is not None and opt.xor_out is not None:
+            return True
+    elif opt.algorithm == opt.algo_table_driven:
+        if opt.width is not None and opt.reflect_in is not None and opt.reflect_out is not None and opt.xor_out is not None:
+            return True
+    return False
+
+
+def _use_inline_crc_finalize(opt):
+    """
+    Return True if the init function can be inlined.
+    """
+    if opt.algorithm in set([opt.algo_bit_by_bit_fast, opt.algo_table_driven]) and \
+            (opt.width is not None and opt.reflect_in is not None and opt.reflect_out is not None and opt.xor_out is not None):
+        return True
+    else:
+        return False
+
+
+def _use_constant_crc_table(opt):
+    """
+    Return True is the CRC table is constant.
+    """
+    if opt.width is not None and opt.poly is not None and opt.reflect_in is not None:
+        return True
+    else:
+        return False
+
+
+def _crc_finalize_function_def(opt, sym):
+    """
+    The definition of the finalize function.
+    """
+    if _use_cfg_in_finalize(opt):
+        return '{crc_t} {crc_finalize_function}({crc_t} crc)'.format(**sym)
+    else:
+        return '{crc_t} {crc_finalize_function}(const {cfg_t} *cfg, {crc_t} crc)'.format(**sym)
+
+
+def _crc_final_value(opt, sym):
+    """
+    The return value for the finalize function.
+    """
+    if opt.algorithm == opt.algo_table_driven:
+        if opt.reflect_in == opt.reflect_out:
+            return expr.Xor('crc', sym['crc_xor_out']).simplify()
+        else:
+            reflect_fun = expr.FunctionCall(sym['crc_reflect_function'], ['crc', sym['crc_width']])
+            return expr.Xor(reflect_fun, sym['crc_xor_out']).simplify()
+    elif opt.reflect_out:
+        reflect_fun = expr.FunctionCall(sym['crc_reflect_function'], ['crc', sym['crc_width']])
+        return expr.Xor(reflect_fun, sym['crc_xor_out']).simplify()
+    else:
+        return expr.Xor('crc', sym['crc_xor_out']).simplify()
+
+
+def _crc_table(opt, sym):
+    """
+    Return the code for the CRC table or the generator function.
+    """
+    if opt.algorithm != opt.algo_table_driven:
+        return []
+    return [
+            '', '',
+            Comment(opt, '', [
+                'Static table used for the table_driven implementation.',
+                Conditional(opt, '', opt.undefined_crc_parameters, [
+                    'Must be initialised with the {crc_table_gen_function} function.'.format(**sym),
+                    ]),
+                ]),
+            Conditional2(opt, '', _use_constant_crc_table(opt), [
+                Conditional2(opt, '', opt.slice_by > 1, [
+                    'static const {crc_t} crc_table[{crc_slice_by}][{crc_table_width}] = {crc_table_init};'.format(**sym),
+                    ], [
+                    'static const {crc_t} crc_table[{crc_table_width}] = {crc_table_init};'.format(**sym),
+                    ]),
+                ], [
+                'static {crc_t} crc_table[{crc_table_width}];'.format(**sym),
+                ]),
+            ]
+
+
+def _crc_table_gen(opt, sym):
+    """
+    Return the code for the CRC table or the generator function.
+    """
+    if opt.algorithm != opt.algo_table_driven or _use_constant_crc_table(opt):
+        return []
+    return [
+            '', '',
+            'void {crc_table_gen_function}(const {cfg_t} *cfg)'.format(**sym),
+            '{',
+            CodeGen(opt, 4*' ', [
+                '{crc_t} crc;'.format(**sym),
+                'unsigned int i, j;',
+                '',
+                'for (i = 0; i < {cfg_table_width}; i++) '.format(**sym) + '{',
+                CodeGen(opt, 4*' ', [
+                    Conditional2(opt, '', opt.reflect_in is None, [
+                        'if (cfg->reflect_in) {',
+                        CodeGen(opt, 4*' ', [
+                            'crc = {crc_reflect_function}(i, {cfg_table_idx_width});'.format(**sym),
+                            ]),
+                        '} else {',
+                            CodeGen(opt, 4*' ', [
+                            'crc = i;',
+                            ]),
+                        '}',
+                        ], [
+                            Conditional2(opt, '', opt.reflect_in, [
+                                'crc = {crc_reflect_function}(i, {cfg_table_idx_width});'.format(**sym),
+                                ], [
+                                'crc = i;',
+                                ]),
+                        ]),
+                        'crc <<= {0};'.format(expr.Parenthesis(expr.Add(expr.Sub(sym['cfg_width'], sym['cfg_table_idx_width']), sym['cfg_shift'])).simplify()),
+                        'for (j = 0; j < {cfg_table_idx_width}; j++) '.format(**sym) + '{',
+                        CodeGen(opt, 4*' ', [
+                            'if (crc & {cfg_msb_mask_shifted}) '.format(**sym) + '{',
+                            CodeGen(opt, 4*' ', [
+                                'crc = {0};'.format(expr.Xor(expr.Parenthesis(expr.Shl('crc', 1)), sym['cfg_poly_shifted']).simplify()),
+                                ]),
+                            '} else {',
+                            CodeGen(opt, 4*' ', [
+                                'crc = crc << 1;',
+                                ]),
+                            '}',
+                            ]),
+                        '}',
+                        Conditional(opt, '', opt.reflect_in is None, [
+                            'if (cfg->reflect_in) {',
+                            Conditional2(opt, 4*' ', sym.tbl_shift is None or sym.tbl_shift > 0, [
+                                'crc = {0};'.format(expr.Shl(expr.FunctionCall(sym['crc_reflect_function'], [expr.Shr('crc', sym['cfg_shift']), sym['cfg_width']]), sym['cfg_shift']).simplify()),
+                                ], [
+                                'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+                                ]),
+                            '}',
+                            ]),
+                        Conditional(opt, '', opt.reflect_in, [
+                            Conditional2(opt, 4*' ', sym.tbl_shift is None or sym.tbl_shift > 0, [
+                                'crc = {0};'.format(expr.Shl(expr.FunctionCall(sym['crc_reflect_function'], [expr.Shr('crc', sym['cfg_shift']), sym['cfg_width']]), sym['cfg_shift']).simplify()),
+                                ], [
+                                'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+                                ]),
+                            ]),
+                        'crc_table[i] = {0};'.format(expr.Shr(expr.Parenthesis(expr.And('crc', sym['cfg_mask_shifted'])), sym['cfg_shift'])),
+                        ]),
+                    '}',
+                ]),
+            '}',
+        ]
+
+
+def _crc_reflect_function_gen(opt, sym):
+    """
+    Return the code for the reflect functon.
+    """
+    if not _use_reflect_func(opt):
+        return []
+    if not (opt.reflect_in is None or opt.reflect_in or \
+            opt.reflect_out is None or opt.reflect_out):
+        return []
+    return [
+            '', '',
+            '{crc_t} {crc_reflect_function}({crc_t} data, size_t data_len)'.format(**sym),
+            '{',
+            CodeGen(opt, 4*' ', [
+                'unsigned int i;',
+                '{crc_t} ret;'.format(**sym),
+                '',
+                'ret = data & 0x01;',
+                'for (i = 1; i < data_len; i++) {',
+                CodeGen(opt, 4*' ', [
+                    'data >>= 1;',
+                    'ret = (ret << 1) | (data & 0x01);',
+                    ]),
+                '}',
+                'return ret;',
+                ]),
+            '}',
+            ]
+
+
+def _crc_init_function_gen(opt, sym):
+    """
+    Return the code for the init function.
+    """
+    if _use_constant_crc_init(sym):
+        return []
+    out = [
+            '', '',
+            _crc_init_function_def(opt, sym),
+            '{',
+            CodeGen(opt, 4*' ', [
+                Conditional(opt, '', opt.algorithm == opt.algo_bit_by_bit, [
+                    'unsigned int i;',
+                    '{c_bool} bit;'.format(**sym),
+                    '{crc_t} crc = {cfg_xor_in};'.format(**sym),
+                    'for (i = 0; i < {cfg_width}; i++) '.format(**sym) + '{',
+                    CodeGen(opt, 4*' ', [
+                        'bit = crc & 0x01;',
+                        'if (bit) {',
+                        CodeGen(opt, 4*' ', [
+                            'crc = ((crc ^ {cfg_poly}) >> 1) | {cfg_msb_mask};'.format(**sym),
+                            ]),
+                        '} else {',
+                        CodeGen(opt, 4*' ', [
+                            'crc >>= 1;',
+                            ]),
+                        '}',
+                        ]),
+                    '}',
+                    'return crc & {cfg_mask};'.format(**sym),
+                    ]),
+                Conditional(opt, '', opt.algorithm == opt.algo_bit_by_bit_fast, [
+                    'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
+                    ]),
+                Conditional(opt, '', opt.algorithm == opt.algo_table_driven, [
+                    Conditional2(opt, '', opt.reflect_in is None, [
+                        'if ({cfg_reflect_in}) '.format(**sym) + '{',
+                            CodeGen(opt, 4*' ', [
+                                'return {crc_reflect_function}({cfg_xor_in} & {cfg_mask}, {cfg_width});'.format(**sym),
+                                ]),
+                        '} else {',
+                            CodeGen(opt, 4*' ', [
+                                'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
+                                ]),
+                        '}',
+                    ], [
+                        Conditional2(opt, '', opt.algorithm == opt.reflect_in, [
+                            'return {crc_reflect_function}({cfg_xor_in} & {cfg_mask}, {cfg_width});'.format(**sym),
+                            ], [
+                            'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
+                            ]),
+                        ]),
+                    ]),
+                ]),
+            '}',
+            ]
+    return out
+
+
+def _crc_update_function_gen(opt, sym):
+    """
+    Return the code for the update function.
+    """
+    out = [
+            '', '',
+            _crc_update_function_def(opt, sym),
+            '{',
+            CodeGen(opt, 4*' ', [ 'const unsigned char *d = (const unsigned char *)data;' ]),
+            ]
+    if opt.algorithm == opt.algo_bit_by_bit:
+        out += [
+                CodeGen(opt, 4*' ', [
+                    'unsigned int i;',
+                    '{c_bool} bit;'.format(**sym),
+                    'unsigned char c;',
+                    '',
+                    'while (data_len--) {',
+                    Conditional2(opt, 4*' ', opt.reflect_in is None, [
+                        'if (' + sym['cfg_reflect_in'] + ') {',
+                        CodeGen(opt, 4*' ', [
+                            'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
+                            ]),
+                        '} else {',
+                        CodeGen(opt, 4*' ', [
+                            'c = *d++;',
+                            ]),
+                        '}',
+                        ], [
+                        Conditional2(opt, '', opt.reflect_in, [
+                            'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
+                            ], [
+                            'c = *d++;',
+                            ]),
+                        ]),
+
+                        CodeGen(opt, 4*' ', [
+                            'for (i = 0; i < 8; i++) {',
+                            CodeGen(opt, 4*' ', [
+                                Conditional2(opt, '', opt.c_std == 'C89', [
+                                    'bit = !!(crc & {cfg_msb_mask});'.format(**sym),
+                                    ], [
+                                    'bit = crc & {cfg_msb_mask};'.format(**sym),
+                                    ]),
+                                'crc = (crc << 1) | ((c >> (7 - i)) & 0x01);',
+                                'if (bit) {',
+                                CodeGen(opt, 4*' ', [
+                                    'crc ^= {cfg_poly};'.format(**sym),
+                                    ]),
+                                '}',
+                                ]),
+                            '}',
+                            'crc &= {cfg_mask};'.format(**sym),
+                        ]),
+                    '}',
+                    'return crc & {cfg_mask};'.format(**sym),
+                    ]),
+                ]
+
+    if opt.algorithm == opt.algo_bit_by_bit_fast:
+        out += [
+                CodeGen(opt, 4*' ', [
+                    'unsigned int i;',
+                    '{c_bool} bit;'.format(**sym),
+                    'unsigned char c;',
+                    '',
+                    'while (data_len--) {',
+                    CodeGen(opt, 4*' ', [
+                        Conditional2(opt, '', opt.reflect_in == None, [
+                            'if (' + sym['cfg_reflect_in'] + ') {',
+                            CodeGen(opt, 4*' ', [
+                                'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
+                                ]),
+                            '} else {',
+                            CodeGen(opt, 4*' ', [
+                                'c = *d++;',
+                                ]),
+                            '}',
+                            ], [
+                            'c = *d++;',
+                            ]),
+                        Conditional2(opt, '', opt.reflect_in, [
+                            'for (i = 0x01; i & 0xff; i <<= 1) {',
+                            ], [
+                            'for (i = 0x80; i > 0; i >>= 1) {',
+                            ]),
+                        CodeGen(opt, 4*' ', [
+                            Conditional2(opt, '', opt.c_std == 'C89', [
+                                'bit = !!({0});'.format(expr.And('crc', sym['cfg_msb_mask']).simplify()),
+                                ], [
+                                'bit = {0};'.format(expr.And('crc', sym['cfg_msb_mask']).simplify()),
+                                ]),
+                            'if (c & i) {',
+                            CodeGen(opt, 4*' ', [
+                                'bit = !bit;',
+                                ]),
+                            '}',
+                            'crc <<= 1;',
+                            'if (bit) {',
+                            CodeGen(opt, 4*' ', [
+                                'crc ^= {cfg_poly};'.format(**sym),
+                                ]),
+                            '}',
+                            ]),
+                        '}',
+                        'crc &= {cfg_mask};'.format(**sym)
+                        ]),
+                    '}',
+                    'return {0};'.format(expr.And('crc', sym['cfg_mask']).simplify()),
+                    ]),
+                ]
+
+    if opt.algorithm == opt.algo_table_driven:
+        out += [
+                CodeGen(opt, 4*' ', [
+                    'unsigned int tbl_idx;',
+                    '',
+                    Conditional2(opt, '', opt.reflect_in == None, [
+                        'if (cfg->reflect_in) {',
+                        CodeGen(opt, 4*' ', [
+                            'while (data_len--) {',
+                            CodeGen(opt, 4*' ', [
+                                _crc_table_core_algorithm_reflected(opt, sym),
+                                'd++;',
+                                ]),
+                            '}',
+                            ]),
+                        '} else {',
+                        CodeGen(opt, 4*' ', [
+                            'while (data_len--) {',
+                            CodeGen(opt, 4*' ', [
+                                _crc_table_core_algorithm_nonreflected(opt, sym),
+                                'd++;',
+                                ]),
+                            '}',
+                            ]),
+                        '}',
+                        ], [
+                            Conditional(opt, '', opt.slice_by > 1, [
+                                '/* Align to a multiple of {crc_slice_by} bytes */'.format(**sym),
+                                'while (data_len && (((uintptr_t)(const void *)d) % {crc_slice_by} != 0))'.format(**sym) + ' {',
+                                CodeGen(opt, 4*' ', [
+                                    _crc_table_core_algorithm(opt, sym),
+                                    'data_len--;',
+                                    ]),
+                                '}',
+                                '',
+                                _crc_table_slice_by_algorithm(opt, sym),
+                                '/* Remaining bytes with the standard algorithm */',
+                                'd = (const unsigned char *)d32;',
+                                ]),
+                            'while (data_len--) {',
+                            CodeGen(opt, 4*' ', [
+                                _crc_table_core_algorithm(opt, sym),
+                                ]),
+                            '}',
+                        ]),
+                    'return {0};'.format(expr.And('crc', sym['cfg_mask']).simplify()),
+                    ]),
+            ]
+    out += [
+            '}',
+            ]
+    return out
+
+
+
+def _crc_finalize_function_gen(opt, sym):
+    """
+    Return the code for the finalize function.
+    """
+    if _use_inline_crc_finalize(opt):
+        return []
+    out = [
+            '', '',
+            _crc_finalize_function_def(opt, sym),
+            '{',
+            ]
+    if opt.algorithm in set([opt.algo_bit_by_bit, opt.algo_bit_by_bit_fast]):
+        out += [
+                Conditional(opt, 4*' ', opt.algorithm == opt.algo_bit_by_bit, [
+                    'unsigned int i;',
+                    '{c_bool} bit;'.format(**sym),
+                    '',
+                    'for (i = 0; i < ' + sym['cfg_width'] + '; i++) {',
+                    CodeGen(opt, 4*' ', [
+                        Conditional2(opt, '', opt.c_std == 'C89', [
+                            'bit = !!(crc & {cfg_msb_mask});'.format(**sym)
+                            ], [
+                            'bit = crc & {cfg_msb_mask};'.format(**sym),
+                            ]),
+                        'crc <<= 1;',
+                        'if (bit) {',
+                        CodeGen(opt, 4*' ', [
+                            'crc ^= {cfg_poly};'.format(**sym),
+                            ]),
+                        '}',
+                        ]),
+                    '}',
+                    Conditional(opt, '', opt.reflect_out is None, [
+                        'if (' + sym['cfg_reflect_out'] + ') {',
+                        CodeGen(opt, 4*' ', [
+                            'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+                            ]),
+                        '}',
+                        ]),
+                    Conditional(opt, '', opt.reflect_out, [
+                        'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+                        ]),
+                    ]),
+
+                 Conditional(opt, 4*' ', opt.algorithm == opt.algo_bit_by_bit_fast, [
+                    Conditional(opt, '', opt.reflect_out is None, [
+                        'if (' + sym['cfg_reflect_out'] + ') {',
+                        CodeGen(opt, 4*' ', [
+                            'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+                            ]),
+                        '}',
+                    ]),
+                    Conditional(opt, '', opt.reflect_out, [
+                        'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+                        ]),
+                    ]),
+                 ]
+
+    if opt.algorithm == opt.algo_table_driven:
+        if opt.reflect_in is None or opt.reflect_out is None:
+            if opt.reflect_in is None and opt.reflect_out is None:
+                cond = 'cfg->reflect_in != cfg->reflect_out'
+            elif opt.reflect_out is None:
+                cond = '!' if opt.reflect_in else '' + 'cfg->reflect_out'
+            else:
+                cond = '!' if opt.reflect_out else '' + 'cfg->reflect_in'
+            out += [
+                    CodeGen(opt, 4*' ', [
+                        'if (' + cond + ') {',
+                        CodeGen(opt, 4*' ', [
+                            'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+                            ]),
+                        '}',
+                        ]),
+                    ]
+        elif opt.reflect_in != opt.reflect_out:
+            out += [
+                    'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+                    ]
+    out += [
+            CodeGen(opt, 4*' ', [
+                'return {0};'.format(expr.And(expr.Parenthesis(expr.Xor('crc', sym['cfg_xor_out'])), sym['cfg_mask']).simplify()),
+                ]),
+            '}',
+            ]
+    return out
+
+def _crc_table_core_algorithm(opt, sym):
+    """
+    Return the core of the table-driven algorithm.
+    """
+    out = []
+    out += [
+        Conditional2(opt, '', opt.reflect_in, [
+            _crc_table_core_algorithm_reflected(opt, sym),
+            ], [
+            _crc_table_core_algorithm_nonreflected(opt, sym),
+            ]),
+        'd++;',
+    ]
+    return CodeGen(opt, '', out)
+
+def _crc_table_core_algorithm_reflected(opt, sym):
+    """
+    Return the core loop of the table-driven algorithm, reflected variant.
+    """
+    out = []
+    if opt.width is not None and opt.tbl_idx_width is not None and opt.width <= opt.tbl_idx_width:
+        crc_xor_expr = '0'
+    else:
+        crc_xor_expr = '(crc >> {cfg_table_idx_width})'.format(**sym)
+
+    if opt.tbl_idx_width == 8:
+        if opt.slice_by > 1:
+            crc_lookup = 'crc_table[0][tbl_idx]'
+        else:
+            crc_lookup = 'crc_table[tbl_idx]'
+        out += [
+                Conditional2(opt, '', opt.width is None or opt.width > 8, [
+                    'tbl_idx = (crc ^ *d) & {crc_table_mask};'.format(**sym),
+                    ], [
+                    'tbl_idx = crc ^ *d;',
+                    ]),
+                    'crc = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_lookup, expr.Parenthesis(expr.Shr('crc', sym['cfg_table_idx_width'])))), sym['cfg_mask']).simplify()),
+                ]
+    else:
+        crc_lookup = 'crc_table[tbl_idx & {crc_table_mask}]'.format(**sym)
+        for i in range(8 // opt.tbl_idx_width):
+            out += [
+                'tbl_idx = {0};'.format(expr.Xor('crc', expr.Parenthesis(expr.Shr('*d', expr.Parenthesis(expr.Mul(i, sym['cfg_table_idx_width']))))).simplify()),
+                'crc = {0};'.format(expr.Xor(crc_lookup, crc_xor_expr).simplify())
+                ]
+    return CodeGen(opt, '', out)
+
+def _crc_table_core_algorithm_nonreflected(opt, sym):
+    """
+    Return the core loop of the table-driven algorithm, non-reflected variant.
+    """
+    out = []
+    if opt.width == None:
+        crc_shifted_right = expr.Parenthesis(expr.Shr('crc', expr.Parenthesis(expr.Sub(sym['cfg_width'], sym['cfg_table_idx_width'])))).simplify()
+    elif opt.width < 8:
+        shift_val = opt.width - opt.tbl_idx_width
+        if shift_val < 0:
+            crc_shifted_right = expr.Parenthesis(expr.Shl('crc', -shift_val)).simplify()
+        else:
+            crc_shifted_right = expr.Parenthesis(expr.Shr('crc', shift_val)).simplify()
+    else:
+        shift_val = opt.width - opt.tbl_idx_width
+        crc_shifted_right = expr.Parenthesis(expr.Shr('crc', shift_val)).simplify()
+
+    if opt.width is not None and opt.tbl_idx_width is not None and opt.width <= opt.tbl_idx_width:
+        crc_xor_expr = '0'
+    else:
+        crc_xor_expr = '(crc << {cfg_table_idx_width})'.format(**sym)
+
+    if opt.tbl_idx_width == 8:
+        if opt.slice_by > 1:
+            crc_lookup = 'crc_table[0][tbl_idx]'
+        else:
+            crc_lookup = 'crc_table[tbl_idx]'
+        out += [
+                Conditional2(opt, '', opt.width is None or opt.width > 8, [
+                    'tbl_idx = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_shifted_right, '*d')), sym['crc_table_mask']).simplify())
+                    ], [
+                    'tbl_idx = {0};'.format(expr.Xor(crc_shifted_right, '*d').simplify())
+                    ]),
+                    'crc = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_lookup, crc_xor_expr)), sym['cfg_mask']).simplify())
+                ]
+    else:
+        crc_lookup = 'crc_table[tbl_idx & {crc_table_mask}]'.format(**sym)
+        for i in range(8 // opt.tbl_idx_width):
+            str_idx = '{0:d}'.format(8 - (i + 1) * opt.tbl_idx_width)
+            out += [
+                    'tbl_idx = {0};'.format(expr.Xor(crc_shifted_right, expr.Parenthesis(expr.Shr('*d', str_idx)))),
+                    'crc = {0};'.format(expr.Xor(crc_lookup, crc_xor_expr).simplify()),
+                    ]
+    return CodeGen(opt, '', out)
+
+def _crc_table_slice_by_algorithm(opt, sym):
+    update_be = []
+    for i in range(opt.slice_by // 4):
+        vard = 'd{0}'.format(opt.slice_by // 4 - i)
+        for j in range(4):
+            idx1 = i * 4 + j
+            idx2 = expr.And(expr.Parenthesis(expr.Shr(vard, j*8)), expr.Terminal(255, '0xffu')).simplify()
+            update_be.append('crc_table[{0}][{1}]{2}'.format(idx1, idx2, ' ^' if idx1 < opt.slice_by - 1 else ';'))
+
+    update_le = []
+    for i in range(opt.slice_by // 4):
+        vard = 'd{0}'.format(opt.slice_by // 4 - i)
+        for j in range(4):
+            idx1 = i * 4 + j
+            idx2 = expr.And(expr.Parenthesis(expr.Shr(vard, 24 - j*8)), expr.Terminal(255, '0xffu')).simplify()
+            update_le.append('crc_table[{0}][{1}]{2}'.format(idx1, idx2, ' ^' if idx1 < opt.slice_by - 1 else ';'))
+
+    out = [
+            'const uint32_t *d32 = (const uint32_t *)d;',
+            'while (data_len >= {crc_slice_by})'.format(**sym),
+            '{',
+            CodeGen(opt, 4*' ', [
+                CodeGen(opt, None, [
+                    '#if __BYTE_ORDER == __BIG_ENDIAN',
+                    ]),
+                '{crc_t} d1 = *d32++ ^ le16toh(crc);'.format(**sym),
+                Conditional(opt, '', opt.slice_by >= 8, [
+                    '{crc_t} d2 = *d32++;'.format(**sym),
+                    ]),
+                Conditional(opt, '', opt.slice_by >= 16, [
+                    '{crc_t} d3 = *d32++;'.format(**sym),
+                    '{crc_t} d4 = *d32++;'.format(**sym),
+                    ]),
+                'crc  =',
+                CodeGen(opt, 4*' ', update_be),
+                CodeGen(opt, None, [
+                    '#else',
+                    ]),
+                '{crc_t} d1 = *d32++ ^ crc;'.format(**sym),
+                Conditional(opt, '', opt.slice_by >= 8, [
+                    '{crc_t} d2 = *d32++;'.format(**sym),
+                    ]),
+                Conditional(opt, '', opt.slice_by >= 16, [
+                    '{crc_t} d3 = *d32++;'.format(**sym),
+                    '{crc_t} d4 = *d32++;'.format(**sym),
+                    ]),
+                'crc  =',
+                CodeGen(opt, 4*' ', update_le),
+                CodeGen(opt, None, [
+                    '#endif',
+                    ]),
+                '',
+                'data_len -= {crc_slice_by};'.format(**sym),
+                ]),
+            '}',
+            '',
+            ]
+    return CodeGen(opt, '', out)
diff --git a/pycrc/expr.py b/pycrc/expr.py
new file mode 100644
index 0000000..a15742c
--- /dev/null
+++ b/pycrc/expr.py
@@ -0,0 +1,398 @@
+#  pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+#  Copyright (c) 2017  Thomas Pircher  <tehpeh-web@tty1.net>
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to
+#  deal in the Software without restriction, including without limitation the
+#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+#  sell copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+#  IN THE SOFTWARE.
+
+
+"""
+This modules simplifies an expression.
+
+    import pycrc.expr as exp
+
+    my_expr = exp.Xor('var', exp.Parenthesis(exp.And('0x700', 4)))
+    print('"{}" -> "{}"'.format(my_expr, my_expr.simplify()))
+"""
+
+
+def _classify(val):
+    """
+    Creates a Terminal object if the parameter is a string or an integer.
+    """
+    if type(val) is int:
+        return Terminal(val)
+    if type(val) is str:
+        if val.isdigit():
+            return Terminal(int(val), val)
+        if val[:2].lower() == '0x':
+            return Terminal(int(val, 16), val)
+        return Terminal(val)
+    return val
+
+
+class Expression(object):
+    """
+    Base class for all expressions.
+    """
+    def is_int(self, val = None):
+        return False
+
+
+class Terminal(Expression):
+    """
+    A terminal object.
+    """
+    def __init__(self, val, pretty = None):
+        """
+        Construct a Terminal.
+        The val variable is usually a string or an integer. Integers may also
+        be passed as strings. The pretty-printer will use the string when
+        formatting the expression.
+        """
+        self.val = val
+        self.pretty = pretty
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        if self.pretty is None:
+            return str(self.val)
+        return self.pretty
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        return self
+
+    def is_int(self, val = None):
+        """
+        Return True if the value of this Terminal is an integer.
+        """
+        if type(self.val) is int:
+            return val is None or self.val == val
+        return False
+
+
+class FunctionCall(Expression):
+    """
+    Represent a function call
+    """
+    def __init__(self, name, args):
+        """
+        Construct a function call object.
+        """
+        self.name = _classify(name)
+        self.args = [_classify(arg) for arg in args]
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.name) + '(' + ', '.join([str(arg) for arg in self.args]) + ')'
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        args = [arg.simplify() for arg in self.args]
+        return FunctionCall(self.name, args)
+
+
+class Parenthesis(Expression):
+    """
+    Represent a pair of round brackets.
+    """
+    def __init__(self, val):
+        """
+        Construct a parenthesis object.
+        """
+        self.val = _classify(val)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        val = self.val.simplify()
+        if type(val) is Terminal:
+            return val
+        return Parenthesis(val)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return '(' + str(self.val) + ')'
+
+
+class Add(Expression):
+    """
+    Represent an addition of operands.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct an addition object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val + rhs.val)
+        if lhs.is_int(0):
+            return rhs
+        if rhs.is_int(0):
+            return lhs
+        return Add(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' + ' + str(self.rhs)
+
+
+class Sub(Expression):
+    """
+    Represent a subtraction of operands.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct subtraction object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val - rhs.val)
+        if lhs.is_int(0):
+            return rhs
+        if rhs.is_int(0):
+            return lhs
+        return Sub(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' - ' + str(self.rhs)
+
+
+class Mul(Expression):
+    """
+    Represent the multiplication of operands.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a multiplication object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val * rhs.val)
+        if lhs.is_int(0) or rhs.is_int(0):
+            return Terminal(0)
+        if lhs.is_int(1):
+            return rhs
+        if rhs.is_int(1):
+            return lhs
+        return Mul(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' * ' + str(self.rhs)
+
+
+class Shl(Expression):
+    """
+    Shift left operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a shift left object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val << rhs.val)
+        if lhs.is_int(0):
+            return Terminal(0)
+        if rhs.is_int(0):
+            return lhs
+        return Shl(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' << ' + str(self.rhs)
+
+
+class Shr(Expression):
+    """
+    Shift right operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a shift right object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val >> rhs.val)
+        if lhs.is_int(0):
+            return Terminal(0)
+        if rhs.is_int(0):
+            return lhs
+        return Shr(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' >> ' + str(self.rhs)
+
+
+class Or(Expression):
+    """
+    Logical or operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a logical and object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val | rhs.val)
+        if lhs.is_int(0):
+            return rhs
+        if rhs.is_int(0):
+            return lhs
+        return Or(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' | ' + str(self.rhs)
+
+
+class And(Expression):
+    """
+    Logical and operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a logical and object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val & rhs.val)
+        if lhs.is_int(0) or rhs.is_int(0):
+            return Terminal(0)
+        return And(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' & ' + str(self.rhs)
+
+
+class Xor(Expression):
+    """
+    Logical xor operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a logical xor object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val ^ rhs.val)
+        if lhs.is_int(0):
+            return rhs
+        if rhs.is_int(0):
+            return lhs
+        return Xor(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' ^ ' + str(self.rhs)
diff --git a/pycrc/main.py b/pycrc/main.py
new file mode 100644
index 0000000..d446362
--- /dev/null
+++ b/pycrc/main.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+
+#  pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+#  Copyright (c) 2006-2017  Thomas Pircher  <tehpeh-web@tty1.net>
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to
+#  deal in the Software without restriction, including without limitation the
+#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+#  sell copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+#  IN THE SOFTWARE.
+
+
+"""
+pycrc is a fully parameterisable Cyclic Redundancy Check (CRC) calculation
+utility and C source code generator written in Python.
+
+It can:
+    -  generate the checksum of a string
+    -  generate the checksum of a file
+    -  generate the C header file and source of any of the algorithms below
+
+It supports the following CRC algorithms:
+    -  bit-by-bit       the basic algorithm which operates bit by bit on the
+                        augmented message
+    -  bit-by-bit-fast  a variation of the simple bit-by-bit algorithm
+    -  table-driven     the standard table driven algorithm
+"""
+
+from __future__ import print_function
+from pycrc import progname, version, url
+from pycrc.opt import Options
+from pycrc.algorithms import Crc
+import pycrc.codegen as cg
+import binascii
+import sys
+
+
+
+def print_parameters(opt):
+    """
+    Generate a string with the options pretty-printed (used in the --verbose mode).
+    """
+    return str(cg.ParamBlock(opt, ''))
+
+
+def check_string(opt):
+    """
+    Return the calculated CRC sum of a string.
+    """
+    error = False
+    if opt.undefined_crc_parameters:
+        sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
+        sys.exit(1)
+    if opt.algorithm == 0:
+        opt.algorithm = opt.algo_bit_by_bit | opt.algo_bit_by_bit_fast | opt.algo_table_driven
+
+    alg = Crc(
+        width=opt.width, poly=opt.poly,
+        reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+        reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+        table_idx_width=opt.tbl_idx_width)
+
+    crc = None
+    if opt.algorithm & opt.algo_bit_by_bit:
+        bbb_crc = alg.bit_by_bit(opt.check_string)
+        if crc != None and bbb_crc != crc:
+            error = True
+        crc = bbb_crc
+    if opt.algorithm & opt.algo_bit_by_bit_fast:
+        bbf_crc = alg.bit_by_bit_fast(opt.check_string)
+        if crc != None and bbf_crc != crc:
+            error = True
+        crc = bbf_crc
+    if opt.algorithm & opt.algo_table_driven:
+        # no point making the python implementation slower by using less than 8 bits as index.
+        opt.tbl_idx_width = 8
+        tbl_crc = alg.table_driven(opt.check_string)
+        if crc != None and tbl_crc != crc:
+            error = True
+        crc = tbl_crc
+
+    if error:
+        sys.stderr.write("{0:s}: error: different checksums!\n".format(progname))
+        if opt.algorithm & opt.algo_bit_by_bit:
+            sys.stderr.write("       bit-by-bit:        {0:#x}\n".format(bbb_crc))
+        if opt.algorithm & opt.algo_bit_by_bit_fast:
+            sys.stderr.write("       bit-by-bit-fast:   {0:#x}\n".format(bbf_crc))
+        if opt.algorithm & opt.algo_table_driven:
+            sys.stderr.write("       table_driven:      {0:#x}\n".format(tbl_crc))
+        sys.exit(1)
+    return crc
+
+
+def check_hexstring(opt):
+    """
+    Return the calculated CRC sum of a hex string.
+    """
+    if opt.undefined_crc_parameters:
+        sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
+        sys.exit(1)
+    if len(opt.check_string) % 2 != 0:
+        opt.check_string = "0" + opt.check_string
+    if sys.version_info >= (3, 0):
+        opt.check_string = bytes(opt.check_string, 'utf_8')
+    try:
+        check_str = bytearray(binascii.unhexlify(opt.check_string))
+    except TypeError:
+        sys.stderr.write(
+            "{0:s}: error: invalid hex string {1:s}\n".format(progname, opt.check_string))
+        sys.exit(1)
+
+    opt.check_string = check_str
+    return check_string(opt)
+
+
+def crc_file_update(alg, register, check_bytes):
+    """
+    Update the CRC using the bit-by-bit-fast CRC algorithm.
+    """
+    # If the input data is a string, convert to bytes.
+    if isinstance(check_bytes, str):
+        check_bytes = bytearray(check_bytes, 'utf_8')
+
+    for octet in check_bytes:
+        if alg.reflect_in:
+            octet = alg.reflect(octet, 8)
+        for j in range(8):
+            bit = register & alg.msb_mask
+            register <<= 1
+            if octet & (0x80 >> j):
+                bit ^= alg.msb_mask
+            if bit:
+                register ^= alg.poly
+        register &= alg.mask
+    return register
+
+
+def check_file(opt):
+    """
+    Calculate the CRC of a file.
+    This algorithm uses the table_driven CRC algorithm.
+    """
+    if opt.undefined_crc_parameters:
+        sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
+        sys.exit(1)
+    alg = Crc(
+        width=opt.width, poly=opt.poly,
+        reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+        reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+        table_idx_width=opt.tbl_idx_width)
+
+    if not opt.reflect_in:
+        register = opt.xor_in
+    else:
+        register = alg.reflect(opt.xor_in, opt.width)
+
+    try:
+        with open(opt.check_file, 'rb') as f:
+            check_bytes = bytearray(f.read(1024))
+            while check_bytes != b"":
+                register = crc_file_update(alg, register, check_bytes)
+                check_bytes = bytearray(f.read(1024))
+    except IOError:
+        sys.stderr.write(
+            "{0:s}: error: can't open file {1:s}\n".format(progname, opt.check_file))
+        sys.exit(1)
+
+    if opt.reflect_out:
+        register = alg.reflect(register, opt.width)
+    register = register ^ opt.xor_out
+    return register
+
+
+def write_file(filename, out_str):
+    """
+    Write the content of out_str to filename.
+    """
+    try:
+        out_file = open(filename, "w")
+        out_file.write(out_str)
+        out_file.close()
+    except IOError:
+        sys.stderr.write("{0:s}: error: cannot write to file {1:s}\n".format(progname, filename))
+        sys.exit(1)
+
+
+def main():
+    """
+    Main function.
+    """
+    opt = Options(progname, version, url)
+    opt.parse(sys.argv[1:])
+    if opt.verbose:
+        print(print_parameters(opt))
+    if opt.action == opt.action_check_str:
+        crc = check_string(opt)
+        print("{0:#x}".format(crc))
+    if opt.action == opt.action_check_hex_str:
+        crc = check_hexstring(opt)
+        print("{0:#x}".format(crc))
+    if opt.action == opt.action_check_file:
+        crc = check_file(opt)
+        print("{0:#x}".format(crc))
+    if opt.action in set([
+            opt.action_generate_h, opt.action_generate_c, opt.action_generate_c_main,
+            opt.action_generate_table]):
+        if opt.action == opt.action_generate_h:
+            in_str = "$h_template"
+        elif opt.action == opt.action_generate_c:
+            in_str = "$c_template"
+        elif opt.action == opt.action_generate_c_main:
+            in_str = "$c_template\n\n$main_template"
+        elif opt.action == opt.action_generate_table:
+            in_str = "$crc_table_init"
+        else:
+            sys.stderr.write(
+                "{0:s}: error: unknown action. Please file a bug report!\n".format(progname))
+            sys.exit(1)
+        out = str(cg.File(opt, ''))
+        if opt.output_file == None:
+            print(out)
+        else:
+            write_file(opt.output_file, out)
+    return 0
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/pycrc/models.py b/pycrc/models.py
new file mode 100644
index 0000000..d12c91c
--- /dev/null
+++ b/pycrc/models.py
@@ -0,0 +1,334 @@
+#  pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+#  Copyright (c) 2006-2017  Thomas Pircher  <tehpeh-web@tty1.net>
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to
+#  deal in the Software without restriction, including without limitation the
+#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+#  sell copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+#  IN THE SOFTWARE.
+
+
+"""
+Collection of CRC models. This module contains the CRC models known to pycrc.
+
+To print the parameters of a particular model:
+
+    from pycrc.models import CrcModels
+
+    models = CrcModels()
+    print(", ".join(models.names()))
+    m = models.get_params("crc-32")
+    if m != None:
+        print("Width:        {width:d}".format(**m))
+        print("Poly:         {poly:#x}".format(**m))
+        print("ReflectIn:    {reflect_in}".format(**m))
+        print("XorIn:        {xor_in:#x}".format(**m))
+        print("ReflectOut:   {reflect_out}".format(**m))
+        print("XorOut:       {xor_out:#x}".format(**m))
+        print("Check:        {check:#x}".format(**m))
+    else:
+        print("model not found.")
+"""
+
+
+
+class CrcModels(object):
+    """
+    CRC Models.
+
+    All models are defined as constant class variables.
+    """
+
+    models = []
+
+    models.append({
+        'name':         'crc-5',
+        'width':         5,
+        'poly':          0x05,
+        'reflect_in':    True,
+        'xor_in':        0x1f,
+        'reflect_out':   True,
+        'xor_out':       0x1f,
+        'check':         0x19,
+    })
+    models.append({
+        'name':         'crc-8',
+        'width':         8,
+        'poly':          0x07,
+        'reflect_in':    False,
+        'xor_in':        0x0,
+        'reflect_out':   False,
+        'xor_out':       0x0,
+        'check':         0xf4,
+    })
+    models.append({
+        'name':         'dallas-1-wire',
+        'width':         8,
+        'poly':          0x31,
+        'reflect_in':    True,
+        'xor_in':        0x0,
+        'reflect_out':   True,
+        'xor_out':       0x0,
+        'check':         0xa1,
+    })
+    models.append({
+        'name':         'crc-12-3gpp',
+        'width':         12,
+        'poly':          0x80f,
+        'reflect_in':    False,
+        'xor_in':        0x0,
+        'reflect_out':   True,
+        'xor_out':       0x0,
+        'check':         0xdaf,
+    })
+    models.append({
+        'name':         'crc-15',
+        'width':         15,
+        'poly':          0x4599,
+        'reflect_in':    False,
+        'xor_in':        0x0,
+        'reflect_out':   False,
+        'xor_out':       0x0,
+        'check':         0x59e,
+    })
+    models.append({
+        'name':         'crc-16',
+        'width':         16,
+        'poly':          0x8005,
+        'reflect_in':    True,
+        'xor_in':        0x0,
+        'reflect_out':   True,
+        'xor_out':       0x0,
+        'check':         0xbb3d,
+    })
+    models.append({
+        'name':         'crc-16-usb',
+        'width':         16,
+        'poly':          0x8005,
+        'reflect_in':    True,
+        'xor_in':        0xffff,
+        'reflect_out':   True,
+        'xor_out':       0xffff,
+        'check':         0xb4c8,
+    })
+    models.append({
+        'name':         'crc-16-modbus',
+        'width':         16,
+        'poly':          0x8005,
+        'reflect_in':    True,
+        'xor_in':        0xffff,
+        'reflect_out':   True,
+        'xor_out':       0x0,
+        'check':         0x4b37,
+    })
+    models.append({
+        'name':         'crc-16-genibus',
+        'width':         16,
+        'poly':          0x1021,
+        'reflect_in':    False,
+        'xor_in':        0xffff,
+        'reflect_out':   False,
+        'xor_out':       0xffff,
+        'check':         0xd64e,
+    })
+    models.append({
+        'name':         'crc-16-ccitt',
+        'width':         16,
+        'poly':          0x1021,
+        'reflect_in':    False,
+        'xor_in':        0x1d0f,
+        'reflect_out':   False,
+        'xor_out':       0x0,
+        'check':         0xe5cc,
+    })
+    models.append({
+        'name':         'r-crc-16',
+        'width':         16,
+        'poly':          0x0589,
+        'reflect_in':    False,
+        'xor_in':        0x0,
+        'reflect_out':   False,
+        'xor_out':       0x0001,
+        'check':         0x007e,
+    })
+    models.append({
+        'name':         'kermit',
+        'width':         16,
+        'poly':          0x1021,
+        'reflect_in':    True,
+        'xor_in':        0x0,
+        'reflect_out':   True,
+        'xor_out':       0x0,
+        'check':         0x2189,
+    })
+    models.append({
+        'name':         'x-25',
+        'width':         16,
+        'poly':          0x1021,
+        'reflect_in':    True,
+        'xor_in':        0xffff,
+        'reflect_out':   True,
+        'xor_out':       0xffff,
+        'check':         0x906e,
+    })
+    models.append({
+        'name':         'xmodem',
+        'width':         16,
+        'poly':          0x1021,
+        'reflect_in':    False,
+        'xor_in':        0x0,
+        'reflect_out':   False,
+        'xor_out':       0x0,
+        'check':         0x31c3,
+    })
+    models.append({
+        'name':         'zmodem',
+        'width':         16,
+        'poly':          0x1021,
+        'reflect_in':    False,
+        'xor_in':        0x0,
+        'reflect_out':   False,
+        'xor_out':       0x0,
+        'check':         0x31c3,
+    })
+    models.append({
+        'name':         'crc-24',
+        'width':         24,
+        'poly':          0x864cfb,
+        'reflect_in':    False,
+        'xor_in':        0xb704ce,
+        'reflect_out':   False,
+        'xor_out':       0x0,
+        'check':         0x21cf02,
+    })
+    models.append({
+        'name':         'crc-32',
+        'width':         32,
+        'poly':          0x4c11db7,
+        'reflect_in':    True,
+        'xor_in':        0xffffffff,
+        'reflect_out':   True,
+        'xor_out':       0xffffffff,
+        'check':         0xcbf43926,
+    })
+    models.append({
+        'name':         'crc-32c',
+        'width':         32,
+        'poly':          0x1edc6f41,
+        'reflect_in':    True,
+        'xor_in':        0xffffffff,
+        'reflect_out':   True,
+        'xor_out':       0xffffffff,
+        'check':         0xe3069283,
+    })
+    models.append({
+        'name':         'crc-32-mpeg',
+        'width':         32,
+        'poly':          0x4c11db7,
+        'reflect_in':    False,
+        'xor_in':        0xffffffff,
+        'reflect_out':   False,
+        'xor_out':       0x0,
+        'check':         0x0376e6e7,
+    })
+    models.append({
+        'name':         'crc-32-bzip2',
+        'width':         32,
+        'poly':          0x04c11db7,
+        'reflect_in':    False,
+        'xor_in':        0xffffffff,
+        'reflect_out':   False,
+        'xor_out':       0xffffffff,
+        'check':         0xfc891918,
+    })
+    models.append({
+        'name':         'posix',
+        'width':         32,
+        'poly':          0x4c11db7,
+        'reflect_in':    False,
+        'xor_in':        0x0,
+        'reflect_out':   False,
+        'xor_out':       0xffffffff,
+        'check':         0x765e7680,
+    })
+    models.append({
+        'name':         'jam',
+        'width':         32,
+        'poly':          0x4c11db7,
+        'reflect_in':    True,
+        'xor_in':        0xffffffff,
+        'reflect_out':   True,
+        'xor_out':       0x0,
+        'check':         0x340bc6d9,
+    })
+    models.append({
+        'name':         'xfer',
+        'width':         32,
+        'poly':          0x000000af,
+        'reflect_in':    False,
+        'xor_in':        0x0,
+        'reflect_out':   False,
+        'xor_out':       0x0,
+        'check':         0xbd0be338,
+    })
+    models.append({
+        'name':         'crc-64',
+        'width':         64,
+        'poly':          0x000000000000001b,
+        'reflect_in':    True,
+        'xor_in':        0x0,
+        'reflect_out':   True,
+        'xor_out':       0x0,
+        'check':         0x46a5a9388a5beffe,
+    })
+    models.append({
+        'name':         'crc-64-jones',
+        'width':         64,
+        'poly':          0xad93d23594c935a9,
+        'reflect_in':    True,
+        'xor_in':        0xffffffffffffffff,
+        'reflect_out':   True,
+        'xor_out':       0x0,
+        'check':         0xcaa717168609f281,
+    })
+    models.append({
+        'name':         'crc-64-xz',
+        'width':         64,
+        'poly':          0x42f0e1eba9ea3693,
+        'reflect_in':    True,
+        'xor_in':        0xffffffffffffffff,
+        'reflect_out':   True,
+        'xor_out':       0xffffffffffffffff,
+        'check':         0x995dc9bbdf1939fa,
+    })
+
+
+    def names(self):
+        """
+        This function returns the list of supported CRC models.
+        """
+        return [model['name'] for model in self.models]
+
+
+    def get_params(self, model):
+        """
+        This function returns the parameters of a given model.
+        """
+        model = model.lower()
+        for i in self.models:
+            if i['name'] == model:
+                return i
+        return None
diff --git a/pycrc/opt.py b/pycrc/opt.py
new file mode 100644
index 0000000..7868b2e
--- /dev/null
+++ b/pycrc/opt.py
@@ -0,0 +1,484 @@
+#  pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+#  Copyright (c) 2006-2017  Thomas Pircher  <tehpeh-web@tty1.net>
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to
+#  deal in the Software without restriction, including without limitation the
+#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+#  sell copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+#  IN THE SOFTWARE.
+
+
+"""
+Option parsing library for pycrc.
+use as follows:
+
+   from pycrc.opt import Options
+
+   opt = Options()
+   opt.parse(sys.argv[1:])
+"""
+
+from optparse import OptionParser, Option, OptionValueError
+from copy import copy
+import sys
+from pycrc.models import CrcModels
+
+
+class Options(object):
+    """
+    The options parsing and validating class.
+    """
+    # pylint: disable=too-many-instance-attributes, too-few-public-methods
+
+    # Bitmap of the algorithms
+    algo_none = 0x00
+    algo_bit_by_bit = 0x01
+    algo_bit_by_bit_fast = 0x02
+    algo_table_driven = 0x08
+
+    action_check_str = 0x01
+    action_check_hex_str = 0x02
+    action_check_file = 0x03
+    action_generate_h = 0x04
+    action_generate_c = 0x05
+    action_generate_c_main = 0x06
+    action_generate_table = 0x07
+
+
+    def __init__(self, progname='pycrc', version=None, url=None):
+        self.program_name = progname
+        self.version = version
+        self.version_str = "{0:s} v{1:s}".format(progname, version)
+        self.web_address = url
+
+        self.width = None
+        self.poly = None
+        self.reflect_in = None
+        self.xor_in = None
+        self.reflect_out = None
+        self.xor_out = None
+        self.tbl_idx_width = 8
+        self.tbl_width = 1 << self.tbl_idx_width
+        self.slice_by = 1
+        self.verbose = False
+        self.check_string = "123456789"
+        self.msb_mask = None
+        self.mask = None
+
+        self.algorithm = self.algo_none
+        self.symbol_prefix = "crc_"
+        self.crc_type = None
+        self.include_files = []
+        self.output_file = None
+        self.action = self.action_check_str
+        self.check_file = None
+        self.c_std = None
+        self.undefined_crc_parameters = False
+
+
+    def parse(self, argv=None):
+        """
+        Parses and validates the options given as arguments
+        """
+        # pylint: disable=too-many-branches, too-many-statements
+
+        usage = """python %prog [OPTIONS]
+
+To calculate the checksum of a string or hexadecimal data:
+    python %prog [model] --check-string "123456789"
+    python %prog [model] --check-hexstring "313233343536373839"
+
+To calculate the checksum of a file:
+    python %prog [model] --check-file filename
+
+To generate the C source code and write it to filename:
+    python %prog [model] --generate c -o filename
+
+The model can be defined either with the --model switch or by specifying each
+of the following parameters:
+    --width --poly --reflect-in --xor-in --reflect-out --xor-out"""
+
+        models = CrcModels()
+        model_list = ", ".join(models.names())
+        parser = OptionParser(option_class=MyOption, usage=usage, version=self.version_str)
+        parser.add_option(
+                "-v", "--verbose",
+                action="store_true", dest="verbose", default=False,
+                help="be more verbose; print the value of the parameters "
+                "and the chosen model to stdout")
+        parser.add_option(
+                "--check-string",
+                action="store", type="string", dest="check_string",
+                help="calculate the checksum of a string (default: '123456789')",
+                metavar="STRING")
+        parser.add_option(
+                "--check-hexstring",
+                action="store", type="string", dest="check_hexstring",
+                help="calculate the checksum of a hexadecimal number string",
+                metavar="STRING")
+        parser.add_option(
+                "--check-file",
+                action="store", type="string", dest="check_file",
+                help="calculate the checksum of a file",
+                metavar="FILE")
+        parser.add_option(
+                "--generate",
+                action="store", type="string", dest="generate", default=None,
+                help="generate C source code; choose the type from {h, c, c-main, table}",
+                metavar="CODE")
+        parser.add_option(
+                "--std",
+                action="store", type="string", dest="c_std", default="C99",
+                help="choose the C dialect of the generated code from {C89, ANSI, C99}",
+                metavar="STD")
+        parser.add_option(
+                "--algorithm",
+                action="store", type="string", dest="algorithm", default="all",
+                help="choose an algorithm from "
+                "{bit-by-bit, bbb, bit-by-bit-fast, bbf, table-driven, tbl, all}",
+                metavar="ALGO")
+        parser.add_option(
+                "--model",
+                action="callback", callback=_model_cb, type="string", dest="model", default=None,
+                help="choose a parameter set from {{{0:s}}}".format(model_list),
+                metavar="MODEL")
+        parser.add_option(
+                "--width",
+                action="store", type="hex", dest="width",
+                help="use NUM bits in the polynomial",
+                metavar="NUM")
+        parser.add_option(
+                "--poly",
+                action="store", type="hex", dest="poly",
+                help="use HEX as polynomial",
+                metavar="HEX")
+        parser.add_option(
+                "--reflect-in",
+                action="store", type="bool", dest="reflect_in",
+                help="reflect the octets in the input message",
+                metavar="BOOL")
+        parser.add_option(
+                "--xor-in",
+                action="store", type="hex", dest="xor_in",
+                help="use HEX as initial value",
+                metavar="HEX")
+        parser.add_option(
+                "--reflect-out",
+                action="store", type="bool", dest="reflect_out",
+                help="reflect the resulting checksum before applying the --xor-out value",
+                metavar="BOOL")
+        parser.add_option(
+                "--xor-out",
+                action="store", type="hex", dest="xor_out",
+                help="xor the final CRC value with HEX",
+                metavar="HEX")
+        parser.add_option(
+                "--slice-by",
+                action="store", type="int", dest="slice_by",
+                help="read NUM bytes at a time from the input. NUM must be one of the values {4, 8, 16}",
+                metavar="NUM")
+        parser.add_option(
+                "--table-idx-width",
+                action="store", type="int", dest="table_idx_width",
+                help="use NUM bits to index the CRC table; NUM must be one of the values {1, 2, 4, 8}",
+                metavar="NUM")
+        parser.add_option(
+                "--force-poly",
+                action="store_true", dest="force_poly", default=False,
+                help="override any errors about possibly unsuitable polynoms")
+        parser.add_option(
+                "--symbol-prefix",
+                action="store", type="string", dest="symbol_prefix",
+                help="when generating source code, use STRING as prefix to the exported C symbols",
+                metavar="STRING")
+        parser.add_option(
+                "--crc-type",
+                action="store", type="string", dest="crc_type",
+                help="when generating source code, use STRING as crc_t type",
+                metavar="STRING")
+        parser.add_option(
+                "--include-file",
+                action="append", type="string", dest="include_files",
+                help="when generating source code, include also FILE as header file; "
+                "can be specified multiple times",
+                metavar="FILE")
+        parser.add_option(
+                "-o", "--output",
+                action="store", type="string", dest="output_file",
+                help="write the generated code to file instead to stdout",
+                metavar="FILE")
+
+        (options, args) = parser.parse_args(argv)
+
+        if options.c_std != None:
+            std = options.c_std.upper()
+            if std == "ANSI" or std == "C89":
+                self.c_std = "C89"
+            elif std == "C99":
+                self.c_std = std
+            else:
+                self.__error("unknown C standard {0:s}".format(options.c_std))
+
+        undefined_params = []
+        if options.width != None:
+            self.width = options.width
+        else:
+            undefined_params.append("--width")
+        if options.poly != None:
+            self.poly = options.poly
+        else:
+            undefined_params.append("--poly")
+        if options.reflect_in != None:
+            self.reflect_in = options.reflect_in
+        else:
+            undefined_params.append("--reflect-in")
+        if options.xor_in != None:
+            self.xor_in = options.xor_in
+        else:
+            undefined_params.append("--xor-in")
+        if options.reflect_out != None:
+            self.reflect_out = options.reflect_out
+        else:
+            undefined_params.append("--reflect-out")
+        if options.xor_out != None:
+            self.xor_out = options.xor_out
+        else:
+            undefined_params.append("--xor-out")
+
+        if options.table_idx_width != None:
+            if options.table_idx_width in set((1, 2, 4, 8)):
+                self.tbl_idx_width = options.table_idx_width
+                self.tbl_width = 1 << options.table_idx_width
+            else:
+                self.__error("unsupported table-idx-width {0:d}".format(options.table_idx_width))
+
+        if self.poly != None and self.poly % 2 == 0 and not options.force_poly:
+            self.__error("even polinomials are not allowed by default. Use --force-poly to override this.")
+
+        if self.width != None:
+            if self.width <= 0:
+                self.__error("Width must be strictly positive")
+            self.msb_mask = 0x1 << (self.width - 1)
+            self.mask = ((self.msb_mask - 1) << 1) | 1
+            if self.poly != None and self.poly >> (self.width + 1) != 0 and not options.force_poly:
+                self.__error("the polynomial is wider than the supplied Width. Use --force-poly to override this.")
+            if self.poly != None:
+                self.poly = self.poly & self.mask
+            if self.xor_in != None:
+                self.xor_in = self.xor_in & self.mask
+            if self.xor_out != None:
+                self.xor_out = self.xor_out & self.mask
+        else:
+            self.msb_mask = None
+            self.mask = None
+
+        if self.width == None or \
+                self.poly == None or \
+                self.reflect_in == None or \
+                self.xor_in == None or \
+                self.reflect_out == None or \
+                self.xor_out == None:
+            self.undefined_crc_parameters = True
+        else:
+            self.undefined_crc_parameters = False
+
+        if options.slice_by != None:
+            if options.slice_by in set((4, 8, 16)):
+                self.slice_by = options.slice_by
+            else:
+                self.__error("unsupported slice-by {0:d}".format(options.slice_by))
+            if self.undefined_crc_parameters:
+                self.__error("slice-by is only implemented for fully defined models")
+            if self.tbl_idx_width != 8:
+                self.__error("slice-by is only implemented for table-idx-width=8")
+            # FIXME tp: Fix corner cases and disable the following tests
+            if self.width < 8:
+                self.__warning("disabling slice-by for width {0}".format(self.width))
+                self.slice_by = 1
+            if self.width < 16:
+                self.__warning("disabling slice-by for width {0}".format(self.width))
+                self.slice_by = 1
+            if self.width > 32:
+                self.__warning("disabling slice-by for width {0}".format(self.width))
+                self.slice_by = 1
+            if not self.reflect_in:
+                self.__warning("disabling slice-by for non-reflected algorithm")
+                self.slice_by = 1
+# FIXME tp: reintroduce this?
+#            if self.width % 8 != 0:
+#                self.__error("slice-by is only implemented for width multiples of 8")
+#            if options.slice_by < self.width / 8:
+#                self.__error("slice-by must be greater or equal width / 8")
+            if self.c_std == "C89":
+                self.__error("--slice-by not supported for C89")
+
+        if options.algorithm != None:
+            alg = options.algorithm.lower()
+            if alg in set(["bit-by-bit", "bbb", "all"]):
+                self.algorithm |= self.algo_bit_by_bit
+            if alg in set(["bit-by-bit-fast", "bbf", "all"]):
+                self.algorithm |= self.algo_bit_by_bit_fast
+            if alg in set(["table-driven", "tbl", "all"]):
+                self.algorithm |= self.algo_table_driven
+            if self.algorithm == 0:
+                self.__error("unknown algorithm {0:s}".format(options.algorithm))
+
+        if options.symbol_prefix != None:
+            self.symbol_prefix = options.symbol_prefix
+        if options.include_files != None:
+            self.include_files = options.include_files
+        if options.crc_type != None:
+            self.crc_type = options.crc_type
+        if options.output_file != None:
+            self.output_file = options.output_file
+        op_count = 0
+        if options.check_string != None:
+            self.action = self.action_check_str
+            self.check_string = options.check_string
+            op_count += 1
+        if options.check_hexstring != None:
+            self.action = self.action_check_hex_str
+            self.check_string = options.check_hexstring
+            op_count += 1
+        if options.check_file != None:
+            self.action = self.action_check_file
+            self.check_file = options.check_file
+            op_count += 1
+        if options.generate != None:
+            arg = options.generate.lower()
+            if arg == 'h':
+                self.action = self.action_generate_h
+            elif arg == 'c':
+                self.action = self.action_generate_c
+            elif arg == 'c-main':
+                self.action = self.action_generate_c_main
+            elif arg == 'table':
+                self.action = self.action_generate_table
+            else:
+                self.__error("don't know how to generate {0:s}".format(options.generate))
+            op_count += 1
+
+            if self.action == self.action_generate_table:
+                if self.algorithm & self.algo_table_driven == 0:
+                    self.__error("the --generate table option is incompatible "
+                        "with the --algorithm option")
+                self.algorithm = self.algo_table_driven
+            elif self.algorithm not in set(
+                    [self.algo_bit_by_bit, self.algo_bit_by_bit_fast, self.algo_table_driven]):
+                self.__error("select an algorithm to be used in the generated file")
+        else:
+            if self.tbl_idx_width != 8:
+                self.__warning("reverting to Table Index Width = 8 "
+                    "for internal CRC calculation")
+                self.tbl_idx_width = 8
+                self.tbl_width = 1 << options.table_idx_width
+        if op_count == 0:
+            self.action = self.action_check_str
+        if op_count > 1:
+            self.__error("too many actions specified")
+
+        if len(args) != 0:
+            self.__error("unrecognized argument(s): {0:s}".format(" ".join(args)))
+
+        def_params_acts = (self.action_check_str, self.action_check_hex_str,
+                           self.action_check_file, self.action_generate_table)
+        if self.undefined_crc_parameters and self.action in set(def_params_acts):
+            self.__error("undefined parameters: Add {0:s} or use --model"
+                .format(", ".join(undefined_params)))
+        self.verbose = options.verbose
+
+
+
+    def __warning(self, message):
+        """
+        Print a warning message to stderr.
+        """
+        sys.stderr.write(
+            "{0:s}: warning: {1:s}\n".format(self.program_name, message))
+
+
+
+    def __error(self, message):
+        """
+        Print a error message to stderr and terminate the program.
+        """
+        sys.stderr.write(
+            "{0:s}: error: {1:s}\n".format(self.program_name, message))
+        sys.exit(1)
+
+
+def _model_cb(option, opt_str, value, parser):
+    """
+    This function sets up the single parameters if the 'model' option has been selected
+    by the user.
+    """
+    model_name = value.lower()
+    models = CrcModels()
+    model = models.get_params(model_name)
+    if model != None:
+        setattr(parser.values, 'width', model['width'])
+        setattr(parser.values, 'poly', model['poly'])
+        setattr(parser.values, 'reflect_in', model['reflect_in'])
+        setattr(parser.values, 'xor_in', model['xor_in'])
+        setattr(parser.values, 'reflect_out', model['reflect_out'])
+        setattr(parser.values, 'xor_out', model['xor_out'])
+    else:
+        models = CrcModels()
+        model_list = ", ".join(models.names())
+        raise OptionValueError(
+            "unsupported model {0:s}. Supported models are: {1:s}."
+            .format(value, model_list))
+
+
+def _check_hex(dummy_option, opt, value):
+    """
+    Checks if a value is given in a decimal integer of hexadecimal reppresentation.
+    Returns the converted value or rises an exception on error.
+    """
+    try:
+        if value.lower().startswith("0x"):
+            return int(value, 16)
+        else:
+            return int(value)
+    except ValueError:
+        raise OptionValueError(
+            "option {0:s}: invalid integer or hexadecimal value: {1:s}.".format(opt, value))
+
+
+def _check_bool(dummy_option, opt, value):
+    """
+    Checks if a value is given as a boolean value (either 0 or 1 or "true" or "false")
+    Returns the converted value or rises an exception on error.
+    """
+    if value.isdigit():
+        return int(value, 10) != 0
+    elif value.lower() == "false":
+        return False
+    elif value.lower() == "true":
+        return True
+    else:
+        raise OptionValueError("option {0:s}: invalid boolean value: {1:s}.".format(opt, value))
+
+
+class MyOption(Option):
+    """
+    New option parsing class extends the Option class
+    """
+    TYPES = Option.TYPES + ("hex", "bool")
+    TYPE_CHECKER = copy(Option.TYPE_CHECKER)
+    TYPE_CHECKER["hex"] = _check_hex
+    TYPE_CHECKER["bool"] = _check_bool
+
diff --git a/pycrc/symtable.py b/pycrc/symtable.py
new file mode 100644
index 0000000..e46ab9c
--- /dev/null
+++ b/pycrc/symtable.py
@@ -0,0 +1,352 @@
+#  pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+#  Copyright (c) 2006-2017  Thomas Pircher  <tehpeh-web@tty1.net>
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to
+#  deal in the Software without restriction, including without limitation the
+#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+#  sell copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+#  IN THE SOFTWARE.
+
+
+"""
+Symbol table for the macro processor used by pycrc.
+use as follows:
+
+    import pycrc.opt as opt
+    import pycrc.symtable as sym
+
+    opt = opt.Options()
+    sym = sym.SymbolTable(opt)
+
+    print(sym['crc_width'])
+    print('width: {crc_width}, poly: {crc_poly}'.format(**sym))
+"""
+
+from pycrc.algorithms import Crc
+import collections
+import time
+import os
+
+
+class SymbolTable(object):
+    def __init__(self, opt):
+        self.opt = opt
+
+
+class SymbolTable(collections.MutableMapping):
+    """A dictionary that applies an arbitrary key-altering
+       function before accessing the keys"""
+
+    def __init__(self, opt):
+        self.opt = opt
+        self.tbl_shift = _tbl_shift(opt)
+        self.cache = dict()
+        self.generator = dict({
+            'datetime': lambda: time.asctime(),
+            'program_version': lambda: self.opt.version_str,
+            'program_url': lambda: self.opt.web_address,
+            'filename': lambda: 'pycrc_stdout' if self.opt.output_file is None else os.path.basename(self.opt.output_file),
+            'header_filename': lambda: _pretty_header_filename(self.opt.output_file),
+            'header_protection': lambda: _pretty_hdrprotection(self.opt),
+
+            'crc_algorithm': lambda: _pretty_algorithm(self.opt),
+            'crc_width': lambda: _pretty_str(self.opt.width),
+            'crc_poly': lambda: _pretty_hex(self.opt.poly, self.opt.width),
+            'crc_reflect_in': lambda: _pretty_bool(self.opt.reflect_in),
+            'crc_xor_in': lambda: _pretty_hex(self.opt.xor_in, self.opt.width),
+            'crc_reflect_out': lambda: _pretty_bool(self.opt.reflect_out),
+            'crc_xor_out': lambda: _pretty_hex(self.opt.xor_out, self.opt.width),
+            'crc_slice_by': lambda: _pretty_str(self.opt.slice_by),
+            'crc_table_idx_width': lambda: str(self.opt.tbl_idx_width),
+            'crc_table_width': lambda: _pretty_str(1 << self.opt.tbl_idx_width),
+            'crc_table_mask': lambda: _pretty_hex(self.opt.tbl_width - 1, 8),
+            'crc_mask': lambda: _pretty_hex(self.opt.mask, self.opt.width),
+            'crc_msb_mask': lambda: _pretty_hex(self.opt.msb_mask, self.opt.width),
+            'crc_shift': lambda: _pretty_str(self.tbl_shift),
+
+            'cfg_width': lambda: self.__getitem__('crc_width') if self.opt.width is not None else 'cfg->width',
+            'cfg_poly': lambda: self.__getitem__('crc_poly') if self.opt.poly is not None else 'cfg->poly',
+            'cfg_reflect_in': lambda: self.__getitem__('crc_reflect_in') if self.opt.reflect_in is not None else 'cfg->reflect_in',
+            'cfg_xor_in': lambda: self.__getitem__('crc_xor_in') if self.opt.xor_in is not None else 'cfg->xor_in',
+            'cfg_reflect_out': lambda: self.__getitem__('crc_reflect_out') if self.opt.reflect_out is not None else 'cfg->reflect_out',
+            'cfg_xor_out': lambda: self.__getitem__('crc_xor_out') if self.opt.xor_out is not None else 'cfg->xor_out',
+            'cfg_table_idx_width': lambda: self.__getitem__('crc_table_idx_width') if self.opt.tbl_idx_width is not None else 'cfg->table_idx_width',
+            'cfg_table_width': lambda: self.__getitem__('crc_table_width') if self.opt.tbl_width is not None else 'cfg->table_width',
+            'cfg_mask': lambda: self.__getitem__('crc_mask') if self.opt.mask is not None else 'cfg->crc_mask',
+            'cfg_msb_mask': lambda: self.__getitem__('crc_msb_mask') if self.opt.msb_mask is not None else 'cfg->msb_mask',
+            'cfg_shift': lambda: self.__getitem__('crc_shift') if self.tbl_shift is not None else 'cfg->crc_shift',
+            'cfg_poly_shifted': lambda: '('+self.__getitem__('cfg_poly')+' << '+self.__getitem__('cfg_shift')+')' if self.tbl_shift is None or self.tbl_shift > 0 else self.__getitem__('cfg_poly'),
+            'cfg_mask_shifted': lambda: '('+self.__getitem__('cfg_mask')+' << '+self.__getitem__('cfg_shift')+')' if self.tbl_shift is None or self.tbl_shift > 0 else self.__getitem__('cfg_mask'),
+            'cfg_msb_mask_shifted': lambda: '('+self.__getitem__('cfg_msb_mask')+' << '+self.__getitem__('cfg_shift')+')' if self.tbl_shift is None or self.tbl_shift > 0 else self.__getitem__('cfg_msb_mask'),
+
+            'c_bool': lambda: 'int' if self.opt.c_std == 'C89' else 'bool',
+            'c_true': lambda: '1' if self.opt.c_std == 'C89' else 'true',
+            'c_false': lambda: '0' if self.opt.c_std == 'C89' else 'false',
+
+            'underlying_crc_t': lambda: _get_underlying_crc_t(self.opt),
+            'crc_t': lambda: self.opt.symbol_prefix + 't',
+            'cfg_t': lambda: self.opt.symbol_prefix + 'cfg_t',
+            'crc_reflect_function': lambda: self.opt.symbol_prefix + 'reflect',
+            'crc_table_gen_function': lambda: self.opt.symbol_prefix + 'table_gen',
+            'crc_init_function': lambda: self.opt.symbol_prefix + 'init',
+            'crc_update_function': lambda: self.opt.symbol_prefix + 'update',
+            'crc_finalize_function': lambda: self.opt.symbol_prefix + 'finalize',
+
+            'crc_init_value': lambda: _get_init_value(self.opt),
+            'crc_table_init': lambda: _get_table_init(self.opt),
+        })
+
+    def __getitem__(self, key):
+        """
+        Return the value for the requested key
+        """
+        if key in self.cache:
+            return self.cache[key]
+        if key not in self.generator:
+            raise KeyError(key)
+        generator = self.generator[key]
+        val = self.generator[key]()
+        self.cache[key] = val
+        return val
+
+    def __setitem__(self, key, value):
+        self.generator[key] = value
+
+    def __delitem__(self, key):
+        del self.generator[key]
+
+    def __iter__(self):
+        return iter(self.generator)
+
+    def __len__(self):
+        return len(self.generator)
+
+
+
+def _pretty_str(value):
+    """
+    Return a value of width bits as a pretty string.
+    """
+    if value is None:
+        return 'Undefined'
+    return str(value)
+
+
+def _pretty_hex(value, width=None):
+    """
+    Return a value of width bits as a pretty hexadecimal formatted string.
+    """
+    if value is None:
+        return 'Undefined'
+    if width is None:
+        return '{0:#x}'.format(value)
+    width = (width + 3) // 4
+    hex_str = "{{0:#0{0:d}x}}".format(width + 2)
+    return hex_str.format(value)
+
+
+def _pretty_bool(value):
+    """
+    Return a boolen value of width bits as a pretty formatted string.
+    """
+    if value is None:
+        return 'Undefined'
+    return 'True' if value else 'False'
+
+
+def _pretty_algorithm(opt):
+    """
+    Return the algorithm name.
+    """
+    if opt.algorithm == opt.algo_bit_by_bit:
+        return 'bit-by-bit'
+    elif opt.algorithm == opt.algo_bit_by_bit_fast:
+        return 'bit-by-bit-fast'
+    elif opt.algorithm == opt.algo_table_driven:
+        return 'table-driven'
+    else:
+        return 'UNDEFINED'
+
+def _pretty_header_filename(filename):
+    """
+    Return the sanitized filename of a header file.
+    """
+    if filename is None:
+        return 'pycrc_stdout.h'
+    filename = os.path.basename(filename)
+    if filename[-2:] == '.c':
+        return filename[0:-1] + 'h'
+    else:
+        return filename + '.h'
+
+
+def _pretty_hdrprotection(opt):
+    """
+    Return the name of a C header protection (e.g. CRC_IMPLEMENTATION_H).
+    """
+    if opt.output_file is None:
+        filename = 'pycrc_stdout'
+    else:
+        filename = os.path.basename(opt.output_file)
+    out_str = ''.join([s.upper() if s.isalnum() else '_' for s in filename])
+    return out_str
+
+
+def _get_underlying_crc_t(opt):
+    """
+    Return the C type of the crc_t typedef.
+    """
+    # pylint: disable=too-many-return-statements, too-many-branches
+
+    if opt.crc_type is not None:
+        return opt.crc_type
+    if opt.c_std == 'C89':
+        if opt.width is None:
+            return 'unsigned long int'
+        if opt.width <= 8:
+            return 'unsigned char'
+        elif opt.width <= 16:
+            return 'unsigned int'
+        else:
+            return 'unsigned long int'
+    else:   # C99
+        if opt.width is None:
+            return 'unsigned long long int'
+        if opt.width <= 8:
+            return 'uint_fast8_t'
+        elif opt.width <= 16:
+            return 'uint_fast16_t'
+        elif opt.width <= 32:
+            return 'uint_fast32_t'
+        elif opt.width <= 64:
+            return 'uint_fast64_t'
+        elif opt.width <= 128:
+            return 'uint_fast128_t'
+        else:
+            return 'uintmax_t'
+
+
+def _get_init_value(opt):
+    """
+    Return the init value of a C implementation, according to the selected
+    algorithm and to the given options.
+    If no default option is given for a given parameter, value in the cfg_t
+    structure must be used.
+    """
+    if opt.algorithm == opt.algo_bit_by_bit:
+        if opt.xor_in is None or opt.width is None or opt.poly is None:
+            return None
+        crc = Crc(
+            width=opt.width, poly=opt.poly,
+            reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+            reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+            table_idx_width=opt.tbl_idx_width)
+        init = crc.nondirect_init
+    elif opt.algorithm == opt.algo_bit_by_bit_fast:
+        if opt.xor_in is None:
+            return None
+        init = opt.xor_in
+    elif opt.algorithm == opt.algo_table_driven:
+        if opt.reflect_in is None or opt.xor_in is None or opt.width is None:
+            return None
+        if opt.poly is None:
+            poly = 0
+        else:
+            poly = opt.poly
+        crc = Crc(
+            width=opt.width, poly=poly,
+            reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+            reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+            table_idx_width=opt.tbl_idx_width)
+        if opt.reflect_in:
+            init = crc.reflect(crc.direct_init, opt.width)
+        else:
+            init = crc.direct_init
+    else:
+        init = 0
+    return _pretty_hex(init, opt.width)
+
+
+def _get_simple_table(opt, crc_tbl, values_per_line, format_width, indent):
+    """
+    Get one CRC table, formatted as string with appropriate indenting and
+    line breaks.
+    """
+    out = ""
+    for i in range(opt.tbl_width):
+        if i % values_per_line == 0:
+            out += " " * indent
+        tbl_val = _pretty_hex(crc_tbl[i], format_width)
+        if i == (opt.tbl_width - 1):
+            out += "{0:s}".format(tbl_val)
+        elif i % values_per_line == (values_per_line - 1):
+            out += "{0:s},\n".format(tbl_val)
+        else:
+            out += "{0:s}, ".format(tbl_val)
+    return out
+
+
+def _get_table_init(opt):       # TODO: change to return a list
+    """
+    Return the precalculated CRC table for the table_driven implementation.
+    """
+    if opt.algorithm != opt.algo_table_driven:
+        return "0"
+    if opt.width is None or opt.poly is None or opt.reflect_in is None:
+        return "0"
+    crc = Crc(
+        width=opt.width, poly=opt.poly,
+        reflect_in=opt.reflect_in,
+        xor_in=0, reflect_out=False, xor_out=0,     # set unimportant variables to known values
+        table_idx_width=opt.tbl_idx_width,
+        slice_by=opt.slice_by)
+    crc_tbl = crc.gen_table()
+    if opt.width > 32:
+        values_per_line = 4
+    elif opt.width >= 16:
+        values_per_line = 8
+    else:
+        values_per_line = 16
+    format_width = max(opt.width, 8)
+    if opt.slice_by == 1:
+        indent = 4
+    else:
+        indent = 8
+
+    out = [''] * opt.slice_by
+    for i in range(opt.slice_by):
+        out[i] = _get_simple_table(opt, crc_tbl[i], values_per_line, format_width, indent)
+    fixed_indent = ' ' * (indent - 4)
+    out = '{0:s}{{\n'.format(fixed_indent) + \
+        '\n{0:s}}},\n{0:s}{{\n'.format(fixed_indent).join(out) + \
+        '\n{0:s}}}'.format(fixed_indent)
+    if opt.slice_by == 1:
+        return out
+    return '{\n' + out + '\n}'
+
+
+def _tbl_shift(opt):
+    """
+    Return the table shift value
+    """
+    if opt.algorithm == opt.algo_table_driven and (opt.width is None or opt.width < 8):
+        if opt.width is None:
+            return None
+        else:
+            return 8 - opt.width
+    else:
+        return 0
+