Squashed 'third_party/pycrc/' content from commit cb91196b9

Change-Id: Iaed6f7d683e3c11395f10f0724f973363aad2cdb
git-subtree-dir: third_party/pycrc
git-subtree-split: cb91196b920d1f892c05941ed470c7a80cba7596
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a72d066
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+.svn
+.*.swp
+*.pyc
+*.pyo
+__pycache__
+build
+doc/pycrc.1
+doc/pycrc.html
+doc/docbook.css
+test/pycrc_files.tar.gz
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..3c04ca9
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,15 @@
+language: python
+python:
+    - "2.6"
+    - "2.7"
+    - "3.2"
+    - "3.3"
+    - "3.4"
+    - "3.5"
+    - "3.6"
+
+install:
+    python setup.py install
+
+script:
+    python test/test.py -av
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e81101d
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,14 @@
+Thomas Pircher: main developer.
+
+Matthias Urlichs: removed the unused 'direct' parameter and added a fix not to
+    recurse into main() when an unknown algorithm is selected.
+
+Marti Raudsepp: improved spacing for the table-driven algorithm.
+
+Stephan Brumme: his implementation of the slice-by-x algorithm was used as a
+    basis for the implementation in pycrc.
+
+Danjel McGougan: whose Universal Crc project was highly influential in the
+    implementation of widths < 8 in the table-driven algorithm.
+
+André Hartmann, ashelly and others for minor fixes.
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..a086a96
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,511 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+For a detailed list of changes see the [pycrc GitHub][pycrc github] page.
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+
+
+## [v0.9.1] - 2017-09-09
+
+### Added
+- Added setup.py script to install pycrc on the system, if desired.
+- Added checks about possibly unsuitable polynomials. Use the --force-poly
+  option to override the error message.
+
+### Changed
+- Completely rewritten the code generator back-end. The new back-end is more
+  flexible and allows for a better optimisation of the generated expressions.
+- Moved the python code under the `pycrc` directory and changed how the pycrc
+  sub-modules are included. Before one would write `import crc_xxx`, now one
+  would write `import pycrc.xxx`.
+- New license for the documentation:
+  [Creative Commons Attribution-Share Alike 4.0 Unported License][CC-BY-SA-4.0].
+
+### Fixed
+- Fixed binary files handling with Python 2.7.
+  Fixes #11. Thanks to James Bowman.
+- Fixed some spelling. Thanks to Frank (ftheile) and ashelly.
+- Fixed Header Guard generation. Don't use underscores to start the header
+  guard name. Thanks to Andre Hartmann.
+
+
+## [v0.9] - 2016-01-06
+
+### Added
+- Added Stephan Brumme to the `AUTHORS` file as his implementation of the
+  slice-by algorithm is the basis for pycrc's implementation.
+- Added a new option `--slice-by`. This option is still experimental and
+  limited in its use.
+
+### Changed
+- Documented the experimental `--slice-by option`.
+- Simplified the implementation where Width is less than 8 bits.
+- Run the code through `pylint`.
+- __API change__: changed the names of the member variables from `CamelCase` to the
+  format suggested in `PEP 0008` (lowercase letters and words separated by
+  underscore).
+
+### Fixed
+- Suppressed the `crc_reflect` function where not needed. Addresses part of #8.
+  Thanks to Craig McQueen.
+- Allow strings with values greater than 0x80 in `--check-hexstring`.
+- When the CRC width is less than 8 then the `bit-by-bit` algorithm needs to
+  apply the CRC mask to the final value.
+  Fixes #10. Thanks to Steve Geo.
+- Fixed the initial value of the 16-bit `CCITT` algorithm. Renamed the model
+  from `ccitt` to `crc-16-ccitt`.
+  Fixes #7. Thanks to Craig McQueen.
+
+
+## [v0.8.3] - 2015-08-31
+
+### Changed
+- pycrc has a new [homepage][pycrc home].
+- The [issue tracker on GitHub][pycrc issues]
+  is now advertised as the preferred issue tracker.
+- Applied some minor optimisations to the generated table-driven code.
+- Belatedly added an authors file. Should I have forgotten to mention someone
+  please don't hesitate to send a mail.
+- Upgraded documentation to DocBook 5.
+- Removed sourceforge mailing list from `README.md` in an effort to move pycrc
+  away from sourceforge.
+- Removed the experimental `--bitwise-expression` option to facilitate
+  restructuring of the code.
+- The preferred format for the input data for the Python API is now a byte
+  array. But if a string is supplied it is decoded as UTF-8 string.
+  Alternative formats are not supported and must be passed to the functions
+  as byte arrays.
+- Changed the signature of the `crc_update()` function: the data argument is
+  now a pointer to void to improve compatibility with C++.
+  Thanks to Kamil Szczygieł.
+  This closes GitHub issue #4.
+
+
+## [v0.8.2] - 2014-12-04
+
+### Changed
+- Smaller code cleanups.
+- Stated more clearly that the bitwise expression algorithm is experimental in
+  the documentation.
+- Fixed a typo in the documentation.
+  The description previously stated:
+  "The reflected value of 0xa3 (10100010b) is 0x45 (01000101b)"
+  but this should be:
+  "The reflected value of 0xa2 (10100010b) is 0x45 (01000101b)"
+  Thanks to Andreas Nebenfuehr for reporting the mistake.
+- Small cleanups.
+  Added a tests for special cases. For now, added `crc-5` with non-inverted
+  input. This test is currently failing.
+- Removed warning about even polynomials. As Lars Pötter rightly pointed out,
+  polynomials may be even.
+  Added a caveat emptor about even polinomials in the documentation.
+
+### Fixed
+- The table-driven code for polynomials of width < 8 using a table index
+  width < 8 was producing a wrong checksum.
+  Thanks to Radosław Gancarz.
+- Updated the generated code to cope with big Widths (>32 bits) on 32 bit
+  processors.
+  Since C89 does not give a way to specify the minimum length of a data type,
+  the test does not validate C89 code using Widths > 32.
+  For C99, the `uint_fastN_t` data types are used or long long, if the Width is
+  unknown.
+
+
+## [v0.8.1] - 2013-05-17
+
+### Changed
+- Updated [qm.py from GitHub][qm github].
+- Explicitly stated that the output of pycrc is not considered a substantial
+  part of the code of pycrc in `README.md`.
+- Re-organised the symbol table: grouped the code by functionality, not by
+  algorithm.
+- The input to the CRC routines can now be bytes or strings.
+- Minor formatting change in the manpage.
+- Better python3 compatibility.
+- Added the files generated with the `bwe` algorithm to `check_files.sh`.
+
+### Fixed
+- Fixed a bug in the handling of hexstrings in Python3.
+  Thanks to Matthias Kuehlewein.
+- Added `--check-hexstring` to the tests.
+- Remove obsolete and unused `direct` parameter.
+  Merge pull request #2 from smurfix/master.
+  Thanks to Matthias Urlichs.
+- Don't recurse into main() when an unknown algorithm is selected.
+  Merge pull request #2 from smurfix/master.
+  Thanks to Matthias Urlichs.
+
+
+## [v0.8] - 2013-01-04
+
+### Added
+- Merged (private) bitwise-expression branch to main.
+  This adds the highly experimental `bitwise-expression` (`bwe`) code generator
+  target, which might one day be almost as fast as the table-driven code but
+  much smaller.
+  At the moment the generated code is bigger and slower than any other
+  algorithm, so use at your own risk.
+
+### Changed
+- Now it is possible to specify the `--include` option multiple times.
+- Completely revisited and reworked the documentation.
+- Updated the command line help screen with more useful command descriptions.
+- Removed the `-*- coding: Latin-1 -*-` string.
+- Updated the copyright year to 2013.
+- Renamed abbreviations to `bbb`, `bbf`, `tbl`.
+- It is possible now to abbreviate the algorithms (`bbb` for `bit-by-bit`,
+  `bbf` for `bit-by-bit-fast` and `tbl` for `table-driven`).
+  Added the list of supported CRC models to the error message when an
+  unknown model parameter was supplied.
+- Documented the possibility to abbreviate the algorithms. Minor
+  improvements in the documentation.
+- Added a note to `README.md` that version 0.7.10 of pycrc is the last one
+  known to work with Python 2.4.
+- Updated a link to the list of CRC models.
+- Renamed i`README` to `README.md`.
+- Updated link to the [Catalogue of parametrised CRC algorithms][crc catalogue].
+
+
+## [v0.7.11] - 2012-10-20
+
+### Changed
+- Improved Python3 compatibility. pycrc now requires Python 2.6 or later.
+- Added a test for compiled standard models.
+
+### Fixed
+- Fixed a wrong `check` value of the `crc-64-jones` model.
+- Don't use `snprintf()` with `c89` code, changed to `sprintf()`.
+- Deleted `test.sh` shell script and replaced it with `test.py`.
+
+
+## [v0.7.10] - 2012-02-13
+
+### Added
+- Added the models `crc-12-3gpp`, `crc-16-genibus`, `crc-32-bzip2` and `crc-64-xz`.
+  Taken from [Greg Cook's Catalogue of parametrised CRC algorithms][crc catalogue].
+
+### Changed
+- Bad-looking C code generated; make sure the `bit-by-bit`(`-fast`) code does not
+  contain two instructions on one line. Thanks to "intgr" for the fix.
+- Some small code clean-up: use `set()` when appropriate.
+
+### Fixed
+- Fixed a mistake in the man page that still used the old model name
+  `crc-32mpeg` instead of `crc-32-mpeg`.  Thanks to Marek Erban.
+
+
+## [v0.7.9] - 2011-12-08
+
+### Fixed
+- Fixed a bug in the generated C89 code that included `stdint.h`.
+  Thanks to Frank (ftheile).
+  Closes issue 3454356.
+- Fixed a bug in the generated C89 code when using a 64 bit CRC.
+- Using the `--verbose` option made pycrc quit without error message.
+
+
+## [v0.7.8] - 2011-07-10
+
+### Changed
+- When generating C code for the C89 or ANSI standard, don't include `stdint.h`.
+  This closes issue 3338930
+- If no output file name is given while generating a C file, then pycrc will
+  `#include` a hypothetical `pycrc.h` file instead of a `stdout.h` file.
+  Also, added a comment on that line to make debugging easier.
+  Closes issue 3325109.
+- Removed unused variable `this_option_optind` in the generated option parser.
+
+
+## [v0.7.7] - 2011-02-11
+
+### Changed
+- Updated the copyright year.
+  Fixed some coding style issues found by `pylint` and `pychecker`.
+
+### Fixed
+- Substituted the deprecated function `atoi()` with `int()`. Closes issue 3136566.
+  Thanks to Tony Smith.
+- Updated the documentation using Windows-style calls to the Python interpreter.
+
+
+## [v0.7.6] - 2010-10-21
+
+### Changed
+- Rewritten macro parser from scratch. Simplified the macro language.
+- Changed a simple division (/) to a integer division (//) for Python3
+  compatibility.
+
+### Fixed
+- Fixed a minor bug in the command line parsing of the generated main function.
+
+
+## [v0.7.5] - 2010-03-28
+
+### Added
+- Python implementation of the `table-driven` algorithm can handle widths less
+  than 8.
+- Suppressed warnings of unused cfg structure on partially defined models.
+
+### Removed
+- Removed the half-baken and confusing `--direct` option.
+
+### Changed
+- C/C++ code can now be generated for the table-driven algorithm with widths
+  that are not byte-aligned or less than 8.
+  This feature was heavily inspired by a similar feature in Danjel McGougan's
+  [Universal Crc][universal crc].
+- __API change__: introduced new variable `crc_shift`, member of the `crc_cfg_t`
+  structure, which must be initialised manually when the width was undefined
+  during C/C++ code generation.
+- Minor code cleanup.
+
+
+## [v0.7.4] - 2010-01-24
+
+### Added
+- Added `crc-16-modbus`. Closes issue 2896611.
+
+### Changed
+- Changed the `xor-in` value of the `crc-64-jones` model.
+- Set xmodem parameters equal to the `zmodem` parameters.
+- Generate more uniform error messages.
+- Added a warning for even polynomials.
+
+### Fixed
+- Fix for unused variable argv.
+  Closes issue 2893224. Thanks to Marko von Oppen.
+
+
+## [v0.7.3] - 2009-10-25
+
+### Added
+- Added `crc-64-jones` CRC model. Thanks to Waterspirit.
+
+### Changed
+- Renamed `crc-32mpeg` to `crc-32-mpeg`.
+
+
+## [v0.7.2] - 2009-09-30
+
+### Fixed
+- Fixed a bug that caused the result of the Python `table-driven` code not
+  being evaluated at all.
+  Closes issue 2870630. Thanks to Ildar Muslukhov.
+
+
+## [v0.7.1] - 2009-04-05
+
+### Added
+- Added `crc-32mpeg`. Thanks to Thomas Edwards.
+
+
+## [v0.7] - 2009-02-27
+
+### Added
+- Added the `--direct` option.
+- Added `--check-hexstring` option. Closes issue 2545183.
+  Thanks to Arnim Littek.
+- Added a check for extra arguments on the command line.
+  Closes issue 2545185. Thanks to Arnim Littek.
+
+### Changed
+- Added one more example in the documentation.
+
+
+## [v0.6.7] - 2008-12-11
+
+### Changed
+- Run Python's 2to3 script on all files.
+  Check the code on a x64 platform.
+- Fixed a bug that raised an exception when an unknown model was selected.
+
+
+## [v0.6.6] - 2008-06-05
+
+### Changed
+- New license for the documentation:
+  [Creative Commons Attribution-Share Alike 3.0 Unported License][CC-BY-SA-3.0].
+
+### Fixed
+- Fixed a bug in the `print_params()` function. Closes issue 1985197.
+  Thanks to Artur Lipowski.
+
+
+## [v0.6.5] - 2008-03-03
+
+### Added
+- Added dallas-1-wire 8 bit CRC.
+- Added `r-crc-16 model` (DECT (cordless digital standard) packets A-field
+  according to ETSI EN 300 175-3 v2.1.1).
+  Thanks to "raimondo".
+- Added `--crc-type` and `--include-file` options.
+- Added new file to handle CRC models.
+
+### Changed
+- Added extern "C" declaration to the generated C header file.
+  Thanks to Nathan Royer.
+- Changed the API to take the CRC model direct as parameter. Deleted the need
+  for an obscure `opt` object.
+
+### Fixed
+- Fixed a problem with the generated code for bit-by-bit-fast algorithms.
+  Thanks to Hans Bacher.
+
+
+## [v0.6.4] - 2007-12-05
+
+### Fixed
+- Fixed a bug in the code generator for the `table-driven`
+  algorithm. Thanks to Tom McDermott. Closes issue 1843774
+
+
+## [v0.6.3] - 2007-10-13
+
+### Added
+- Added new models: `crc-5`, `crc-15`, `crc-16-usb`, `crc-24`, `crc-64`.
+  The new models are taken from Ray Burr's CrcMoose.
+
+### Fixed
+- Fixed some portability problems in the generated code.
+  Thanks to Helmut Bauer. Closes issue 1812894.
+- The option `--check-file` works now with `--width` < 8. Closes issue 1794343.
+- Removed unnecessary restriction on the width when using the `bit-by-bit-fast`
+  algorithm. Closes issue 1794344.
+
+
+## [v0.6.2] - 2007-08-25
+
+### Changed
+- Simplified the table-driven code. Closes issue 1727128.
+- Changed the macro language syntax to a better format.
+- Renamed `crc_code_gen.py` to `crc_parser.py`.
+- Documented the usage of the `crc_*` modules.
+
+### Fixed
+- The parameter to `--check-string` was ignored. Closes issue 1781637.
+
+
+## [v0.6.1] - 2007-08-12
+
+### Added
+- Added test for C89 compilation.
+- Added a test case to loop over the input bytes one by one.
+
+### Removed
+- Deleted obsolete options.
+
+### Changed
+- Tidied up the documentation.
+  Code cleanup.
+
+### Fixed
+- Bugfix in the source code generator for C89:
+  Compilation error due to mismatch of parameters in the `crc_finalize`
+  funtion.
+- Changes related to 919107: Code generator includes `reflect()` function even
+  if not needed.
+- Fixed a typo in the C89 source code generator.
+  Thanks to Helmut Bauer.
+
+
+## [v0.6] - 2007-05-21
+
+### Added
+- Added the `--std` option to generate C89 (ANSI) compliant code.
+- Added a new check to the test script which validate all possible
+  combination of undefined parameters.
+- Made the generated main function cope with command line arguments.
+- Added the `--generate` table option.
+- Added a template engine for the code generation. Split up `pycrc.py` into
+  smaller modules.
+- Added obsolete options again tor legacy reasons.
+- Added a better handling of the `--model` parameter.
+
+### Changed
+- Reduced the size of the symbol table by re-arranging items.
+- Changed licence to the MIT licence. This makes the additional clause for
+  generated source code obsolete.
+  Changed all command line options with underscores to hyphen (e.g.
+  `table_driven` becomes `table-driven`).
+  Added the option `--generate` which obsoletes the old options `--generate_c`
+  `--generate_h` etc.
+
+
+## [v0.5] - 2007-03-25
+
+### Fixed
+- Fixed bug 1686404: unhandled exception when called with both options
+  `--table_idx_width` and `--check_file`.
+- Eliminated useless declaration of `crc_reflect`, when not used.
+- Corrected typos in the documentation.
+
+
+## [v0.4] - 2007-01-26
+
+### Added
+- Added more parameter sets (now supported: `crc-8`, `crc-16`, `citt`, `kermit`,
+  `x-25`, `xmodem`, `zmodem`, `crc-32`, `crc-32c`, `posix`, `jam`, `xfer`) from
+  [Greg Cook's Catalogue of parametrised CRC algorithms][crc catalogue].
+- Added Doxygen documentation strings to the functions.
+- Added the `--symbol_prefix` option.
+- Added the `--check_file` option.
+- Added a non-regression test on the generated C source.
+
+### Changed
+- Eliminated needless documentation of not generated functions.
+- Many corrections to the manual (thanks Francesca) Documented the new
+  parameter sets.
+- Added some new tests, disabled the random loop.
+
+### Fixed
+- Corrected many typos and bad phrasing (still a lot to do) Documented the
+  `--symbol_prefix` option.
+
+
+## [v0.3] - 2007-01-14
+
+### Added
+- First public release pycrc v0.3
+
+
+
+[Unreleased]: https://github.com/tpircher/pycrc
+[v0.9.1]: https://github.com/tpircher/pycrc/releases/tag/v0.9.1
+[v0.9]: https://github.com/tpircher/pycrc/releases/tag/v0.9
+[v0.8.3]: https://github.com/tpircher/pycrc/releases/tag/v0.8.3
+[v0.8.2]: https://github.com/tpircher/pycrc/releases/tag/v0.8.2
+[v0.8.1]: https://github.com/tpircher/pycrc/releases/tag/v0.8.1
+[v0.8]: https://github.com/tpircher/pycrc/releases/tag/v0.8
+[v0.7.11]: https://github.com/tpircher/pycrc/releases/tag/v0.7.11
+[v0.7.10]: https://github.com/tpircher/pycrc/releases/tag/v0.7.10
+[v0.7.9]: https://github.com/tpircher/pycrc/releases/tag/v0.7.9
+[v0.7.8]: https://github.com/tpircher/pycrc/releases/tag/v0.7.8
+[v0.7.7]: https://github.com/tpircher/pycrc/releases/tag/v0.7.7
+[v0.7.6]: https://github.com/tpircher/pycrc/releases/tag/v0.7.6
+[v0.7.5]: https://github.com/tpircher/pycrc/releases/tag/v0.7.5
+[v0.7.4]: https://github.com/tpircher/pycrc/releases/tag/v0.7.4
+[v0.7.3]: https://github.com/tpircher/pycrc/releases/tag/v0.7.3
+[v0.7.2]: https://github.com/tpircher/pycrc/releases/tag/v0.7.2
+[v0.7.1]: https://github.com/tpircher/pycrc/releases/tag/v0.7.1
+[v0.7]: https://github.com/tpircher/pycrc/releases/tag/v0.7
+[v0.6.7]: https://github.com/tpircher/pycrc/releases/tag/v0.6.7
+[v0.6.6]: https://github.com/tpircher/pycrc/releases/tag/v0.6.6
+[v0.6.5]: https://github.com/tpircher/pycrc/releases/tag/v0.6.5
+[v0.6.4]: https://github.com/tpircher/pycrc/releases/tag/v0.6.4
+[v0.6.3]: https://github.com/tpircher/pycrc/releases/tag/v0.6.3
+[v0.6.2]: https://github.com/tpircher/pycrc/releases/tag/v0.6.2
+[v0.6.1]: https://github.com/tpircher/pycrc/releases/tag/v0.6.1
+[v0.6]: https://github.com/tpircher/pycrc/releases/tag/v0.6
+[v0.5]: https://github.com/tpircher/pycrc/releases/tag/v0.5
+[v0.4]: https://github.com/tpircher/pycrc/releases/tag/v0.4
+[v0.3]: https://github.com/tpircher/pycrc/releases/tag/v0.3
+
+[pycrc home]: https://pycrc.org
+[pycrc github]: https://github.com/tpircher/pycrc
+[pycrc issues]: https://github.com/tpircher/pycrc/issues
+[crc catalogue]: http://regregex.bbcmicro.net/crc-catalogue.htm
+[universal crc]: http://mcgougan.se/universal_crc/
+[qm github]: https://github.com/tpircher/quine-mccluskey
+[CC-BY-SA-3.0]: https://creativecommons.org/licenses/by-sa/3.0/
+[CC-BY-SA-4.0]: https://creativecommons.org/licenses/by-sa/4.0/
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..9f90d03
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+Copyright (c) 2006-2015, 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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cab802b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,80 @@
+
+
+                         _ __  _   _  ___ _ __ ___
+                        | '_ \| | | |/ __| '__/ __|
+                        | |_) | |_| | (__| | | (__
+                        | .__/ \__, |\___|_|  \___|
+                        |_|    |___/
+
+                             https://pycrc.org
+
+
+pycrc is a free, easy to use Cyclic Redundancy Check (CRC) calculator and C
+source code generator.
+
+
+
+System Requirements
+===================
+
+pycrc requires Python 2.6 or later. Python 3.x is supported.
+The last version compatible with Python 2.4 is pycrc v0.7.10.
+
+
+Running pycrc
+=============
+
+This program doesn't need to be installed to be called. The script can be
+executed from the source directory.
+Simply call the python interpreter with the script as parameter:
+
+    python pycrc.py [options]
+
+On a UNIX-like system, you can make the pycrc.py wrapper script executable and
+call it like a normal binary:
+
+    chmod +x pycrc.py
+    ./pycrc.py [options]
+
+
+Installation
+============
+
+Install pycrc (if required) using the setup.py script:
+
+    python setup.py install
+
+
+Getting help
+============
+
+If you are new to pycrc and want to generate C code, start with
+[the tutorial](https://pycrc.org/tutorial.html).
+
+The [pycrc manual page](https://pycrc.org/pycrc.html) explains the command line
+options in some detail and also gives some more examples how to use pycrc.
+
+If you have found a bug in pycrc or want to request a feature please take the
+time and submit it to the
+[issue tracker](https://github.com/tpircher/pycrc/issues).
+Thanks for your help.
+
+Also see the [frequently asked questions](https://pycrc.org/faq.html).
+
+
+Feedback
+========
+
+If you like pycrc, let me know and drop me a note. If you don't like pycrc let
+me know what you don't like and why. In both cases, I would really appreciate
+some [feed back](https://sourceforge.net/projects/pycrc/reviews/).
+If you want some idea how to say thanks for this software, please have a look
+[here](https://www.tty1.net/say-thanks_en.html).
+
+
+Copyright of the generated source code
+======================================
+
+The code generated by pycrc is not considered a substantial portion of the
+software, therefore the licence does not cover the generated code, and the
+author of pycrc will not claim any copyright on the generated code.
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..a0f2581
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,24 @@
+HTML_PARAMS	= style-html.xsl
+MAN_PARAMS	= style-man.xsl
+
+source		= pycrc.xml
+targets		= $(source:.xml=.html) $(source:.xml=.1)
+
+all: $(targets)
+
+.PHONY: clean
+clean:
+	$(RM) $(targets)
+
+.PHONY: check
+check:
+	xmllint --valid --noout $(source)
+
+%.html: %.xml $(HTML_PARAMS)
+	saxon-xslt -o $@ $^
+
+%.1: %.xml $(MAN_PARAMS)
+	saxon-xslt -o $@ $^
+
+%.txt: %.html
+	links -dump -no-numbering -no-references $< > $@
diff --git a/doc/pycrc.xml b/doc/pycrc.xml
new file mode 100644
index 0000000..9f5a4a2
--- /dev/null
+++ b/doc/pycrc.xml
@@ -0,0 +1,681 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V5.1//EN"
+        "http://www.oasis-open.org/docbook/xml/5.0b5/dtd/docbook.dtd" [
+<!ENTITY project_version    "0.9.1">
+<!ENTITY project_homepage   "https://pycrc.org">
+<!ENTITY project_models     "https://pycrc.org/models.html">
+<!ENTITY date               "2017-08-11">
+<!ENTITY author_firstname   "Thomas">
+<!ENTITY author_surname     "Pircher">
+<!ENTITY author_email       "tehpeh-web@tty1.net">
+<!ENTITY bit-by-bit         "bit-by-bit">
+<!ENTITY bbb                "bbb">
+<!ENTITY bit-by-bit-fast    "bit-by-bit-fast">
+<!ENTITY bbf                "bbf">
+<!ENTITY table-driven       "table-driven">
+<!ENTITY tbl                "tbl">
+<!ENTITY slice-by           "slice-by">
+<!ENTITY width          "Width">
+<!ENTITY poly           "Polynomial">
+<!ENTITY reflect_in     "ReflectIn">
+<!ENTITY xor_in         "XorIn">
+<!ENTITY reflect_out    "ReflectOut">
+<!ENTITY xor_out        "XorOut">
+<!ENTITY check          "Check">
+]>
+
+
+<refentry xmlns='http://docbook.org/ns/docbook' version="5.0" xml:id="pycrc">
+    <info>
+        <title>pycrc</title>
+        <productname>pycrc</productname>
+        <productnumber>&project_version;</productnumber>
+        <author>
+            <personname>
+                <firstname>&author_firstname;</firstname>
+                <surname>&author_surname;</surname>
+            </personname>
+            <contrib>Author of pycrc and this manual page.</contrib>
+            <email>&author_email;</email>
+        </author>
+        <date>&date;</date>
+    </info>
+
+    <refmeta>
+        <refentrytitle>pycrc</refentrytitle>
+        <manvolnum>1</manvolnum>
+    </refmeta>
+
+    <refnamediv>
+        <refname>pycrc</refname>
+        <refpurpose>a free, easy to use Cyclic Redundancy Check (CRC) calculator and C source code generator.</refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+        <cmdsynopsis>
+            <command>python pycrc.py</command>
+            <arg>OPTIONS</arg>
+        </cmdsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1>
+        <title>Description</title>
+        <para>
+            <link xlink:href="&project_homepage;">pycrc</link>
+            is a CRC reference implementation in Python and a C source code generator for parametrised CRC models.
+            The generated C source code can be optimised for simplicity,
+            speed or small memory footprint, as required on small embedded systems.
+
+            The following operations are implemented:
+            <itemizedlist>
+                <listitem>
+                    <para>calculate the checksum of a string (ASCII or hex)</para>
+                </listitem>
+                <listitem>
+                    <para>calculate the checksum of a file</para>
+                </listitem>
+                <listitem>
+                    <para>generate the header and source files for a C implementation.</para>
+                </listitem>
+            </itemizedlist>
+        </para>
+        <para>
+            pycrc supports the following variants of the CRC algorithm:
+            <itemizedlist>
+                <listitem>
+                    <para><replaceable>&bit-by-bit;</replaceable> or <replaceable>&bbb;</replaceable>:
+                        the basic algorithm which operates individually on every bit of the augmented message
+                        (i.e. the input data with <replaceable>&width;</replaceable> zero bits added at the end).
+                        This algorithm is a straightforward implementation of the basic polynomial division and
+                        is the easiest one to understand, but it is also the slowest one among all possible
+                        variants.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para><replaceable>&bit-by-bit-fast;</replaceable> or <replaceable>&bbf;</replaceable>:
+                        a variation of the simple <replaceable>&bit-by-bit;</replaceable> algorithm.
+                        This algorithm still iterates over every bit of the message, but does not augment
+                        it (does not add <replaceable>&width;</replaceable> zero bits at the end).
+                        It gives the same result as the <replaceable>&bit-by-bit;</replaceable> method by
+                        carefully choosing the initial value of the algorithm.
+                        This method might be a good choice for embedded platforms, where code space is more
+                        important than execution speed.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para><replaceable>&table-driven;</replaceable> or <replaceable>&tbl;</replaceable>:
+                        the standard table driven algorithm.
+                        This is the fastest variant because it operates on one byte at a time, as opposed to one
+                        bit at the time.
+                        This method uses a look-up table (usually of 256 elements), which might not be acceptable
+                        for small embedded systems. The number of elements in the look-up table can be reduced
+                        with the <option>--table-idx-width</option> command line switch.
+                        The value of 4 bits for the table index (16 elements in the look-up table) can be a good
+                        compromise between execution speed and code size.
+                    </para>
+                    <para>
+                        The <option>--slice-by</option> option enables a variant of the <replaceable>&table-driven;</replaceable>
+                        algorithm that operates on 32 bits of data or more at a time rather than 8 bits.
+                        This can dramatically speed-up the calculation of the CRC, at the cost of
+                        increased code and data size.
+                        <emphasis>Note</emphasis>: this option is experimental and not well-tested.
+                        Check your results and please raise bugs if you find problems.
+                    </para>
+                </listitem>
+            </itemizedlist>
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title>Options</title>
+        <variablelist>
+            <varlistentry>
+                <term>
+                    <option>--version</option>
+                </term>
+                <listitem>
+                    <para>show the program version number and exit.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>-h</option>
+                </term>
+                <term>
+                    <option>--help</option>
+                </term>
+                <listitem>
+                    <para>show this help message and exit.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--verbose</option>
+                </term>
+                <listitem>
+                    <para>be more verbose; in particular, print the value of the parameters and the chosen model to <filename>stdout</filename>.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--check-string=</option><replaceable>STRING</replaceable>
+                </term>
+                <listitem>
+                    <para>calculate the checksum of a string (default: <quote><replaceable>123456789</replaceable></quote>). If the string contains non-ASCII characters then it will be UTF-8 decoded.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--check-hexstring=</option><replaceable>STRING</replaceable>
+                </term>
+                <listitem>
+                    <para>calculate the checksum of a hexadecimal number string.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--check-file=</option><replaceable>FILE</replaceable>
+                </term>
+                <listitem>
+                    <para>calculate the checksum of a file. If the file contains non-ASCII characters then it will be UTF-8 decoded.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--generate=</option><replaceable>CODE</replaceable>
+                </term>
+                <listitem>
+                    <para>generate C source code; choose the type from {<replaceable>h</replaceable>,
+                    <replaceable>c</replaceable>, <replaceable>c-main</replaceable>, <replaceable>table</replaceable>}.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--std=</option><replaceable>STD</replaceable>
+                </term>
+                <listitem>
+                    <para>specify the C dialect of the generated code from {C89, ANSI, C99}.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--algorithm=</option><replaceable>ALGO</replaceable>
+                </term>
+                <listitem>
+                    <para>choose an algorithm from {<replaceable>bit-by-bit</replaceable>, <replaceable>bbb</replaceable>,
+                    <replaceable>bit-by-bit-fast</replaceable>, <replaceable>bbf</replaceable>,
+                    <replaceable>table-driven</replaceable>, <replaceable>tbl</replaceable>,
+                    <replaceable>all</replaceable>}.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--model=</option><replaceable>MODEL</replaceable>
+                </term>
+                <listitem>
+                    <para>choose a parameter set from
+                       {<replaceable>crc-5</replaceable>,
+                        <replaceable>crc-8</replaceable>,
+                        <replaceable>dallas-1-wire</replaceable>,
+                        <replaceable>crc-12-3gpp</replaceable>,
+                        <replaceable>crc-15</replaceable>,
+                        <replaceable>crc-16</replaceable>,
+                        <replaceable>crc-16-usb</replaceable>,
+                        <replaceable>crc-16-modbus</replaceable>,
+                        <replaceable>crc-16-genibus</replaceable>,
+                        <replaceable>crc-16-ccitt</replaceable>,
+                        <replaceable>r-crc-16</replaceable>,
+                        <replaceable>kermit</replaceable>,
+                        <replaceable>x-25</replaceable>,
+                        <replaceable>xmodem</replaceable>,
+                        <replaceable>zmodem</replaceable>,
+                        <replaceable>crc-24</replaceable>,
+                        <replaceable>crc-32</replaceable>,
+                        <replaceable>crc-32c</replaceable>,
+                        <replaceable>crc-32-mpeg</replaceable>,
+                        <replaceable>crc-32-bzip2</replaceable>,
+                        <replaceable>posix</replaceable>,
+                        <replaceable>jam</replaceable>,
+                        <replaceable>xfer</replaceable>,
+                        <replaceable>crc-64</replaceable>,
+                        <replaceable>crc-64-jones</replaceable>,
+                        <replaceable>crc-64-xz</replaceable>}.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--width=</option><replaceable>NUM</replaceable>
+                </term>
+                <listitem>
+                    <para>use <replaceable>NUM</replaceable> bits in the <replaceable>&poly;</replaceable>.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--poly=</option><replaceable>HEX</replaceable>
+                </term>
+                <listitem>
+                    <para>use <replaceable>HEX</replaceable> as <replaceable>&poly;</replaceable>.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--reflect-in=</option><replaceable>BOOL</replaceable>
+                </term>
+                <listitem>
+                    <para>reflect the octets in the input message.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--xor-in=</option><replaceable>HEX</replaceable>
+                </term>
+                <listitem>
+                    <para>use <replaceable>HEX</replaceable> as initial value.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--reflect-out=</option><replaceable>BOOL</replaceable>
+                </term>
+                <listitem>
+                    <para>reflect the resulting checksum before applying the &xor_out; value.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--xor-out=</option><replaceable>HEX</replaceable>
+                </term>
+                <listitem>
+                    <para>xor the final CRC value with <replaceable>HEX</replaceable>.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--slice-by=</option><replaceable>NUM</replaceable>
+                </term>
+                <listitem>
+                    <para>speed-up the &table-driven; calculation by operating on
+                        <replaceable>NUM</replaceable> octets of data rather than a
+                        single octet at a time.
+                        <replaceable>NUM</replaceable> must be one of the values
+                        {<replaceable>4</replaceable>, <replaceable>8</replaceable>,
+                        <replaceable>16</replaceable>}.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--table-idx-width=</option><replaceable>NUM</replaceable>
+                </term>
+                <listitem>
+                    <para>use <replaceable>NUM</replaceable> bits to index the CRC table;
+                        <replaceable>NUM</replaceable> must be one of the values
+                        {<replaceable>1</replaceable>, <replaceable>2</replaceable>,
+                        <replaceable>4</replaceable>, <replaceable>8</replaceable>}.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--force-poly</option>
+                </term>
+                <listitem>
+                    <para>override any errors about possibly unsuitable
+                        polynoms. pycrc does not allow even polynoms or
+                        polynoms that are wider than &width;. Use this option
+                        to override the error, if you know what you are
+                        doing.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--symbol-prefix=</option><replaceable>STRING</replaceable>
+                </term>
+                <listitem>
+                    <para>when generating source code, use <replaceable>STRING</replaceable>
+                        as prefix to the exported C symbols.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--crc-type=</option><replaceable>STRING</replaceable>
+                </term>
+                <listitem>
+                    <para>when generating source code, use <replaceable>STRING</replaceable> as crc_t type.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>--include-file=</option><replaceable>FILE</replaceable>
+                </term>
+                <listitem>
+                    <para>when generating source code, include also <replaceable>FILE</replaceable> as header file.
+                        This option can be specified multiple times.</para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>-o</option><replaceable>FILE</replaceable>
+                </term>
+                <term>
+                    <option>--output=</option><replaceable>FILE</replaceable>
+                </term>
+                <listitem>
+                    <para>write the generated code to <replaceable>FILE</replaceable> instead of <filename>stdout</filename>.</para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsect1>
+
+    <refsect1>
+        <title>The CRC Parametric Model</title>
+        <para>
+            The parametric model follows Ross N. Williams' convention described in
+            <link xlink:href="http://www.ross.net/crc/crcpaper.html">A Painless Guide to CRC Error Detection Algorithms</link>,
+            often called the Rocksoft Model.
+            Since most people are familiar with this kind of parameters, pycrc follows this convention, described as follows:
+            <glosslist>
+                <glossentry>
+                    <glossterm><replaceable>&width;</replaceable></glossterm>
+                    <glossdef>
+                        <para>
+                        The number of significant bits in the CRC <replaceable>&poly;</replaceable>,
+                        excluding the most significant 1.
+                        This will also be the number of bits in the final CRC result.
+                        In previous versions of pycrc only multiples of 8 could be used as
+                        <replaceable>&width;</replaceable> for the <replaceable>&table-driven;</replaceable> algorithm.
+                        As of version 0.7.5 any value is accepted for <replaceable>&width;</replaceable> for all algorithms.
+                        </para>
+                    </glossdef>
+                </glossentry>
+                <glossentry>
+                    <glossterm><replaceable>&poly;</replaceable></glossterm>
+                    <glossdef>
+                        <para>
+                        The unreflected polynomial of the CRC algorithm.
+                        </para>
+                        <para>
+                        The <replaceable>&poly;</replaceable> may be specified in its standard form,
+                        i.e. with bit <replaceable>&width;</replaceable>+1 set to 1, but the most significant
+                        bit may also be omitted.
+                        For example, both numbers 0x18005 and 0x8005 are accepted for a 16-bit
+                        <replaceable>&poly;</replaceable>.
+                        </para>
+                        <para>
+                        Most polynomials used in real world applications are odd (the least significant
+                        bit is 1), but there are some good even ones.
+                        pycrc allows the use of even polynomials with the <option>--force-poly</option>
+                        option.
+                        Some even polynomials may yield incorrect checksums depending on the used algorithm.
+                        Use at your own risk and if at all possible use a well-known <replaceable>MODEL</replaceable> above.
+                        </para>
+                    </glossdef>
+                </glossentry>
+                <glossentry>
+                    <glossterm><replaceable>&reflect_in;</replaceable></glossterm>
+                    <glossdef>
+                        <para>
+                        Reflect the octets of the message before processing them.
+                        </para>
+                        <para>
+                        A word is reflected or reversed by <quote>flipping</quote> its bits around the
+                        mid-point of the word.
+                        The most significant bit of the word is moved to the least significant position,
+                        the second-most significant bit is moved to the second-least significant position
+                        and so on.
+                        The reflected value of 0xa2 (10100010b) is 0x45 (01000101b), for example.
+                        </para>
+                        <para>
+                        Some CRC algorithms can be implemented more efficiently in a bit reversed version,
+                        that's why many of the standard CRC models use reflected input octets.
+                        </para>
+                    </glossdef>
+                </glossentry>
+                <glossentry>
+                    <glossterm><replaceable>&xor_in;</replaceable></glossterm>
+                    <glossdef>
+                        <para>
+                        The initial value (usually all 0 or all 1) for algorithms which operate on the
+                        non-augmented message, that is, any algorithm other than the
+                        <replaceable>&bit-by-bit;</replaceable> one.
+                        This value can be interpreted as a value which will be XOR-ed into the CRC register
+                        after <replaceable>&width;</replaceable> iterations of the
+                        <replaceable>&bit-by-bit;</replaceable> algorithm.
+                        This implies that the simple <replaceable>&bit-by-bit;</replaceable> algorithm must
+                        calculate the initial value using some sort of reverse CRC algorithm on the
+                        <replaceable>&xor_in;</replaceable> value.
+                        </para>
+                    </glossdef>
+                </glossentry>
+                <glossentry>
+                    <glossterm><replaceable>&reflect_out;</replaceable></glossterm>
+                    <glossdef>
+                        <para>
+                        Reflect the final CRC result. This operation takes place before XOR-ing the final CRC
+                        value with the <replaceable>&xor_out;</replaceable> parameter.
+                        </para>
+                    </glossdef>
+                </glossentry>
+                <glossentry>
+                    <glossterm><replaceable>&xor_out;</replaceable></glossterm>
+                    <glossdef>
+                        <para>
+                        A value (usually all bits 0 or all 1) which will be XOR-ed to the final CRC value.
+                        </para>
+                    </glossdef>
+                </glossentry>
+                <glossentry>
+                    <glossterm><replaceable>&check;</replaceable></glossterm>
+                    <glossdef>
+                        <para>
+                        This value is not exactly a parameter of a model but it is sometimes given together
+                        with the Rocksoft Model parameters.
+                        It is the CRC value of the parametrised model over the string
+                        <quote><replaceable>123456789</replaceable></quote> and
+                        can be used as a sanity check for a particular CRC implementation.
+                        </para>
+                    </glossdef>
+                </glossentry>
+            </glosslist>
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title>Code generation</title>
+        <para>
+        In the default configuration, the generated code is strict ISO C99.
+        A minimal set of three functions are defined for each algorithm:
+        <function>crc_init()</function>, <function>crc_update()</function> and <function>crc_finalize()</function>.
+        Depending on the number of parameters given to pycrc, a different interface will be defined.
+        A fully parametrised model has a simpler API, while the generated code for a runtime-specified
+        implementation requires a pointer to a configuration structure as first parameter to all functions.
+        </para>
+        <para>
+        The generated source code uses the type <type>crc_t</type>, which is used throughout the code
+        to hold intermediate results and also the final CRC value.
+        It is defined in the generated header file and its type may be overridden with the
+        <option>--crc-type</option> option.
+        </para>
+
+        <refsect2><title>Fully parametrised models</title>
+            <para>
+            The prototypes of the CRC functions are normally generated by pycrc using the
+            <replaceable>--generate h</replaceable> option.
+            The CRC functions for a fully parametrised model will look like:
+            </para>
+            <funcsynopsis>
+                <funcsynopsisinfo>
+#include &lt;stdlib.h&gt;
+typedef uint16_t crc_t;         /* pycrc will use an appropriate size here */
+                </funcsynopsisinfo>
+                <funcprototype>
+                    <?dbhtml funcsynopsis-style='ansi'?>
+                    <funcdef>crc_t <function>crc_init</function></funcdef>
+                    <void/>
+                </funcprototype>
+
+                <funcprototype>
+                    <?dbhtml funcsynopsis-style='ansi'?>
+                    <funcdef>crc_t <function>crc_update</function></funcdef>
+                    <paramdef>crc_t <parameter>crc</parameter></paramdef>
+                    <paramdef>const unsigned char *<parameter>data</parameter></paramdef>
+                    <paramdef>size_t <parameter>data_len</parameter></paramdef>
+                </funcprototype>
+
+                <funcprototype>
+                    <?dbhtml funcsynopsis-style='ansi'?>
+                    <funcdef>crc_t <function>crc_finalize</function></funcdef>
+                    <paramdef>crc_t <parameter>crc</parameter></paramdef>
+                </funcprototype>
+            </funcsynopsis>
+
+            <para>
+            The code snippet below shows how to use the generated functions.
+            <programlisting>
+#include "pycrc_generated_crc.h"
+#include &lt;stdio.h&gt;
+
+int main(void)
+{
+    static const unsigned char str1[] = "1234";
+    static const unsigned char str2[] = "56789";
+    crc_t crc;
+
+    crc = crc_init();
+    crc = crc_update(crc, str1, sizeof(str1) - 1);
+    crc = crc_update(crc, str2, sizeof(str2) - 1);
+    /* more calls to crc_update... */
+    crc = crc_finalize(crc);
+
+    printf("0x%lx\n", (long)crc);
+    return 0;
+}
+            </programlisting>
+            </para>
+        </refsect2>
+
+        <refsect2>
+            <title>Models with runtime-configurable parameters</title>
+            <para>
+            When the model is not fully defined then the missing parameters are stored in a structure of
+            type <type>crc_cfg_t</type>.
+            If a CRC function requires a value from the <type>crc_cfg_t</type> structure, then the first
+            function argument is always a pointer to that structure.
+            All fields of the configuration structure must be properly initialised before the first call
+            to any CRC function.
+            </para>
+            <para>
+            If the <replaceable>&width;</replaceable> was not specified when the code was generated, then
+            the <type>crc_cfg_t</type> structure will contain three more fields:
+            <parameter>msb_mask</parameter>, <parameter>crc_mask</parameter> and <parameter>crc_shift</parameter>.
+            They are defined for performance reasons and must be initialised to the value given next to the
+            field definition.
+            </para>
+            <para>
+            For example, a completely undefined CRC implementation will generate a <type>crc_cfg_t</type>
+            structure as below:
+            <programlisting>
+typedef struct {
+    unsigned int width;
+    crc_t poly;
+    bool reflect_in;
+    crc_t xor_in;
+    bool reflect_out;
+    crc_t xor_out;
+
+    // internal parameters
+    crc_t msb_mask;             // initialise as (crc_t)1u &lt;&lt; (cfg-&gt;width - 1)
+    crc_t crc_mask;             // initialise as (cfg-&gt;msb_mask - 1) | cfg-&gt;msb_mask
+    unsigned int crc_shift;     // initialise as cfg-&gt;width &lt; 8 ? 8 - cfg-&gt;width : 0
+} crc_cfg_t;
+            </programlisting>
+            </para>
+            <para>
+            <parameter>msb_mask</parameter> is a bitmask with the most significant bit of a
+            <replaceable>&width;</replaceable> bits wide data type set to 1.
+
+            <parameter>crc_mask</parameter> is a bitmask with all bits of a
+            <replaceable>&width;</replaceable> bits wide data type set to 1.
+
+            <parameter>crc_shift</parameter> is a shift counter that is used when
+            <replaceable>&width;</replaceable> is less than 8.
+            It is the number of bits to shift the CRC register to align its top bit to a byte boundary.
+            </para>
+
+            <para>
+            The file <filename>test/main.c</filename> in the source package of pycrc
+            contains a fully featured example of how to use the generated source code.
+            A shorter, more compact <code>main()</code> function can be generated with the
+            <replaceable>--generate c-main</replaceable> option.
+            This second variant is the better option as it will always output valid code when
+            some of the CRC parameters are known and some are unknown during code generation.
+            </para>
+        </refsect2>
+    </refsect1>
+
+    <refsect1><title>Examples</title>
+        <para>
+            <glosslist>
+                <glossentry>
+                    <glossterm>Calculate the CRC-32 checksum of the string <quote>123456789</quote>:</glossterm>
+                    <glossdef>
+                        <para>
+                        <userinput>python pycrc.py --model crc-32 --check-string 123456789</userinput>
+                        </para>
+                    </glossdef>
+                </glossentry>
+                <glossentry>
+                    <glossterm>Generate the source code of the table-driven algorithm for an embedded application.</glossterm>
+                    <glossdef>
+                        <para>
+                        The table index width of 4 bits ensures a moderate memory usage.
+                        To be precise, the size of the resulting table will be <code>16 * sizeof(crc_t)</code>.
+                        </para>
+                        <para>
+                        <userinput>python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate h -o crc.h</userinput>
+                        </para>
+                        <para>
+                        <userinput>python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c -o crc.c</userinput>
+                        </para>
+                        <para>
+                        A variant of the <replaceable>c</replaceable> target is <replaceable>c-main</replaceable>:
+                        this target will generate a simple <replaceable>main()</replaceable> function in addition to
+                        the CRC functions:
+                        </para>
+                        <para>
+                        <userinput>python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c-main -o crc.c</userinput>
+                        </para>
+                    </glossdef>
+                </glossentry>
+                <glossentry>
+                    <glossterm>Generate the CRC table only:</glossterm>
+                    <glossdef>
+                        <para>
+                        <userinput>python pycrc.py --model kermit --generate table -o crc-table.txt</userinput>
+                        </para>
+                    </glossdef>
+                </glossentry>
+            </glosslist>
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title>See Also</title>
+        <para>
+            The homepage of pycrc is <link xlink:href="&project_homepage;">&project_homepage;</link>.
+        </para>
+        <para>
+            A list of common CRC models is at <link xlink:href="&project_models;">&project_models;</link>.
+            For a long list of known CRC models, see Greg Cook's
+            <link xlink:href="http://reveng.sourceforge.net/crc-catalogue/">Catalogue of Parameterised CRC Algorithms</link>.
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title>Copyright</title>
+        <para>
+            This work is licensed under a
+            <link xlink:href="https://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International</link>.
+        </para>
+    </refsect1>
+</refentry>
diff --git a/doc/style-html.xsl b/doc/style-html.xsl
new file mode 100644
index 0000000..3f9cb89
--- /dev/null
+++ b/doc/style-html.xsl
@@ -0,0 +1,14 @@
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:import href="file:///usr/share/xml/docbook/stylesheet/docbook-xsl-ns/xhtml5/docbook.xsl"/>
+
+<xsl:output encoding="UTF-8" indent="no" method="html"/>
+<xsl:param name="default.table.frame"   select="none"/>
+<xsl:param name="html.cleanup"          select="1"/>
+<xsl:param name="make.valid.html"       select="1"/>
+
+<xsl:template name="user.head.content">
+    <meta name="viewport" content="width=device-width, initial-scale=1"/>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/style-man.xsl b/doc/style-man.xsl
new file mode 100644
index 0000000..639b454
--- /dev/null
+++ b/doc/style-man.xsl
@@ -0,0 +1,6 @@
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:import href="file:///usr/share/xml/docbook/stylesheet/docbook-xsl-ns/manpages/docbook.xsl"/>
+
+
+</xsl:stylesheet>
diff --git a/pycrc.py b/pycrc.py
new file mode 100755
index 0000000..2dd1612
--- /dev/null
+++ b/pycrc.py
@@ -0,0 +1,31 @@
+#!/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/__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
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..7d270ae
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,12 @@
+from distutils.core import setup
+
+from pycrc import progname, version, url
+
+setup(name = 'pycrc',
+        version = version,
+        description = 'Free, easy to use Cyclic Redundancy Check source code generator for C/C++',
+        author = 'Thomas Pircher',
+        author_email = 'tehpeh-web@tty1.net',
+        url = url,
+        packages = ['pycrc'],
+        )
diff --git a/test/check_files.sh b/test/check_files.sh
new file mode 100755
index 0000000..4cc874f
--- /dev/null
+++ b/test/check_files.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+set -e
+
+PYCRC=`dirname $0`/../pycrc.py
+outdir_old="/tmp/pycrc_out"
+outdir_new="/tmp/pycrc_new"
+tarfile="pycrc_files.tar.gz"
+
+usage() {
+        echo >&2 "usage: $0 [OPTIONS]"
+        echo >&2 ""
+        echo >&2 "with OPTIONS in"
+        echo >&2 "        -c    check the generated output"
+        echo >&2 "        -g    generate the database"
+        echo >&2 "        -n    no cleanup: don't delete the directories with the generated code"
+        echo >&2 "        -h    this help message"
+}
+
+
+opt_check=off
+opt_no_cleanup=off
+opt_generate=off
+
+while getopts cgnh opt; do
+    case "$opt" in
+        c)  opt_check=on;;
+        g)  opt_generate=on;;
+        n)  opt_no_cleanup=on;;
+        h)  usage
+            exit 0
+            ;;
+        \?) usage       # unknown flag
+            exit 1
+            ;;
+    esac
+done
+shift `expr $OPTIND - 1`
+
+if [ -e "$outdir_old" ]; then
+    echo >&2 "Output directory $outdir_old exists!"
+    exit 1
+fi
+if [ -e "$outdir_new" ]; then
+    echo >&2 "Output directory $outdir_new exists!"
+    exit 1
+fi
+
+
+cleanup() {
+    if [ "$opt_no_cleanup" = "on" ]; then
+        echo "No cleanup. Please delete $outdir_old and $outdir_new when you're done"
+    else
+        rm -rf "$outdir_old" "$outdir_new"
+    fi
+}
+
+trap cleanup 0 1 2 3 15
+
+
+generate() {
+    outfile="$1"
+    shift
+    $PYCRC "$@" -o "${outfile}"
+    sed -i -e 's/Generated on ... ... .. ..:..:.. ..../Generated on XXX XXX XX XX:XX:XX XXXX/; s/by pycrc v[0-9.]*/by pycrc vXXX/;' "${outfile}"
+}
+
+populate() {
+    outdir=$1
+    mkdir -p "$outdir"
+    models=`PYTHONPATH=.. python -c 'import pycrc.models as m; print(" ".join(m.CrcModels().names()))'`
+    for model in "undefined" $models; do
+        for algo in "bbb" "bbf" "tbl"; do
+            for cstd in c98 c99; do
+                if [ "$model" = "undefined" ]; then
+                    mod_opt=
+                else
+                    mod_opt="--model=${model}"
+                fi
+                generate "${outdir}/${model}_${algo}_${cstd}.h" --generate=h --algorithm=${algo} $mod_opt
+                generate "${outdir}/${model}_${algo}_${cstd}.c" --generate=c --algorithm=${algo} $mod_opt
+            done
+        done
+    done
+
+    algo=tbl
+    for model in crc-32; do
+        for slice in 4 8 16; do
+            for cstd in c98 c99; do
+                generate "${outdir}/${model}_${algo}_sb${slice}_${cstd}.h" --generate=h --algorithm=${algo} --model=${model} --slice-by ${slice}
+                generate "${outdir}/${model}_${algo}_sb${slice}_${cstd}.c" --generate=c --algorithm=${algo} --model=${model} --slice-by ${slice}
+            done
+        done
+    done
+}
+
+do_check() {
+    tar xzf "$tarfile" -C "`dirname $outdir_new`"
+    populate "$outdir_new"
+    diff -ru "$outdir_old" "$outdir_new"
+}
+
+
+if [ "$opt_check" = "on" ]; then
+    if [ ! -f "$tarfile" ]; then
+        echo >&2 "Can't find tarfile $tarfile"
+        exit 1
+    fi
+    do_check
+fi
+
+if [ "$opt_generate" = "on" ]; then
+    populate "$outdir_old"
+    dirname="`dirname $outdir_old`"
+    basename="`basename $outdir_old`"
+    tar czf "$tarfile" -C "$dirname" "$basename"
+fi
diff --git a/test/main.c b/test/main.c
new file mode 100644
index 0000000..252d4fd
--- /dev/null
+++ b/test/main.c
@@ -0,0 +1,283 @@
+//  Copyright (c) 2006-2013  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.
+
+#include "crc.h"
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <string.h>
+
+static bool atob(const char *str);
+static crc_t xtoi(const char *str);
+static int get_config(int argc, char *argv[], crc_cfg_t *cfg);
+#if CRC_ALGO_BIT_BY_BIT
+static crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc);
+static crc_t crc_reflect(crc_t data, size_t data_len);
+#endif
+
+
+
+static bool verbose = false;
+static unsigned char str[256] = "123456789";
+
+bool atob(const char *str)
+{
+    if (!str) {
+        return 0;
+    }
+    if (isdigit(str[0])) {
+        return (bool)atoi(str);
+    }
+    if (tolower(str[0]) == 't') {
+        return true;
+    }
+    return false;
+}
+
+crc_t xtoi(const char *str)
+{
+    crc_t ret = 0;
+
+    if (!str) {
+        return 0;
+    }
+    if (str[0] == '0' && tolower(str[1]) == 'x') {
+        str += 2;
+        while (*str) {
+            if (isdigit(*str))
+                ret = 16 * ret + *str - '0';
+            else if (isxdigit(*str))
+                ret = 16 * ret + tolower(*str) - 'a' + 10;
+            else
+                return ret;
+            str++;
+        }
+    } else if (isdigit(*str)) {
+        while (*str) {
+            if (isdigit(*str))
+                ret = 10 * ret + *str - '0';
+            else
+                return ret;
+            str++;
+        }
+    }
+    return ret;
+}
+
+
+int get_config(int argc, char *argv[], crc_cfg_t *cfg)
+{
+    int c;
+    int option_index;
+    static struct option long_options[] = {
+        {"width",           1, 0, 'w'},
+        {"poly",            1, 0, 'p'},
+        {"reflect-in",      1, 0, 'n'},
+        {"xor-in",          1, 0, 'i'},
+        {"reflect-out",     1, 0, 'u'},
+        {"xor-out",         1, 0, 'o'},
+        {"verbose",         0, 0, 'v'},
+        {"check-string",    1, 0, 's'},
+        {"table-idx-with",  1, 0, 't'},
+        {0, 0, 0, 0}
+    };
+
+    while (1) {
+        option_index = 0;
+
+        c = getopt_long(argc, argv, "w:p:ni:uo:v", long_options, &option_index);
+        if (c == -1)
+            break;
+
+        switch (c) {
+            case 0:
+                printf("option %s", long_options[option_index].name);
+                if (optarg)
+                    printf(" with arg %s", optarg);
+                printf ("\n");
+            case 'w':
+                cfg->width = atoi(optarg);
+                break;
+            case 'p':
+                cfg->poly = xtoi(optarg);
+                break;
+            case 'n':
+                cfg->reflect_in = atob(optarg);
+                break;
+            case 'i':
+                cfg->xor_in = xtoi(optarg);
+                break;
+            case 'u':
+                cfg->reflect_out = atob(optarg);
+                break;
+            case 'o':
+                cfg->xor_out = xtoi(optarg);
+                break;
+            case 's':
+                memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str));
+                str[sizeof(str) - 1] = '\0';
+                break;
+            case 'v':
+                verbose = true;
+                break;
+            case 't':
+                // ignore --table_idx_width option
+                break;
+            case '?':
+                return -1;
+            case ':':
+                fprintf(stderr, "missing argument to option %c\n", c);
+                return -1;
+            default:
+                fprintf(stderr, "unhandled option %c\n", c);
+                return -1;
+        }
+    }
+    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;
+
+    cfg->poly &= cfg->crc_mask;
+    cfg->xor_in &= cfg->crc_mask;
+    cfg->xor_out &= cfg->crc_mask;
+    return 0;
+}
+
+
+#if CRC_ALGO_BIT_BY_BIT
+crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc)
+{
+    crc_t result;
+    unsigned char data;
+    unsigned int i;
+
+    // don't verify if the width is not a multiple of 8
+    if (cfg->width % 8) {
+        return 0;
+    }
+    if (cfg->xor_out) {
+        crc ^= cfg->xor_out;
+    }
+    if (cfg->reflect_out) {
+        crc = crc_reflect(crc, cfg->width);
+    }
+    result = crc_pre_final;
+    for (i = 0; i < cfg->width / 8; i++) {
+        data = (crc >> (cfg->width - 8 * i - 8)) & 0xff;
+        if (cfg->reflect_in) {
+            data = crc_reflect(data, 8);
+        }
+        result = crc_update(cfg, result, &data, 1);
+    }
+    // no crc_finalize, because if the CRC calculation is correct, result == 0.
+    // A crc_finalize would XOR-in again some ones into the solution.
+    // In theory the finalize function of the bit-by-bit algorithm
+    // would also loop over cfg->width zero bits, but since
+    // a) result == 0, and
+    // b) input data == 0
+    // the output would always be zero
+    return result;
+}
+
+crc_t crc_reflect(crc_t data, size_t data_len)
+{
+    unsigned int i;
+    crc_t ret;
+
+    ret = 0;
+    for (i = 0; i < data_len; i++)
+    {
+        if (data & 0x01) {
+            ret = (ret << 1) | 1;
+        } else {
+            ret = ret << 1;
+        }
+        data >>= 1;
+    }
+    return ret;
+}
+#endif       // CRC_ALGO_BIT_BY_BIT
+
+
+int main(int argc, char *argv[])
+{
+    crc_cfg_t cfg = {
+        0,      // width
+        0,      // poly
+        0,      // xor_in
+        0,      // reflect_in
+        0,      // xor_out
+        0,      // reflect_out
+
+        0,      // crc_mask
+        0,      // msb_mask
+        0,      // crc_shift
+    };
+    crc_t crc;
+    crc_t crc_test, crc_pre_final;
+    char format[20];
+    int ret, i;
+
+    ret = get_config(argc, argv, &cfg);
+    if (ret == 0) {
+#       if CRC_ALGO_TABLE_DRIVEN
+        crc_table_gen(&cfg);
+#       endif       // CRC_ALGO_TABLE_DRIVEN
+        crc = crc_init(&cfg);
+        crc = crc_pre_final = crc_update(&cfg, crc, str, strlen((char *)str));
+        crc = crc_finalize(&cfg, crc);
+
+#       if CRC_ALGO_BIT_BY_BIT
+        if (crc_verify(&cfg, crc_pre_final, crc) != 0) {
+            fprintf(stderr, "error: crc verification failed\n");
+            return 1;
+        }
+#       endif
+
+        // calculate the checksum again, but this time loop over the input
+        // bytes one-by-one.
+        crc_test = crc_init(&cfg);
+        for (i = 0; str[i]; i++)
+        {
+            crc_test = crc_update(&cfg, crc_test, str + i, 1);
+        }
+        crc_test = crc_finalize(&cfg, crc_test);
+        if (crc_test != crc) {
+            fprintf(stderr, "error: crc loop verification failed\n");
+            return 1;
+        }
+
+        if (verbose) {
+            snprintf(format, sizeof(format), "%%-16s = 0x%%0%dx\n", (unsigned int)(cfg.width + 3) / 4);
+            printf("%-16s = %d\n", "width", (unsigned int)cfg.width);
+            printf(format, "poly", (unsigned int)cfg.poly);
+            printf("%-16s = %s\n", "reflect_in", cfg.reflect_in ? "true": "false");
+            printf(format, "xor_in", cfg.xor_in);
+            printf("%-16s = %s\n", "reflect_out", cfg.reflect_out ? "true": "false");
+            printf(format, "xor_out", (unsigned int)cfg.xor_out);
+            printf(format, "crc_mask", (unsigned int)cfg.crc_mask);
+            printf(format, "msb_mask", (unsigned int)cfg.msb_mask);
+        }
+        printf("0x%llx\n", (unsigned long long int)crc);
+    }
+    return !ret;
+}
diff --git a/test/performance.sh b/test/performance.sh
new file mode 100755
index 0000000..7b6b239
--- /dev/null
+++ b/test/performance.sh
@@ -0,0 +1,147 @@
+#!/bin/sh
+set -e
+
+PYCRC=`dirname $0`/../pycrc.py
+
+cleanup() {
+    rm -f a.out performance.c crc_bbb.[ch] crc_bbf.[ch] crc_tb[l4].[ch] crc_sb4.[ch]
+}
+
+trap cleanup 0 1 2 3 15
+
+model=crc-32
+
+prefix=bbb
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit
+prefix=bbf
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit-fast
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit-fast
+prefix=tbl
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven
+prefix=tb4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven --table-idx-width 4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven --table-idx-width 4
+prefix=sb4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven --slice-by 4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven --slice-by 4
+
+
+print_main() {
+cat <<EOF
+#include "crc_bbb.h"
+#include "crc_bbf.h"
+#include "crc_tbl.h"
+#include "crc_tb4.h"
+#include "crc_sb4.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/times.h>
+#include <unistd.h>
+
+#define NUM_RUNS    (128*256*256)
+
+unsigned char buf[1024];
+
+void test_bbb(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_bbf(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_tbl(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_tb4(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_sb4(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+
+/**
+ * Print results.
+ *
+ * \param   dsc Description of the test
+ * \param   buflen Length of one buffer
+ * \param   num_runs Number of runs over that buffer
+ * \param   t_user user time
+ * \param   t_sys system time
+ * \return  void
+ *****************************************************************************/
+void show_times(const char *dsc, size_t buflen, size_t num_runs, double t_user)
+{
+    double mbps = (((double)buflen) * num_runs)/(1024*1024*t_user);
+    printf("%s of %ld bytes (%ld * %ld)\n", dsc, (long)buflen*num_runs, (long)buflen, (long)num_runs);
+    printf("%13s: %7.3f s %13s: %7.3f MiB/s\n", "user time", t_user, "throughput", mbps);
+    printf("\n");
+}
+
+
+/**
+ * C main function.
+ *
+ * \retval      0 on success
+ * \retval      1 on failure
+ *****************************************************************************/
+int main(void)
+{
+    unsigned int i;
+    long int clock_per_sec;
+
+    for (i = 0; i < sizeof(buf); i++) {
+        buf[i] = (unsigned char)rand();
+    }
+    clock_per_sec = sysconf(_SC_CLK_TCK);
+
+    // bit-by-bit
+    test_bbb(buf, sizeof(buf), NUM_RUNS / 8, clock_per_sec);
+
+    // bit-by-bit-fast
+    test_bbf(buf, sizeof(buf), NUM_RUNS / 8, clock_per_sec);
+
+    // table-driven
+    test_tbl(buf, sizeof(buf), NUM_RUNS, clock_per_sec);
+
+    // table-driven idx4
+    test_tb4(buf, sizeof(buf), NUM_RUNS / 2, clock_per_sec);
+
+    // table-driven slice-by 4
+    test_sb4(buf, sizeof(buf), NUM_RUNS, clock_per_sec);
+
+    return 0;
+}
+EOF
+}
+
+print_routine() {
+    algo=$1
+    prefix=$2
+    cat <<EOF
+/**
+ * Test $algo Algorithm.
+ *
+ * \return      void
+ *****************************************************************************/
+void test_${prefix}(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec)
+{
+    crc_${prefix}_t crc;
+    unsigned int i;
+    struct tms tm1, tm2;
+
+    times(&tm1);
+    crc = crc_${prefix}_init();
+    for (i = 0; i < num_runs; i++) {
+        crc = crc_${prefix}_update(crc, buf, buf_len);
+    }
+    crc = crc_${prefix}_finalize(crc);
+    times(&tm2);
+    show_times("$model, $algo, block-wise", buf_len, num_runs,
+            ((double)(tm2.tms_utime - tm1.tms_utime) / (double)clock_per_sec));
+}
+
+EOF
+}
+
+print_main > performance.c
+print_routine "bit-by-bit" bbb >> performance.c
+print_routine "bit-by-bit-fast" bbf >> performance.c
+print_routine "table-driven" tbl >> performance.c
+print_routine "table-driven idx4" tb4 >> performance.c
+print_routine "table-driven sb4" sb4 >> performance.c
+
+gcc -W -Wall -O3 crc_bbb.c crc_bbf.c crc_tbl.c crc_tb4.c crc_sb4.c performance.c
+./a.out
diff --git a/test/test.py b/test/test.py
new file mode 100644
index 0000000..1731416
--- /dev/null
+++ b/test/test.py
@@ -0,0 +1,679 @@
+#!/usr/bin/env python
+# -*- coding: Latin-1 -*-
+
+#  pycrc test application.
+
+from optparse import OptionParser, Option, OptionValueError
+from copy import copy
+import os, sys
+import tempfile
+sys.path.append('..')
+sys.path.append('.')
+from pycrc.models import CrcModels
+from pycrc.algorithms import Crc
+
+
+class Options(object):
+    """
+    The options parsing and validating class
+    """
+
+    def __init__(self):
+        self.AllAlgorithms          = set(['bit-by-bit', 'bbb', 'bit-by-bit-fast', 'bbf', 'table-driven', 'tbl'])
+        self.Compile                = False
+        self.RandomParameters       = False
+        self.CompileMixedArgs       = False
+        self.VariableWidth          = False
+        self.verbose                = False
+        self.algorithm = copy(self.AllAlgorithms)
+
+    def parse(self, argv = None):
+        """
+        Parses and validates the options given as arguments
+        """
+        usage = """%prog [OPTIONS]"""
+
+        algorithms = ', '.join(sorted(list(self.AllAlgorithms)) + ['all'])
+        parser = OptionParser(usage=usage)
+        parser.add_option('-v', '--verbose',
+                        action='store_true', dest='verbose', default=self.verbose,
+                        help='print information about the model')
+        parser.add_option('-c', '--compile',
+                        action='store_true', dest='compile', default=self.Compile,
+                        help='test compiled version')
+        parser.add_option('-r', '--random-parameters',
+                        action='store_true', dest='random_parameters', default=self.RandomParameters,
+                        help='test random parameters')
+        parser.add_option('-m', '--compile-mixed-arguments',
+                        action='store_true', dest='compile_mixed_args', default=self.CompileMixedArgs,
+                        help='test compiled C program with some arguments given at compile time some arguments given at runtime')
+        parser.add_option('-w', '--variable-width',
+                        action='store_true', dest='variable_width', default=self.VariableWidth,
+                        help='test variable width from 1 to 64')
+        parser.add_option('-a', '--all',
+                        action='store_true', dest='all', default=False,
+                        help='do all tests')
+        parser.add_option('--algorithm',
+                        action='store', type='string', dest='algorithm', default='all',
+                        help='choose an algorithm from {{{0:s}}}'.format(algorithms, metavar='ALGO'))
+
+        (options, args) = parser.parse_args(argv)
+
+        self.verbose = options.verbose
+        self.Compile = options.all or options.compile or options.random_parameters
+        self.RandomParameters = options.all or options.random_parameters
+        self.CompileMixedArgs = options.all or options.compile_mixed_args
+        self.VariableWidth = options.all or options.variable_width
+
+        if options.algorithm is not None:
+            alg = options.algorithm.lower()
+            if alg in self.AllAlgorithms:
+                self.algorithm = set([alg])
+            elif alg == 'all':
+                self.algorithm = copy(self.AllAlgorithms)
+            else:
+                sys.stderr.write('unknown algorithm: {0:s}\n'.format(alg))
+                sys.exit(1)
+
+
+class CrcTests(object):
+    """
+    The CRC test class.
+    """
+
+    def __init__(self):
+        """
+        The class constructor.
+        """
+        self.pycrc_bin = '/bin/false'
+        self.use_algo_bit_by_bit = True
+        self.use_algo_bit_by_bit_fast = True
+        self.use_algo_table_driven = True
+        self.verbose = False
+        self.python3 = sys.version_info[0] >= 3
+        self.tmpdir = tempfile.mkdtemp(prefix='pycrc.')
+        self.check_file = None
+        self.crc_bin_bbb_c89 = None
+        self.crc_bin_bbb_c99 = None
+        self.crc_bin_bbf_c89 = None
+        self.crc_bin_bbf_c99 = None
+        self.crc_bin_bwe_c89 = None
+        self.crc_bin_bwe_c99 = None
+        self.crc_bin_tbl_c89 = None
+        self.crc_bin_tbl_c99 = None
+        self.crc_bin_tbl_sb4 = None
+        self.crc_bin_tbl_sb8 = None
+        self.crc_bin_tbl_sb16 = None
+        self.crc_bin_tbl_idx2 = None
+        self.crc_bin_tbl_idx4 = None
+
+    def __del__(self):
+        """
+        The class destructor. Delete all generated files.
+        """
+        if self.check_file is not None:
+            os.remove(self.check_file)
+        if self.crc_bin_bbb_c89 is not None:
+            self.__del_files([self.crc_bin_bbb_c89, self.crc_bin_bbb_c89+'.h', self.crc_bin_bbb_c89+'.c'])
+        if self.crc_bin_bbb_c99 is not None:
+            self.__del_files([self.crc_bin_bbb_c99, self.crc_bin_bbb_c99+'.h', self.crc_bin_bbb_c99+'.c'])
+        if self.crc_bin_bbf_c89 is not None:
+            self.__del_files([self.crc_bin_bbf_c89, self.crc_bin_bbf_c89+'.h', self.crc_bin_bbf_c89+'.c'])
+        if self.crc_bin_bbf_c99 is not None:
+            self.__del_files([self.crc_bin_bbf_c99, self.crc_bin_bbf_c99+'.h', self.crc_bin_bbf_c99+'.c'])
+        if self.crc_bin_bwe_c89 is not None:
+            self.__del_files([self.crc_bin_bwe_c89, self.crc_bin_bwe_c89+'.h', self.crc_bin_bwe_c89+'.c'])
+        if self.crc_bin_bwe_c99 is not None:
+            self.__del_files([self.crc_bin_bwe_c99, self.crc_bin_bwe_c99+'.h', self.crc_bin_bwe_c99+'.c'])
+        if self.crc_bin_tbl_c89 is not None:
+            self.__del_files([self.crc_bin_tbl_c89, self.crc_bin_tbl_c89+'.h', self.crc_bin_tbl_c89+'.c'])
+        if self.crc_bin_tbl_c99 is not None:
+            self.__del_files([self.crc_bin_tbl_c99, self.crc_bin_tbl_c99+'.h', self.crc_bin_tbl_c99+'.c'])
+        if self.crc_bin_tbl_sb4 is not None:
+            self.__del_files([self.crc_bin_tbl_sb4, self.crc_bin_tbl_sb4+'.h', self.crc_bin_tbl_sb4+'.c'])
+        if self.crc_bin_tbl_sb8 is not None:
+            self.__del_files([self.crc_bin_tbl_sb8, self.crc_bin_tbl_sb8+'.h', self.crc_bin_tbl_sb8+'.c'])
+        if self.crc_bin_tbl_sb16 is not None:
+            self.__del_files([self.crc_bin_tbl_sb16, self.crc_bin_tbl_sb16+'.h', self.crc_bin_tbl_sb16+'.c'])
+        if self.crc_bin_tbl_idx2 is not None:
+            self.__del_files([self.crc_bin_tbl_idx2, self.crc_bin_tbl_idx2+'.h', self.crc_bin_tbl_idx2+'.c'])
+        if self.crc_bin_tbl_idx4 is not None:
+            self.__del_files([self.crc_bin_tbl_idx4, self.crc_bin_tbl_idx4+'.h', self.crc_bin_tbl_idx4+'.c'])
+        os.removedirs(self.tmpdir)
+
+    def __del_files(delf, files):
+        """
+        Helper function to delete files.
+        """
+        for f in files:
+            try:
+                os.remove(f)
+            except:
+                print("error: can't delete {0:s}".format(f))
+                pass
+
+    def __get_status_output(self, cmd_str):
+        if self.python3:
+            import subprocess
+            return subprocess.getstatusoutput(cmd_str)
+        else:
+            import commands
+            return commands.getstatusoutput(cmd_str)
+
+    def __make_src(self, args, basename, cstd):
+        """
+        Generate the *.h and *.c source files for a test.
+        """
+        gen_src = '{0:s}/{1:s}'.format(self.tmpdir, basename)
+        cmd_str = self.pycrc_bin + ' {0:s} --std {1:s} --generate h -o {2:s}.h'.format(args, cstd, gen_src)
+        if self.verbose:
+            print(cmd_str)
+        ret = self.__get_status_output(cmd_str)
+        if ret[0] != 0:
+            print('error: the following command returned error: {0:s}'.format(cmd_str))
+            print(ret[1])
+            print(ret[2])
+            return None
+
+        cmd_str = self.pycrc_bin + ' {0:s} --std {1:s} --generate c-main -o {2:s}.c'.format(args, cstd, gen_src)
+        if self.verbose:
+            print(cmd_str)
+        ret = self.__get_status_output(cmd_str)
+        if ret[0] != 0:
+            print('error: the following command returned error: {0:s}'.format(cmd_str))
+            print(ret[1])
+            print(ret[2])
+            return None
+        return gen_src
+
+    def __compile(self, args, binfile, cstd):
+        """
+        Compile a generated source file.
+        """
+        cmd_str = 'gcc -W -Wall -pedantic -Werror -std={0:s} -o {1:s} {2:s}.c'.format(cstd, binfile, binfile)
+        if self.verbose:
+            print(cmd_str)
+        ret = self.__get_status_output(cmd_str)
+        if len(ret) > 1 and len(ret[1]) > 0:
+            print(ret[1])
+        if ret[0] != 0:
+            print('error: {0:d} with command error: {1:s}'.format(ret[0], cmd_str))
+            return None
+        return binfile
+
+    def __make_bin(self, args, basename, cstd='c99'):
+        """
+        Generate the source and compile to a binary.
+        """
+        filename = self.__make_src(args, basename, cstd)
+        if filename is None:
+            return None
+        if not self.__compile(args, filename, cstd):
+            self.__del_files([filename, filename+'.h', filename+'.c'])
+            return None
+        return filename
+
+    def __setup_files(self, opt):
+        """
+        Set up files needed during the test.
+        """
+        if self.verbose:
+            print('Setting up files...')
+        self.check_file = '{0:s}/check.txt'.format(self.tmpdir)
+        f = open(self.check_file, 'wb')
+        if self.python3:
+            f.write(bytes('123456789', 'utf-8'))
+        else:
+            f.write('123456789')
+        f.close()
+
+        if opt.Compile:
+            if self.use_algo_bit_by_bit:
+                filename = self.__make_bin('--algorithm bit-by-bit', 'crc_bbb_c89', 'c89')
+                if filename is None:
+                    return False
+                self.crc_bin_bbb_c89 = filename
+
+                filename = self.__make_bin('--algorithm bit-by-bit', 'crc_bbb_c99', 'c99')
+                if filename is None:
+                    return False
+                self.crc_bin_bbb_c99 = filename
+
+            if self.use_algo_bit_by_bit_fast:
+                filename = self.__make_bin('--algorithm bit-by-bit-fast', 'crc_bbf_c89', 'c89')
+                if filename is None:
+                    return False
+                self.crc_bin_bbf_c89 = filename
+
+                filename = self.__make_bin('--algorithm bit-by-bit-fast', 'crc_bbf_c99', 'c99')
+                if filename is None:
+                    return False
+                self.crc_bin_bbf_c99 = filename
+
+            if self.use_algo_table_driven:
+                filename = self.__make_bin('--algorithm table-driven', 'crc_tbl_c89', 'c89')
+                if filename is None:
+                    return False
+                self.crc_bin_tbl_c89 = filename
+
+                filename = self.__make_bin('--algorithm table-driven', 'crc_tbl_c99', 'c99')
+                if filename is None:
+                    return False
+                self.crc_bin_tbl_c99 = filename
+
+# FIXME don't test undefined params
+#                filename = self.__make_bin('--algorithm table-driven --slice-by 4', 'crc_tbl_sb4')
+#                if filename is None:
+#                    return False
+#                self.crc_bin_tbl_sb4 = filename
+#
+#                filename = self.__make_bin('--algorithm table-driven --slice-by 8', 'crc_tbl_sb8')
+#                if filename is None:
+#                    return False
+#                self.crc_bin_tbl_sb8 = filename
+#
+#                filename = self.__make_bin('--algorithm table-driven --slice-by 16', 'crc_tbl_sb16')
+#                if filename is None:
+#                    return False
+#                self.crc_bin_tbl_sb16 = filename
+
+                filename = self.__make_bin('--algorithm table-driven --table-idx-width 2', 'crc_tbl_idx2')
+                if filename is None:
+                    return False
+                self.crc_bin_tbl_idx2 = filename
+
+                filename = self.__make_bin('--algorithm table-driven --table-idx-width 4', 'crc_tbl_idx4')
+                if filename is None:
+                    return False
+                self.crc_bin_tbl_idx4 = filename
+
+        return True
+
+
+    def __run_command(self, cmd_str):
+        """
+        Run a command and return its stdout.
+        """
+        if self.verbose:
+            print(cmd_str)
+        ret = self.__get_status_output(cmd_str)
+        if ret[0] != 0:
+            print('error: the following command returned error: {0:s}'.format(cmd_str))
+            print(ret[1])
+            return None
+        return ret[1]
+
+    def __check_command(self, cmd_str, expected_result):
+        """
+        Run a command and check if the stdout matches the expected result.
+        """
+        ret = self.__run_command(cmd_str)
+        if int(ret, 16) != expected_result:
+            print('error: different checksums!')
+            print('{0:s}: expected {1:#x}, got {2:s}'.format(cmd_str, expected_result, ret))
+            return False
+        return True
+
+    def __check_bin(self, args, expected_result, long_data_type = True):
+        """
+        Check all precompiled binaries.
+        """
+        for binary in [
+                self.crc_bin_bbb_c89, self.crc_bin_bbb_c99,
+                self.crc_bin_bbf_c89, self.crc_bin_bbf_c99,
+                self.crc_bin_tbl_c89, self.crc_bin_tbl_c99,
+                self.crc_bin_tbl_sb4, self.crc_bin_tbl_sb8, self.crc_bin_tbl_sb16,
+                self.crc_bin_tbl_idx2, self.crc_bin_tbl_idx4]:
+            if binary is not None:
+                # Don't test width > 32 for C89, as I don't know how to ask for an data type > 32 bits.
+                if binary[-3:] == 'c89' and long_data_type:
+                    continue
+                cmd_str = binary + ' ' + args
+                if not self.__check_command(cmd_str, expected_result):
+                    return False
+        return True
+
+    def __get_crc(self, model, check_str = '123456789', expected_crc = None):
+        """
+        Get the CRC for a set of parameters from the Python reference implementation.
+        """
+        if self.verbose:
+            out_str = 'Crc(width = {width:d}, poly = {poly:#x}, reflect_in = {reflect_in}, xor_in = {xor_in:#x}, reflect_out = {reflect_out}, xor_out = {xor_out:#x})'.format(**model)
+            if expected_crc is not None:
+                out_str += ' [check = {0:#x}]'.format(expected_crc)
+            print(out_str)
+        alg = Crc(width = model['width'], poly = model['poly'],
+            reflect_in = model['reflect_in'], xor_in = model['xor_in'],
+            reflect_out = model['reflect_out'], xor_out = model['xor_out'])
+        error = False
+        crc = expected_crc
+
+        if self.use_algo_bit_by_bit:
+            bbb_crc = alg.bit_by_bit(check_str)
+            if crc is None:
+                crc = bbb_crc
+            error = error or bbb_crc != crc
+        if self.use_algo_bit_by_bit_fast:
+            bbf_crc = alg.bit_by_bit_fast(check_str)
+            if crc is None:
+                crc = bbf_crc
+            error = error or bbf_crc != crc
+        if self.use_algo_table_driven:
+            tbl_crc = alg.table_driven(check_str)
+            if crc is None:
+                crc = tbl_crc
+            error = error or tbl_crc != crc
+
+        if error:
+            print('error: different checksums!')
+            if expected_crc is not None:
+                print('       check:             {0:#x}'.format(expected_crc))
+            if self.use_algo_bit_by_bit:
+                print('       bit-by-bit:        {0:#x}'.format(bbb_crc))
+            if self.use_algo_bit_by_bit_fast:
+                print('       bit-by-bit-fast:   {0:#x}'.format(bbf_crc))
+            if self.use_algo_table_driven:
+                print('       table_driven:      {0:#x}'.format(tbl_crc))
+            return None
+        return crc
+
+    def __compile_and_check_res(self, cmp_opt, run_opt, name, expected_crc):
+        """
+        Compile a model and run it.
+        """
+        filename = self.__make_bin(cmp_opt, name)
+        if filename is None:
+            return False
+        if run_opt is None:
+            cmd = filename
+        else:
+            cmd = filename + ' ' + run_opt
+        ret = self.__check_command(cmd, expected_crc)
+        self.__del_files([filename, filename+'.h', filename+'.c'])
+        if not ret:
+            return False
+        return True
+
+
+    def __test_models(self):
+        """
+        Standard Tests.
+        Test all known models.
+        """
+        if self.verbose:
+            print('Running __test_models()...')
+        check_str = '123456789'
+        check_bytes = bytearray(check_str, 'utf-8')
+        models = CrcModels()
+        for m in models.models:
+            expected_crc = m['check']
+            if self.__get_crc(m, check_str, expected_crc) != expected_crc:
+                return False
+
+            ext_args = '--width {width:d} --poly {poly:#x} --xor-in {xor_in:#x} --reflect-in {reflect_in} --xor-out {xor_out:#x} --reflect-out {reflect_out}'.format(**m)
+
+            cmd_str = '{0:s} --model {1:s}'.format(self.pycrc_bin, m['name'])
+            if not self.__check_command(cmd_str, expected_crc):
+                return False
+
+            cmd_str = '{0:s} {1:s}'.format(self.pycrc_bin, ext_args)
+            if not self.__check_command(cmd_str, expected_crc):
+                return False
+
+            cmd_str = '{0:s} {1:s} --check-hexstring {2:s}'.format(self.pycrc_bin, ext_args, ''.join(['{0:02x}'.format(c) for c in check_bytes]))
+            if not self.__check_command(cmd_str, expected_crc):
+                return False
+
+            cmd_str = '{0:s} --model {1:s} --check-file {2:s}'.format(self.pycrc_bin, m['name'], self.check_file)
+            if not self.__check_command(cmd_str, expected_crc):
+                return False
+
+            if not self.__check_bin(ext_args, expected_crc, m['width'] > 32):
+                return False
+
+        if self.verbose:
+            print("")
+        return True
+
+
+    def __test_compiled_models(self):
+        """
+        Standard Tests.
+        Test all known models with the compiled code
+        """
+        if self.verbose:
+            print('Running __test_compiled_models()...')
+        models = CrcModels()
+        for m in models.models:
+            expected_crc = m['check']
+            cmp_opt = '--model {name}'.format(**m)
+
+            if self.use_algo_bit_by_bit:
+                if not self.__compile_and_check_res('--algorithm bit-by-bit' + ' ' + cmp_opt, None, 'crc_bbb_mod', expected_crc):
+                    return False
+
+            if self.use_algo_bit_by_bit_fast:
+                if not self.__compile_and_check_res('--algorithm bit-by-bit-fast' + ' ' + cmp_opt, None, 'crc_bbf_mod', expected_crc):
+                    return False
+
+            if self.use_algo_table_driven:
+                if not self.__compile_and_check_res('--algorithm table-driven' + ' ' + cmp_opt, None, 'crc_tbl_mod', expected_crc):
+                    return False
+
+                if not self.__compile_and_check_res('--algorithm table-driven --slice-by=4' + ' ' + cmp_opt, None, 'crc_tsb4_mod', expected_crc):
+                    return False
+
+                if not self.__compile_and_check_res('--algorithm table-driven --slice-by=8' + ' ' + cmp_opt, None, 'crc_tsb8_mod', expected_crc):
+                    return False
+
+                if not self.__compile_and_check_res('--algorithm table-driven --slice-by=16' + ' ' + cmp_opt, None, 'crc_tsb16_mod', expected_crc):
+                    return False
+
+                if not self.__compile_and_check_res('--algorithm table-driven --table-idx-width=2' + ' ' + cmp_opt, None, 'crc_tix2_mod', expected_crc):
+                    return False
+
+                if not self.__compile_and_check_res('--algorithm table-driven --table-idx-width=4' + ' ' + cmp_opt, None, 'crc_tix4_mod', expected_crc):
+                    return False
+        return True
+
+
+    def __test_compiled_special_cases(self):
+        """
+        Standard Tests.
+        Test some special cases.
+        """
+        if self.verbose:
+            print('Running __test_compiled_special_cases()...')
+        if self.use_algo_table_driven:
+            if not self.__compile_and_check_res('--model=crc-5 --reflect-in=0 --algorithm table-driven --table-idx-width=8', None, 'crc_tbl_special', 0x01):
+                return False
+            if not self.__compile_and_check_res('--model=crc-5 --reflect-in=0 --algorithm table-driven --table-idx-width=4', None, 'crc_tbl_special', 0x01):
+                return False
+            if not self.__compile_and_check_res('--model=crc-5 --reflect-in=0 --algorithm table-driven --table-idx-width=2', None, 'crc_tbl_special', 0x01):
+                return False
+        return True
+
+
+    def __test_variable_width(self):
+        """
+        Test variable width.
+        """
+        if self.verbose:
+            print('Running __test_variable_width()...')
+        models = CrcModels()
+        m = models.get_params('crc-64-jones')
+
+        for width in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64]:
+            mask = (1 << width) - 1
+            mw = {
+                'width':         width,
+                'poly':          m['poly'] & mask,
+                'reflect_in':    m['reflect_in'],
+                'xor_in':        m['xor_in'] & mask,
+                'reflect_out':   m['reflect_out'],
+                'xor_out':       m['xor_out'] & mask,
+            }
+            args = '--width {width:d} --poly {poly:#x} --xor-in {xor_in:#x} --reflect-in {reflect_in} --xor-out {xor_out:#x} --reflect-out {reflect_out}'.format(**mw)
+
+            check = self.__get_crc(mw)
+            if check is None:
+                return False
+
+            if self.use_algo_bit_by_bit:
+                if self.crc_bin_bbb_c99 is not None:
+                    if not self.__check_command(self.crc_bin_bbb_c99 + ' ' + args, check):
+                        return False
+
+                if not self.__compile_and_check_res('--algorithm bit-by-bit' + ' ' + args, None, 'crc_bbb_arg', check):
+                    return False
+
+            if self.use_algo_bit_by_bit_fast:
+                if self.crc_bin_bbf_c99 is not None:
+                    if not self.__check_command(self.crc_bin_bbf_c99 + ' ' + args, check):
+                        return False
+
+                if not self.__compile_and_check_res('--algorithm bit-by-bit-fast' + ' ' + args, None, 'crc_bbf_arg', check):
+                    return False
+
+            if self.use_algo_table_driven:
+                if self.crc_bin_tbl_c99 is not None:
+                    if not self.__check_command(self.crc_bin_tbl_c99 + ' ' + args, check):
+                        return False
+
+                if not self.__compile_and_check_res('--algorithm table-driven' + ' ' + args, None, 'crc_tbl_arg', check):
+                    return False
+        return True
+
+
+    def __test_compiled_mixed_args(self):
+        """
+        Test compiled arguments.
+        """
+        if self.verbose:
+            print('Running __test_compiled_mixed_args()...')
+        m =  {
+            'name':         'zmodem',
+            'width':         ['', '--width 16'],
+            'poly':          ['', '--poly 0x1021'],
+            'reflect_in':    ['', '--reflect-in False'],
+            'xor_in':        ['', '--xor-in 0x0'],
+            'reflect_out':   ['', '--reflect-out False'],
+            'xor_out':       ['', '--xor-out 0x0'],
+            'check':         0x31c3,
+        }
+        cmp_args = {}
+        run_args = {}
+        for b_width in range(2):
+            cmp_args['width'] = m['width'][b_width]
+            run_args['width'] = m['width'][1 - b_width]
+            for b_poly in range(2):
+                cmp_args['poly'] = m['poly'][b_poly]
+                run_args['poly'] = m['poly'][1 - b_poly]
+                for b_ref_in in range(2):
+                    cmp_args['reflect_in'] = m['reflect_in'][b_ref_in]
+                    run_args['reflect_in'] = m['reflect_in'][1 - b_ref_in]
+                    for b_xor_in in range(2):
+                        cmp_args['xor_in'] = m['xor_in'][b_xor_in]
+                        run_args['xor_in'] = m['xor_in'][1 - b_xor_in]
+                        for b_ref_out in range(2):
+                            cmp_args['reflect_out'] = m['reflect_out'][b_ref_out]
+                            run_args['reflect_out'] = m['reflect_out'][1 - b_ref_out]
+                            for b_xor_out in range(2):
+                                cmp_args['xor_out'] = m['xor_out'][b_xor_out]
+                                run_args['xor_out'] = m['xor_out'][1 - b_xor_out]
+
+                                cmp_opt = '{width:s} {poly:s} {reflect_in} {xor_in:s} {reflect_out} {xor_out:s}'.format(**cmp_args)
+                                run_opt = '{width:s} {poly:s} {reflect_in} {xor_in:s} {reflect_out} {xor_out:s}'.format(**run_args)
+
+                                if self.use_algo_bit_by_bit:
+                                    if not self.__compile_and_check_res('--algorithm bit-by-bit' + ' ' + cmp_opt, run_opt, 'crc_bbb_arg', m['check']):
+                                        return False
+
+                                if self.use_algo_bit_by_bit_fast:
+                                    if not self.__compile_and_check_res('--algorithm bit-by-bit-fast' + ' ' + cmp_opt, run_opt, 'crc_bbf_arg', m['check']):
+                                        return False
+
+                                if self.use_algo_table_driven:
+                                    if not self.__compile_and_check_res('--algorithm table-driven' + ' ' + cmp_opt, run_opt, 'crc_tbl_arg', m['check']):
+                                        return False
+        return True
+
+
+    def __test_random_params(self):
+        """
+        Test random parameters.
+        """
+        if self.verbose:
+            print('Running __test_random_params()...')
+        for width in [8, 16, 32]:
+            for poly in [0x8005, 0x4c11db7, 0xa5a5a5a5]:
+                poly = poly & ((1 << width) - 1)
+                for refin in [0, 1]:
+                    for refout in [0, 1]:
+                        for init in [0x0, 0x1, 0x5a5a5a5a]:
+                            args='--width {0:d} --poly {1:#x} --reflect-in {2} --reflect-out {3} --xor-in {4:#x} --xor-out 0x0'.format(width, poly, refin, refout, init)
+                            cmd_str = self.pycrc_bin + ' ' + args
+                            ret = self.__run_command(cmd_str)
+                            if ret is None:
+                                return False
+                            ret = int(ret, 16)
+                            if not self.__check_bin(args, ret, width > 32):
+                                return False
+        return True
+
+
+    def run(self, opt):
+        """
+        Run all tests
+        """
+        self.use_algo_bit_by_bit = 'bit-by-bit' in opt.algorithm or 'bbb' in opt.algorithm
+        self.use_algo_bit_by_bit_fast = 'bit-by-bit-fast' in opt.algorithm or 'bbf' in opt.algorithm
+        self.use_algo_table_driven = 'table-driven' in opt.algorithm or 'tbl' in opt.algorithm
+        self.verbose = opt.verbose
+
+        if self.python3:
+            self.pycrc_bin = 'python3 pycrc.py'
+        else:
+            self.pycrc_bin = 'python pycrc.py'
+
+        if not self.__setup_files(opt):
+            return False
+
+        if not self.__test_models():
+            return False
+
+        if opt.Compile and not self.__test_compiled_models():
+            return False
+
+        if opt.Compile and not self.__test_compiled_special_cases():
+            return False
+
+        if opt.VariableWidth and not self.__test_variable_width():
+            return False
+
+        if opt.CompileMixedArgs and not self.__test_compiled_mixed_args():
+            return False
+
+        if opt.RandomParameters and not self.__test_random_params():
+            return False
+
+        return True
+
+
+def main():
+    """
+    Main function.
+    """
+    opt = Options()
+    opt.parse(sys.argv[1:])
+
+    test = CrcTests()
+    if not test.run(opt):
+        return 1
+    print('Test OK')
+    return 0
+
+
+# program entry point
+if __name__ == '__main__':
+    sys.exit(main())