summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS.html1079
-rw-r--r--AUTHORS.txt73
-rw-r--r--GPL-3.0.txt674
-rw-r--r--HACKING.txt74
-rw-r--r--INSTALL.md51
-rw-r--r--LICENSE.html1214
-rw-r--r--LICENSE.txt475
-rw-r--r--MANUAL.html2380
-rw-r--r--MANUAL.txt1053
-rw-r--r--Makefile.in133
-rw-r--r--NEWS.html2742
-rw-r--r--NEWS.txt1092
-rw-r--r--README.md66
-rw-r--r--args.c314
-rwxr-xr-xautogen.sh8
-rw-r--r--ccache.11809
-rw-r--r--ccache.c3476
-rw-r--r--ccache.h298
-rw-r--r--cleanup.c275
-rw-r--r--compopt.c201
-rw-r--r--compopt.h15
-rw-r--r--conf.c666
-rw-r--r--conf.h53
-rwxr-xr-xconfig.guess1534
-rw-r--r--config.h.in256
-rwxr-xr-xconfig.sub1786
-rwxr-xr-xconfigure7422
-rw-r--r--configure.ac188
-rw-r--r--confitems.gperf40
-rw-r--r--confitems_lookup.c191
-rw-r--r--counters.c61
-rw-r--r--counters.h32
-rw-r--r--dev.mk.in164
-rw-r--r--dev_mode_disabled1
-rw-r--r--envtoconfitems.gperf41
-rw-r--r--envtoconfitems_lookup.c202
-rw-r--r--execute.c348
-rw-r--r--exitfn.c82
-rw-r--r--getopt_long.c197
-rw-r--r--getopt_long.h30
-rw-r--r--hash.c128
-rw-r--r--hashtable.c303
-rw-r--r--hashtable.h230
-rw-r--r--hashtable_itr.c188
-rw-r--r--hashtable_itr.h122
-rw-r--r--hashtable_private.h85
-rw-r--r--hashutil.c310
-rw-r--r--hashutil.h35
-rwxr-xr-xinstall-sh238
-rw-r--r--language.c178
-rw-r--r--language.h12
-rw-r--r--lockfile.c214
-rw-r--r--m4/feature_macros.m4147
-rw-r--r--m4/snprintf.m4224
-rw-r--r--macroskip.h61
-rw-r--r--main.c26
-rw-r--r--manifest.c780
-rw-r--r--manifest.h15
-rw-r--r--mdfour.c221
-rw-r--r--mdfour.h19
-rw-r--r--murmurhashneutral2.c44
-rw-r--r--murmurhashneutral2.h6
-rw-r--r--snprintf.c2116
-rw-r--r--stats.c562
-rw-r--r--system.h74
-rwxr-xr-xtest.sh3468
-rw-r--r--test/framework.c301
-rw-r--r--test/framework.h151
-rw-r--r--test/main.c93
-rw-r--r--test/suites.h10
-rw-r--r--test/test_args.c213
-rw-r--r--test/test_argument_processing.c441
-rw-r--r--test/test_compopt.c108
-rw-r--r--test/test_conf.c465
-rw-r--r--test/test_counters.c60
-rw-r--r--test/test_hash.c57
-rw-r--r--test/test_hashutil.c188
-rw-r--r--test/test_lockfile.c77
-rw-r--r--test/test_stats.c49
-rw-r--r--test/test_util.c202
-rw-r--r--test/util.c41
-rw-r--r--test/util.h10
-rw-r--r--unify.c252
-rw-r--r--util.c1661
-rw-r--r--version.c1
-rw-r--r--zlib/adler32.c179
-rw-r--r--zlib/crc32.c425
-rw-r--r--zlib/crc32.h441
-rw-r--r--zlib/deflate.c1967
-rw-r--r--zlib/deflate.h346
-rw-r--r--zlib/gzclose.c25
-rw-r--r--zlib/gzguts.h209
-rw-r--r--zlib/gzlib.c634
-rw-r--r--zlib/gzread.c594
-rw-r--r--zlib/gzwrite.c577
-rw-r--r--zlib/inffast.c340
-rw-r--r--zlib/inffast.h11
-rw-r--r--zlib/inffixed.h94
-rw-r--r--zlib/inflate.c1513
-rw-r--r--zlib/inflate.h122
-rw-r--r--zlib/inftrees.c306
-rw-r--r--zlib/inftrees.h62
-rw-r--r--zlib/trees.c1226
-rw-r--r--zlib/trees.h128
-rw-r--r--zlib/zconf.h511
-rw-r--r--zlib/zlib.h1768
-rw-r--r--zlib/zutil.c324
-rw-r--r--zlib/zutil.h253
108 files changed, 57037 insertions, 0 deletions
diff --git a/AUTHORS.html b/AUTHORS.html
new file mode 100644
index 0000000..5079e1f
--- /dev/null
+++ b/AUTHORS.html
@@ -0,0 +1,1079 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.9" />
+<title>ccache authors</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install(2);
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>ccache authors</h1>
+<span id="revnumber">version 3.3.4</span>
+<div id="toc">
+ <div id="toctitle">Table of Contents</div>
+ <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
+</div>
+</div>
+<div id="content">
+<div id="preamble">
+<div class="sectionbody">
+<div class="paragraph"><p>ccache was originally written by Andrew Tridgell and is currently developed and
+maintained by Joel Rosdahl.</p></div>
+<div class="paragraph"><p>ccache is a collective work with contributions from many people, including:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Alfred Landrum &lt;<a href="mailto:alfred.landrum@riverbed.com">alfred.landrum@riverbed.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Anders Björklund &lt;<a href="mailto:anders@psqr.se">anders@psqr.se</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Andrea Bittau &lt;<a href="mailto:a.bittau@cs.ucl.ac.uk">a.bittau@cs.ucl.ac.uk</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Andrew P Boie &lt;<a href="mailto:andrew.p.boie@intel.com">andrew.p.boie@intel.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Andrew Stubbs &lt;<a href="mailto:ams@codesourcery.com">ams@codesourcery.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Andrew Tridgell &lt;<a href="mailto:tridge@samba.org">tridge@samba.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+André Klitzing &lt;<a href="mailto:aklitzing@gmail.com">aklitzing@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Bernhard Bauer &lt;<a href="mailto:bauerb@chromium.org">bauerb@chromium.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Björn Jacke &lt;<a href="mailto:bj@sernet.de">bj@sernet.de</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Bo Rydberg &lt;<a href="mailto:bolry@hotmail.com">bolry@hotmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Chiaki Ishikawa &lt;<a href="mailto:ishikawa@yk.rim.or.jp">ishikawa@yk.rim.or.jp</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Chris AtLee &lt;<a href="mailto:chris@atlee.ca">chris@atlee.ca</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Clemens Rabe &lt;<a href="mailto:clemens.rabe@gmail.com">clemens.rabe@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+David Givone &lt;<a href="mailto:david@givone.net">david@givone.net</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Eric Blau &lt;<a href="mailto:Eric.Blau@tekelec.com">Eric.Blau@tekelec.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Francois Marier &lt;<a href="mailto:francois@debian.org">francois@debian.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Hongli Lai &lt;<a href="mailto:hongli@phusion.nl">hongli@phusion.nl</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Ivan Vaigult &lt;<a href="mailto:i.vaigult@gmail.com">i.vaigult@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Jiang Jiang &lt;<a href="mailto:jiangj@opera.com">jiangj@opera.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Joel Rosdahl &lt;<a href="mailto:joel@rosdahl.net">joel@rosdahl.net</a>&gt;
+</p>
+</li>
+<li>
+<p>
+John Basila &lt;<a href="mailto:jbasila@checkpoint.com">jbasila@checkpoint.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+John Coiner &lt;<a href="mailto:john.coiner@amd.com">john.coiner@amd.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Jon Bernard &lt;<a href="mailto:jbernard@tuxion.com">jbernard@tuxion.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Justin Lebar &lt;<a href="mailto:justin.lebar@gmail.com">justin.lebar@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Jørgen P. Tjernø &lt;<a href="mailto:jorgen@valvesoftware.com">jorgen@valvesoftware.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Karl Chen &lt;<a href="mailto:quarl@cs.berkeley.edu">quarl@cs.berkeley.edu</a>&gt;
+</p>
+</li>
+<li>
+<p>
+KonaBlend &lt;<a href="mailto:kona8lend@gmail.com">kona8lend@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Kovarththanan Rajaratnam &lt;<a href="mailto:kovarththanan.rajaratnam@gmail.com">kovarththanan.rajaratnam@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Lalit Chhabra &lt;<a href="mailto:lchhabra@linuxmail.org">lchhabra@linuxmail.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Lars Gustäbel &lt;<a href="mailto:lars@gustaebel.de">lars@gustaebel.de</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Leanid Chaika &lt;<a href="mailto:leanid.chaika@gmail.com">leanid.chaika@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Luboš Luňák &lt;<a href="mailto:l.lunak@suse.cz">l.lunak@suse.cz</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Mark Starovoytov &lt;<a href="mailto:starovoytov.mark@googlemail.com">starovoytov.mark@googlemail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Martin Pool &lt;<a href="mailto:mbp@sourcefrog.net">mbp@sourcefrog.net</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Matthias Kretz &lt;<a href="mailto:kretz@kde.org">kretz@kde.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Melven Roehrig-Zoellner &lt;<a href="mailto:Melven.Roehrig-Zoellner@DLR.de">Melven.Roehrig-Zoellner@DLR.de</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Michael Marineau &lt;<a href="mailto:michael.marineau@coreos.com">michael.marineau@coreos.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Michael Meeks &lt;<a href="mailto:michael.meeks@suse.com">michael.meeks@suse.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Mihai Serban &lt;<a href="mailto:mihai.serban@intel.com">mihai.serban@intel.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Mike Frysinger &lt;<a href="mailto:vapier@gentoo.org">vapier@gentoo.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Mikhail Kolomeytsev &lt;<a href="mailto:mkolom@yandex-team.ru">mkolom@yandex-team.ru</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Neil Mushell &lt;<a href="mailto:nmushell@bloomberg.net">nmushell@bloomberg.net</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Nick Schultz &lt;<a href="mailto:nick.schultz@intel.com">nick.schultz@intel.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Norbert Lange &lt;<a href="mailto:nolange79@gmail.com">nolange79@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Orgad Shaneh &lt;<a href="mailto:orgad.shaneh@audiocodes.com">orgad.shaneh@audiocodes.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Orion Poplawski &lt;<a href="mailto:orion@cora.nwra.com">orion@cora.nwra.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Owen Mann &lt;<a href="mailto:owen@mann.org">owen@mann.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Patrick von Reth &lt;<a href="mailto:vonreth@kde.org">vonreth@kde.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Paul Griffith &lt;<a href="mailto:paulg@cse.yorku.ca">paulg@cse.yorku.ca</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Pavel Boldin &lt;<a href="mailto:pboldin@cloudlinux.com">pboldin@cloudlinux.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Philippe Proulx &lt;<a href="mailto:eeppeliteloop@gmail.com">eeppeliteloop@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+RW &lt;<a href="mailto:fbsd06@mlists.homeunix.com">fbsd06@mlists.homeunix.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Ramiro Polla &lt;<a href="mailto:ramiro.polla@gmail.com">ramiro.polla@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Robin H. Johnson &lt;<a href="mailto:robbat2@gentoo.org">robbat2@gentoo.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Rolf Bjarne Kvinge &lt;<a href="mailto:rolf@xamarin.com">rolf@xamarin.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Ryan Brown &lt;<a href="mailto:ryb@ableton.com">ryb@ableton.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Tim Potter &lt;<a href="mailto:tpot@samba.org">tpot@samba.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Tor Arne Vestbø &lt;<a href="mailto:torarnv@gmail.com">torarnv@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Vadim Petrochenkov &lt;<a href="mailto:vadim.petrochenkov@gmail.com">vadim.petrochenkov@gmail.com</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Ville Skyttä &lt;<a href="mailto:ville.skytta@iki.fi">ville.skytta@iki.fi</a>&gt;
+</p>
+</li>
+<li>
+<p>
+William S Fulton &lt;<a href="mailto:wsf@fultondesigns.co.uk">wsf@fultondesigns.co.uk</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Wilson Snyder &lt;<a href="mailto:wsnyder@wsnyder.org">wsnyder@wsnyder.org</a>&gt;
+</p>
+</li>
+<li>
+<p>
+Yiding Jia &lt;<a href="mailto:yiding@fb.com">yiding@fb.com</a>&gt;
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>Thanks!</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Version 3.3.4<br />
+Last updated
+ 2017-02-17 22:27:14 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/AUTHORS.txt b/AUTHORS.txt
new file mode 100644
index 0000000..ec52d85
--- /dev/null
+++ b/AUTHORS.txt
@@ -0,0 +1,73 @@
+ccache authors
+==============
+
+ccache was originally written by Andrew Tridgell and is currently developed and
+maintained by Joel Rosdahl.
+
+ccache is a collective work with contributions from many people, including:
+
+* Alfred Landrum <alfred.landrum@riverbed.com>
+* Anders Björklund <anders@psqr.se>
+* Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+* Andrew P Boie <andrew.p.boie@intel.com>
+* Andrew Stubbs <ams@codesourcery.com>
+* Andrew Tridgell <tridge@samba.org>
+* André Klitzing <aklitzing@gmail.com>
+* Bernhard Bauer <bauerb@chromium.org>
+* Björn Jacke <bj@sernet.de>
+* Bo Rydberg <bolry@hotmail.com>
+* Chiaki Ishikawa <ishikawa@yk.rim.or.jp>
+* Chris AtLee <chris@atlee.ca>
+* Clemens Rabe <clemens.rabe@gmail.com>
+* David Givone <david@givone.net>
+* Eric Blau <Eric.Blau@tekelec.com>
+* Francois Marier <francois@debian.org>
+* Hongli Lai <hongli@phusion.nl>
+* Ivan Vaigult <i.vaigult@gmail.com>
+* Jiang Jiang <jiangj@opera.com>
+* Joel Rosdahl <joel@rosdahl.net>
+* John Basila <jbasila@checkpoint.com>
+* John Coiner <john.coiner@amd.com>
+* Jon Bernard <jbernard@tuxion.com>
+* Justin Lebar <justin.lebar@gmail.com>
+* Jørgen P. Tjernø <jorgen@valvesoftware.com>
+* Karl Chen <quarl@cs.berkeley.edu>
+* KonaBlend <kona8lend@gmail.com>
+* Kovarththanan Rajaratnam <kovarththanan.rajaratnam@gmail.com>
+* Lalit Chhabra <lchhabra@linuxmail.org>
+* Lars Gustäbel <lars@gustaebel.de>
+* Leanid Chaika <leanid.chaika@gmail.com>
+* Luboš Luňák <l.lunak@suse.cz>
+* Mark Starovoytov <starovoytov.mark@googlemail.com>
+* Martin Pool <mbp@sourcefrog.net>
+* Matthias Kretz <kretz@kde.org>
+* Melven Roehrig-Zoellner <Melven.Roehrig-Zoellner@DLR.de>
+* Michael Marineau <michael.marineau@coreos.com>
+* Michael Meeks <michael.meeks@suse.com>
+* Mihai Serban <mihai.serban@intel.com>
+* Mike Frysinger <vapier@gentoo.org>
+* Mikhail Kolomeytsev <mkolom@yandex-team.ru>
+* Neil Mushell <nmushell@bloomberg.net>
+* Nick Schultz <nick.schultz@intel.com>
+* Norbert Lange <nolange79@gmail.com>
+* Orgad Shaneh <orgad.shaneh@audiocodes.com>
+* Orion Poplawski <orion@cora.nwra.com>
+* Owen Mann <owen@mann.org>
+* Patrick von Reth <vonreth@kde.org>
+* Paul Griffith <paulg@cse.yorku.ca>
+* Pavel Boldin <pboldin@cloudlinux.com>
+* Philippe Proulx <eeppeliteloop@gmail.com>
+* RW <fbsd06@mlists.homeunix.com>
+* Ramiro Polla <ramiro.polla@gmail.com>
+* Robin H. Johnson <robbat2@gentoo.org>
+* Rolf Bjarne Kvinge <rolf@xamarin.com>
+* Ryan Brown <ryb@ableton.com>
+* Tim Potter <tpot@samba.org>
+* Tor Arne Vestbø <torarnv@gmail.com>
+* Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
+* Ville Skyttä <ville.skytta@iki.fi>
+* William S Fulton <wsf@fultondesigns.co.uk>
+* Wilson Snyder <wsnyder@wsnyder.org>
+* Yiding Jia <yiding@fb.com>
+
+Thanks!
diff --git a/GPL-3.0.txt b/GPL-3.0.txt
new file mode 100644
index 0000000..99a4d62
--- /dev/null
+++ b/GPL-3.0.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/HACKING.txt b/HACKING.txt
new file mode 100644
index 0000000..50ed26f
--- /dev/null
+++ b/HACKING.txt
@@ -0,0 +1,74 @@
+Hacking ccache
+==============
+
+Code formatting
+---------------
+
+* Use tabs for indenting and spaces for aligning C code.
+* Use 4 spaces for indenting other code (and spaces for aligning).
+* Put the opening curly brace on a new line when defining a function, otherwise
+ at the end of the same line.
+* Put no space between function name and the following parenthesis.
+* Put one space between if/switch/for/while/do and opening curly brace.
+* Always use curly braces around if/for/while/do bodies, even if they only
+ contain one statement.
+* If possible, keep lines at most 80 character wide for a 2 character tab
+ width.
+* Use only lowercase names for functions and variables.
+* Use only uppercase names for enum items and (with some exceptions) macros.
+* Don't use typedefs for structs and enums.
+* Use //-style comments.
+
+Tip: Install the tool uncrustify <http://uncrustify.sourceforge.net> and then
+run "make uncrustify" to fix up source code formatting.
+
+Idioms
+------
+
+* Declare variables as late as convenient, not necessarily at the beginning of
+ the scope.
+* Use NULL to initialize null pointers.
+* Don't use NULL when comparing pointers.
+* Use format(), x_malloc() and friends instead of checking for memory
+ allocation failure explicitly.
+* Use str_eq() instead of strcmp() when testing for string (in)equality.
+* Consider using str_startswith() instead of strncmp().
+* Use bool, true and false for boolean values.
+* Use tmp_unlink() or x_unlink() instead of unlink().
+* Use x_rename() instead of rename().
+
+Other
+-----
+
+* Strive to minimize use of global variables.
+* Write test cases for new code.
+
+Commit messages
+---------------
+
+* Write a summary (short description) on the first line.
+* Start the summary with a capital letter. Optional: prefix the short
+ description with a context followed by a colon.
+* The summary should be in imperative mood (see examples below).
+* The summary should not end with a period. It's a title and titles don't end
+ with a period.
+* If a longer description is wanted, add a second line empty and write the
+ longer description on line three and below.
+* Keep lines in the message at most 72 characters wide.
+
+Example 1:
+
+ Hash a delimiter string between parts to separate them
+
+ Previously, "gcc -I-O2 -c file.c" and "gcc -I -O2 -c file.c" would hash
+ to the same sum.
+
+Example 2:
+
+ win32: Add a space between filename and error string in x_fmmap()
+
+See also:
+
+* http://stopwritingramblingcommitmessages.com
+* http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
+* https://github.com/erlang/otp/wiki/Writing-good-commit-messages
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000..be25d02
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,51 @@
+ccache installation
+===================
+
+Prerequisites
+-------------
+
+To build ccache, you need:
+
+- A C compiler (for instance GCC)
+
+It is also recommended that you have:
+
+- [zlib](http://www.zlib.net) (if you don't have zlib installed, ccache will
+ use a bundled copy)
+
+
+Installation
+------------
+
+To compile and install ccache, run these commands:
+
+ ./configure
+ make
+ make install
+
+You may set the installation directory and other parameters by options to
+`./configure`. To see them, run `./configure --help`.
+
+There are two ways to use ccache. You can either prefix your compilation
+commands with `ccache` or you can create a symbolic link (named as your
+compiler) to ccache. The first method is most convenient if you just want to
+try out ccache or wish to use it for some specific projects. The second method
+is most useful for when you wish to use ccache for all your compilations.
+
+To install for usage by the first method just copy ccache to somewhere in your
+path.
+
+To install for the second method, do something like this:
+
+ cp ccache /usr/local/bin/
+ ln -s ccache /usr/local/bin/gcc
+ ln -s ccache /usr/local/bin/g++
+ ln -s ccache /usr/local/bin/cc
+ ln -s ccache /usr/local/bin/c++
+
+And so forth. This will work as long as `/usr/local/bin` comes before the path
+to the compiler (which is usually in `/usr/bin`). After installing you may wish
+to run `which gcc` to make sure that the correct link is being used.
+
+NOTE: Do not use a hard link, use a symbolic link. A hard link will cause
+"interesting" problems.
diff --git a/LICENSE.html b/LICENSE.html
new file mode 100644
index 0000000..6b43c89
--- /dev/null
+++ b/LICENSE.html
@@ -0,0 +1,1214 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.9" />
+<title>ccache copyright and license</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install(2);
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>ccache copyright and license</h1>
+<span id="revnumber">version 3.3.4</span>
+<div id="toc">
+ <div id="toctitle">Table of Contents</div>
+ <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_overall_license">Overall license</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The license for ccache as a whole is as follows:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
+ Street, Fifth Floor, Boston, MA 02110-1301 USA</code></pre>
+</div></div>
+<div class="paragraph"><p>The full license text can be found in GPL-3.0.txt and at
+<a href="http://www.gnu.org/licenses/gpl-3.0.html">http://www.gnu.org/licenses/gpl-3.0.html</a>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_copyright_and_authors">Copyright and authors</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>ccache is a collective work with contributions from many people, listed in
+AUTHORS.txt and at <a href="https://ccache.samba.org/authors.html">https://ccache.samba.org/authors.html</a>. Subsequent additions
+by contributing authors are implicitly licensed to the public under the same
+terms (GNU GPL version 3 or later), but the contributing authors retain
+copyrights on their portions of the work.</p></div>
+<div class="paragraph"><p>The copyright for ccache as a whole is as follows:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> Copyright (C) 2002-2007 Andrew Tridgell
+ Copyright (C) 2009-2017 Joel Rosdahl</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_files_derived_from_other_sources">Files derived from other sources</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The ccache distribution contain some files from other sources and some have
+been modified for use in ccache. These files all carry attribution notices, and
+may qualify as &#8220;separate and independent works in themselves&#8221; for purposes of
+the GPL: that is, if separated from the ccache sources, they may be usable
+under less restrictive terms.</p></div>
+<div class="sect2">
+<h3 id="_getopt_long_hc">getopt_long.[hc]</h3>
+<div class="paragraph"><p>This implementation of <code>getopt_long()</code> was copied from
+<a href="http://www.postgresql.org">PostgreSQL</a> and has the following license text:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> Portions Copyright (c) 1987, 1993, 1994
+ The Regents of the University of California. All rights reserved.
+
+ Portions Copyright (c) 2003
+ PostgreSQL Global Development Group
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_hashtable_hc">hashtable*.[hc]</h3>
+<div class="paragraph"><p>This code comes from <a href="http://www.cl.cam.ac.uk/~cwc22/hashtable/">http://www.cl.cam.ac.uk/~cwc22/hashtable/</a> with the
+following license:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> Copyright (c) 2002, 2004, Christopher Clark
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of the original author; nor the names of any
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_m4_feature_macros_m4">m4/feature_macros.m4</h3>
+<div class="paragraph"><p>This Autoconf M4 snippet comes from <a href="http://www.python.org">Python</a> 2.6&#8217;s
+<code>configure.in</code> with the following license:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> A. HISTORY OF THE SOFTWARE
+ ==========================
+
+ Python was created in the early 1990s by Guido van Rossum at Stichting
+ Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
+ as a successor of a language called ABC. Guido remains Python's
+ principal author, although it includes many contributions from others.
+
+ In 1995, Guido continued his work on Python at the Corporation for
+ National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
+ in Reston, Virginia where he released several versions of the
+ software.
+
+ In May 2000, Guido and the Python core development team moved to
+ BeOpen.com to form the BeOpen PythonLabs team. In October of the same
+ year, the PythonLabs team moved to Digital Creations (now Zope
+ Corporation, see http://www.zope.com). In 2001, the Python Software
+ Foundation (PSF, see http://www.python.org/psf/) was formed, a
+ non-profit organization created specifically to own Python-related
+ Intellectual Property. Zope Corporation is a sponsoring member of
+ the PSF.
+
+ All Python releases are Open Source (see http://www.opensource.org for
+ the Open Source Definition). Historically, most, but not all, Python
+ releases have also been GPL-compatible; the table below summarizes
+ the various releases.
+
+ Release Derived Year Owner GPL-
+ from compatible? (1)
+
+ 0.9.0 thru 1.2 1991-1995 CWI yes
+ 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
+ 1.6 1.5.2 2000 CNRI no
+ 2.0 1.6 2000 BeOpen.com no
+ 1.6.1 1.6 2001 CNRI yes (2)
+ 2.1 2.0+1.6.1 2001 PSF no
+ 2.0.1 2.0+1.6.1 2001 PSF yes
+ 2.1.1 2.1+2.0.1 2001 PSF yes
+ 2.2 2.1.1 2001 PSF yes
+ 2.1.2 2.1.1 2002 PSF yes
+ 2.1.3 2.1.2 2002 PSF yes
+ 2.2.1 2.2 2002 PSF yes
+ 2.2.2 2.2.1 2002 PSF yes
+ 2.2.3 2.2.2 2003 PSF yes
+ 2.3 2.2.2 2002-2003 PSF yes
+ 2.3.1 2.3 2002-2003 PSF yes
+ 2.3.2 2.3.1 2002-2003 PSF yes
+ 2.3.3 2.3.2 2002-2003 PSF yes
+ 2.3.4 2.3.3 2004 PSF yes
+ 2.3.5 2.3.4 2005 PSF yes
+ 2.4 2.3 2004 PSF yes
+ 2.4.1 2.4 2005 PSF yes
+ 2.4.2 2.4.1 2005 PSF yes
+ 2.4.3 2.4.2 2006 PSF yes
+ 2.4.4 2.4.3 2006 PSF yes
+ 2.5 2.4 2006 PSF yes
+ 2.5.1 2.5 2007 PSF yes
+ 2.5.2 2.5.1 2008 PSF yes
+ 2.5.3 2.5.2 2008 PSF yes
+ 2.6 2.5 2008 PSF yes
+ 2.6.1 2.6 2008 PSF yes
+
+ Footnotes:
+
+ (1) GPL-compatible doesn't mean that we're distributing Python under
+ the GPL. All Python licenses, unlike the GPL, let you distribute
+ a modified version without making your changes open source. The
+ GPL-compatible licenses make it possible to combine Python with
+ other software that is released under the GPL; the others don't.
+
+ (2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
+ because its license has a choice of law clause. According to
+ CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
+ is "not incompatible" with the GPL.
+
+ Thanks to the many outside volunteers who have worked under Guido's
+ direction to make these releases possible.
+
+
+ B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+ ===============================================================
+
+ PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+ --------------------------------------------
+
+ 1. This LICENSE AGREEMENT is between the Python Software Foundation
+ ("PSF"), and the Individual or Organization ("Licensee") accessing and
+ otherwise using this software ("Python") in source or binary form and
+ its associated documentation.
+
+ 2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python alone or in any derivative version,
+ provided, however, that PSF's License Agreement and PSF's notice of copyright,
+ i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Python
+ Software Foundation; All Rights Reserved" are retained in Python alone or in any
+ derivative version prepared by Licensee.
+
+ 3. In the event Licensee prepares a derivative work that is based on
+ or incorporates Python or any part thereof, and wants to make
+ the derivative work available to others as provided herein, then
+ Licensee hereby agrees to include in any such work a brief summary of
+ the changes made to Python.
+
+ 4. PSF is making Python available to Licensee on an "AS IS"
+ basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+
+ 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+ 6. This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+
+ 7. Nothing in this License Agreement shall be deemed to create any
+ relationship of agency, partnership, or joint venture between PSF and
+ Licensee. This License Agreement does not grant permission to use PSF
+ trademarks or trade name in a trademark sense to endorse or promote
+ products or services of Licensee, or any third party.
+
+ 8. By copying, installing or otherwise using Python, Licensee
+ agrees to be bound by the terms and conditions of this License
+ Agreement.
+
+
+ BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
+ -------------------------------------------
+
+ BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+ 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+ office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+ Individual or Organization ("Licensee") accessing and otherwise using
+ this software in source or binary form and its associated
+ documentation ("the Software").
+
+ 2. Subject to the terms and conditions of this BeOpen Python License
+ Agreement, BeOpen hereby grants Licensee a non-exclusive,
+ royalty-free, world-wide license to reproduce, analyze, test, perform
+ and/or display publicly, prepare derivative works, distribute, and
+ otherwise use the Software alone or in any derivative version,
+ provided, however, that the BeOpen Python License is retained in the
+ Software, alone or in any derivative version prepared by Licensee.
+
+ 3. BeOpen is making the Software available to Licensee on an "AS IS"
+ basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+
+ 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+ SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+ AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+ DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+ 5. This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+
+ 6. This License Agreement shall be governed by and interpreted in all
+ respects by the law of the State of California, excluding conflict of
+ law provisions. Nothing in this License Agreement shall be deemed to
+ create any relationship of agency, partnership, or joint venture
+ between BeOpen and Licensee. This License Agreement does not grant
+ permission to use BeOpen trademarks or trade names in a trademark
+ sense to endorse or promote products or services of Licensee, or any
+ third party. As an exception, the "BeOpen Python" logos available at
+ http://www.pythonlabs.com/logos.html may be used according to the
+ permissions granted on that web page.
+
+ 7. By copying, installing or otherwise using the software, Licensee
+ agrees to be bound by the terms and conditions of this License
+ Agreement.
+
+
+ CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
+ ---------------------------------------
+
+ 1. This LICENSE AGREEMENT is between the Corporation for National
+ Research Initiatives, having an office at 1895 Preston White Drive,
+ Reston, VA 20191 ("CNRI"), and the Individual or Organization
+ ("Licensee") accessing and otherwise using Python 1.6.1 software in
+ source or binary form and its associated documentation.
+
+ 2. Subject to the terms and conditions of this License Agreement, CNRI
+ hereby grants Licensee a nonexclusive, royalty-free, world-wide
+ license to reproduce, analyze, test, perform and/or display publicly,
+ prepare derivative works, distribute, and otherwise use Python 1.6.1
+ alone or in any derivative version, provided, however, that CNRI's
+ License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+ 1995-2001 Corporation for National Research Initiatives; All Rights
+ Reserved" are retained in Python 1.6.1 alone or in any derivative
+ version prepared by Licensee. Alternately, in lieu of CNRI's License
+ Agreement, Licensee may substitute the following text (omitting the
+ quotes): "Python 1.6.1 is made available subject to the terms and
+ conditions in CNRI's License Agreement. This Agreement together with
+ Python 1.6.1 may be located on the Internet using the following
+ unique, persistent identifier (known as a handle): 1895.22/1013. This
+ Agreement may also be obtained from a proxy server on the Internet
+ using the following URL: http://hdl.handle.net/1895.22/1013".
+
+ 3. In the event Licensee prepares a derivative work that is based on
+ or incorporates Python 1.6.1 or any part thereof, and wants to make
+ the derivative work available to others as provided herein, then
+ Licensee hereby agrees to include in any such work a brief summary of
+ the changes made to Python 1.6.1.
+
+ 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+ basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+
+ 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+ 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+ 6. This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+
+ 7. This License Agreement shall be governed by the federal
+ intellectual property law of the United States, including without
+ limitation the federal copyright law, and, to the extent such
+ U.S. federal law does not apply, by the law of the Commonwealth of
+ Virginia, excluding Virginia's conflict of law provisions.
+ Notwithstanding the foregoing, with regard to derivative works based
+ on Python 1.6.1 that incorporate non-separable material that was
+ previously distributed under the GNU General Public License (GPL), the
+ law of the Commonwealth of Virginia shall govern this License
+ Agreement only as to issues arising under or with respect to
+ Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
+ License Agreement shall be deemed to create any relationship of
+ agency, partnership, or joint venture between CNRI and Licensee. This
+ License Agreement does not grant permission to use CNRI trademarks or
+ trade name in a trademark sense to endorse or promote products or
+ services of Licensee, or any third party.
+
+ 8. By clicking on the "ACCEPT" button where indicated, or by copying,
+ installing or otherwise using Python 1.6.1, Licensee agrees to be
+ bound by the terms and conditions of this License Agreement.
+
+ ACCEPT
+
+
+ CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
+ --------------------------------------------------
+
+ Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+ The Netherlands. All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation, and that the name of Stichting Mathematisch
+ Centrum or CWI not be used in advertising or publicity pertaining to
+ distribution of the software without specific, written prior
+ permission.
+
+ STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+ FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_murmurhashneutral2_hc">murmurhashneutral2.[hc]</h3>
+<div class="paragraph"><p>This fast hash implementation is released to the public domain by Austin
+Appleby. See <a href="http://murmurhash.googlepages.com">http://murmurhash.googlepages.com</a>.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_snprintf_c_and_m4_snprintf_m4">snprintf.c and m4/snprintf.m4</h3>
+<div class="paragraph"><p>This implementation of <code>snprintf()</code> and similar functions was downloaded from
+<a href="http://www.jhweiss.de/software/snprintf.html">http://www.jhweiss.de/software/snprintf.html</a> and has the following license:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> Copyright (c) 1995 Patrick Powell.
+
+ This code is based on code written by Patrick Powell &lt;papowell@astart.com&gt;.
+ It may be used for any purpose as long as this notice remains intact on all
+ source code distributions.
+
+ Copyright (c) 2008 Holger Weiss.
+
+ This version of the code is maintained by Holger Weiss &lt;holger@jhweiss.de&gt;.
+ My changes to the code may freely be used, modified and/or redistributed for
+ any purpose. It would be nice if additions and fixes to this file (including
+ trivial code cleanups) would be sent back in order to let me include them in
+ the version available at &lt;http://www.jhweiss.de/software/snprintf.html&gt;.
+ However, this is not a requirement for using or redistributing (possibly
+ modified) versions of this file, nor is leaving this notice intact mandatory.</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_zlib_hc">zlib/*.[hc]</h3>
+<div class="paragraph"><p>This is a bundled subset of zlib 1.2.8 from <a href="http://zlib.net">http://zlib.net</a> with the
+following license:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu</code></pre>
+</div></div>
+</div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Version 3.3.4<br />
+Last updated
+ 2017-02-17 22:27:14 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..5bf7883
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,475 @@
+ccache copyright and license
+============================
+
+Overall license
+---------------
+
+The license for ccache as a whole is as follows:
+
+-------------------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
+ Street, Fifth Floor, Boston, MA 02110-1301 USA
+-------------------------------------------------------------------------------
+
+The full license text can be found in GPL-3.0.txt and at
+http://www.gnu.org/licenses/gpl-3.0.html.
+
+
+Copyright and authors
+---------------------
+
+ccache is a collective work with contributions from many people, listed in
+AUTHORS.txt and at https://ccache.samba.org/authors.html. Subsequent additions
+by contributing authors are implicitly licensed to the public under the same
+terms (GNU GPL version 3 or later), but the contributing authors retain
+copyrights on their portions of the work.
+
+The copyright for ccache as a whole is as follows:
+
+-------------------------------------------------------------------------------
+ Copyright (C) 2002-2007 Andrew Tridgell
+ Copyright (C) 2009-2017 Joel Rosdahl
+-------------------------------------------------------------------------------
+
+
+Files derived from other sources
+--------------------------------
+
+The ccache distribution contain some files from other sources and some have
+been modified for use in ccache. These files all carry attribution notices, and
+may qualify as ``separate and independent works in themselves'' for purposes of
+the GPL: that is, if separated from the ccache sources, they may be usable
+under less restrictive terms.
+
+
+getopt_long.[hc]
+~~~~~~~~~~~~~~~~
+
+This implementation of `getopt_long()` was copied from
+http://www.postgresql.org[PostgreSQL] and has the following license text:
+
+-------------------------------------------------------------------------------
+ Portions Copyright (c) 1987, 1993, 1994
+ The Regents of the University of California. All rights reserved.
+
+ Portions Copyright (c) 2003
+ PostgreSQL Global Development Group
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+-------------------------------------------------------------------------------
+
+
+hashtable*.[hc]
+~~~~~~~~~~~~~~~
+
+This code comes from http://www.cl.cam.ac.uk/~cwc22/hashtable/ with the
+following license:
+
+-------------------------------------------------------------------------------
+ Copyright (c) 2002, 2004, Christopher Clark
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of the original author; nor the names of any
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+-------------------------------------------------------------------------------
+
+
+m4/feature_macros.m4
+~~~~~~~~~~~~~~~~~~~~
+
+This Autoconf M4 snippet comes from http://www.python.org[Python] 2.6's
+`configure.in` with the following license:
+
+-------------------------------------------------------------------------------
+ A. HISTORY OF THE SOFTWARE
+ ==========================
+
+ Python was created in the early 1990s by Guido van Rossum at Stichting
+ Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
+ as a successor of a language called ABC. Guido remains Python's
+ principal author, although it includes many contributions from others.
+
+ In 1995, Guido continued his work on Python at the Corporation for
+ National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
+ in Reston, Virginia where he released several versions of the
+ software.
+
+ In May 2000, Guido and the Python core development team moved to
+ BeOpen.com to form the BeOpen PythonLabs team. In October of the same
+ year, the PythonLabs team moved to Digital Creations (now Zope
+ Corporation, see http://www.zope.com). In 2001, the Python Software
+ Foundation (PSF, see http://www.python.org/psf/) was formed, a
+ non-profit organization created specifically to own Python-related
+ Intellectual Property. Zope Corporation is a sponsoring member of
+ the PSF.
+
+ All Python releases are Open Source (see http://www.opensource.org for
+ the Open Source Definition). Historically, most, but not all, Python
+ releases have also been GPL-compatible; the table below summarizes
+ the various releases.
+
+ Release Derived Year Owner GPL-
+ from compatible? (1)
+
+ 0.9.0 thru 1.2 1991-1995 CWI yes
+ 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
+ 1.6 1.5.2 2000 CNRI no
+ 2.0 1.6 2000 BeOpen.com no
+ 1.6.1 1.6 2001 CNRI yes (2)
+ 2.1 2.0+1.6.1 2001 PSF no
+ 2.0.1 2.0+1.6.1 2001 PSF yes
+ 2.1.1 2.1+2.0.1 2001 PSF yes
+ 2.2 2.1.1 2001 PSF yes
+ 2.1.2 2.1.1 2002 PSF yes
+ 2.1.3 2.1.2 2002 PSF yes
+ 2.2.1 2.2 2002 PSF yes
+ 2.2.2 2.2.1 2002 PSF yes
+ 2.2.3 2.2.2 2003 PSF yes
+ 2.3 2.2.2 2002-2003 PSF yes
+ 2.3.1 2.3 2002-2003 PSF yes
+ 2.3.2 2.3.1 2002-2003 PSF yes
+ 2.3.3 2.3.2 2002-2003 PSF yes
+ 2.3.4 2.3.3 2004 PSF yes
+ 2.3.5 2.3.4 2005 PSF yes
+ 2.4 2.3 2004 PSF yes
+ 2.4.1 2.4 2005 PSF yes
+ 2.4.2 2.4.1 2005 PSF yes
+ 2.4.3 2.4.2 2006 PSF yes
+ 2.4.4 2.4.3 2006 PSF yes
+ 2.5 2.4 2006 PSF yes
+ 2.5.1 2.5 2007 PSF yes
+ 2.5.2 2.5.1 2008 PSF yes
+ 2.5.3 2.5.2 2008 PSF yes
+ 2.6 2.5 2008 PSF yes
+ 2.6.1 2.6 2008 PSF yes
+
+ Footnotes:
+
+ (1) GPL-compatible doesn't mean that we're distributing Python under
+ the GPL. All Python licenses, unlike the GPL, let you distribute
+ a modified version without making your changes open source. The
+ GPL-compatible licenses make it possible to combine Python with
+ other software that is released under the GPL; the others don't.
+
+ (2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
+ because its license has a choice of law clause. According to
+ CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
+ is "not incompatible" with the GPL.
+
+ Thanks to the many outside volunteers who have worked under Guido's
+ direction to make these releases possible.
+
+
+ B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+ ===============================================================
+
+ PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+ --------------------------------------------
+
+ 1. This LICENSE AGREEMENT is between the Python Software Foundation
+ ("PSF"), and the Individual or Organization ("Licensee") accessing and
+ otherwise using this software ("Python") in source or binary form and
+ its associated documentation.
+
+ 2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python alone or in any derivative version,
+ provided, however, that PSF's License Agreement and PSF's notice of copyright,
+ i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Python
+ Software Foundation; All Rights Reserved" are retained in Python alone or in any
+ derivative version prepared by Licensee.
+
+ 3. In the event Licensee prepares a derivative work that is based on
+ or incorporates Python or any part thereof, and wants to make
+ the derivative work available to others as provided herein, then
+ Licensee hereby agrees to include in any such work a brief summary of
+ the changes made to Python.
+
+ 4. PSF is making Python available to Licensee on an "AS IS"
+ basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+
+ 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+ 6. This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+
+ 7. Nothing in this License Agreement shall be deemed to create any
+ relationship of agency, partnership, or joint venture between PSF and
+ Licensee. This License Agreement does not grant permission to use PSF
+ trademarks or trade name in a trademark sense to endorse or promote
+ products or services of Licensee, or any third party.
+
+ 8. By copying, installing or otherwise using Python, Licensee
+ agrees to be bound by the terms and conditions of this License
+ Agreement.
+
+
+ BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
+ -------------------------------------------
+
+ BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+ 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+ office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+ Individual or Organization ("Licensee") accessing and otherwise using
+ this software in source or binary form and its associated
+ documentation ("the Software").
+
+ 2. Subject to the terms and conditions of this BeOpen Python License
+ Agreement, BeOpen hereby grants Licensee a non-exclusive,
+ royalty-free, world-wide license to reproduce, analyze, test, perform
+ and/or display publicly, prepare derivative works, distribute, and
+ otherwise use the Software alone or in any derivative version,
+ provided, however, that the BeOpen Python License is retained in the
+ Software, alone or in any derivative version prepared by Licensee.
+
+ 3. BeOpen is making the Software available to Licensee on an "AS IS"
+ basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+
+ 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+ SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+ AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+ DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+ 5. This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+
+ 6. This License Agreement shall be governed by and interpreted in all
+ respects by the law of the State of California, excluding conflict of
+ law provisions. Nothing in this License Agreement shall be deemed to
+ create any relationship of agency, partnership, or joint venture
+ between BeOpen and Licensee. This License Agreement does not grant
+ permission to use BeOpen trademarks or trade names in a trademark
+ sense to endorse or promote products or services of Licensee, or any
+ third party. As an exception, the "BeOpen Python" logos available at
+ http://www.pythonlabs.com/logos.html may be used according to the
+ permissions granted on that web page.
+
+ 7. By copying, installing or otherwise using the software, Licensee
+ agrees to be bound by the terms and conditions of this License
+ Agreement.
+
+
+ CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
+ ---------------------------------------
+
+ 1. This LICENSE AGREEMENT is between the Corporation for National
+ Research Initiatives, having an office at 1895 Preston White Drive,
+ Reston, VA 20191 ("CNRI"), and the Individual or Organization
+ ("Licensee") accessing and otherwise using Python 1.6.1 software in
+ source or binary form and its associated documentation.
+
+ 2. Subject to the terms and conditions of this License Agreement, CNRI
+ hereby grants Licensee a nonexclusive, royalty-free, world-wide
+ license to reproduce, analyze, test, perform and/or display publicly,
+ prepare derivative works, distribute, and otherwise use Python 1.6.1
+ alone or in any derivative version, provided, however, that CNRI's
+ License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+ 1995-2001 Corporation for National Research Initiatives; All Rights
+ Reserved" are retained in Python 1.6.1 alone or in any derivative
+ version prepared by Licensee. Alternately, in lieu of CNRI's License
+ Agreement, Licensee may substitute the following text (omitting the
+ quotes): "Python 1.6.1 is made available subject to the terms and
+ conditions in CNRI's License Agreement. This Agreement together with
+ Python 1.6.1 may be located on the Internet using the following
+ unique, persistent identifier (known as a handle): 1895.22/1013. This
+ Agreement may also be obtained from a proxy server on the Internet
+ using the following URL: http://hdl.handle.net/1895.22/1013".
+
+ 3. In the event Licensee prepares a derivative work that is based on
+ or incorporates Python 1.6.1 or any part thereof, and wants to make
+ the derivative work available to others as provided herein, then
+ Licensee hereby agrees to include in any such work a brief summary of
+ the changes made to Python 1.6.1.
+
+ 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+ basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+
+ 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+ 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+ 6. This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+
+ 7. This License Agreement shall be governed by the federal
+ intellectual property law of the United States, including without
+ limitation the federal copyright law, and, to the extent such
+ U.S. federal law does not apply, by the law of the Commonwealth of
+ Virginia, excluding Virginia's conflict of law provisions.
+ Notwithstanding the foregoing, with regard to derivative works based
+ on Python 1.6.1 that incorporate non-separable material that was
+ previously distributed under the GNU General Public License (GPL), the
+ law of the Commonwealth of Virginia shall govern this License
+ Agreement only as to issues arising under or with respect to
+ Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
+ License Agreement shall be deemed to create any relationship of
+ agency, partnership, or joint venture between CNRI and Licensee. This
+ License Agreement does not grant permission to use CNRI trademarks or
+ trade name in a trademark sense to endorse or promote products or
+ services of Licensee, or any third party.
+
+ 8. By clicking on the "ACCEPT" button where indicated, or by copying,
+ installing or otherwise using Python 1.6.1, Licensee agrees to be
+ bound by the terms and conditions of this License Agreement.
+
+ ACCEPT
+
+
+ CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
+ --------------------------------------------------
+
+ Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+ The Netherlands. All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation, and that the name of Stichting Mathematisch
+ Centrum or CWI not be used in advertising or publicity pertaining to
+ distribution of the software without specific, written prior
+ permission.
+
+ STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+ FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-------------------------------------------------------------------------------
+
+
+murmurhashneutral2.[hc]
+~~~~~~~~~~~~~~~~~~~~~~~
+
+This fast hash implementation is released to the public domain by Austin
+Appleby. See http://murmurhash.googlepages.com.
+
+
+snprintf.c and m4/snprintf.m4
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This implementation of `snprintf()` and similar functions was downloaded from
+http://www.jhweiss.de/software/snprintf.html and has the following license:
+
+-------------------------------------------------------------------------------
+ Copyright (c) 1995 Patrick Powell.
+
+ This code is based on code written by Patrick Powell <papowell@astart.com>.
+ It may be used for any purpose as long as this notice remains intact on all
+ source code distributions.
+
+ Copyright (c) 2008 Holger Weiss.
+
+ This version of the code is maintained by Holger Weiss <holger@jhweiss.de>.
+ My changes to the code may freely be used, modified and/or redistributed for
+ any purpose. It would be nice if additions and fixes to this file (including
+ trivial code cleanups) would be sent back in order to let me include them in
+ the version available at <http://www.jhweiss.de/software/snprintf.html>.
+ However, this is not a requirement for using or redistributing (possibly
+ modified) versions of this file, nor is leaving this notice intact mandatory.
+-------------------------------------------------------------------------------
+
+
+zlib/*.[hc]
+~~~~~~~~~~~
+
+This is a bundled subset of zlib 1.2.8 from <http://zlib.net> with the
+following license:
+
+-------------------------------------------------------------------------------
+ Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+-------------------------------------------------------------------------------
diff --git a/MANUAL.html b/MANUAL.html
new file mode 100644
index 0000000..1f2e5d9
--- /dev/null
+++ b/MANUAL.html
@@ -0,0 +1,2380 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.9" />
+<title>CCACHE(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install(2);
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>CCACHE(1)</h1>
+<span id="revnumber">version 3.3.4</span>
+<div id="toc">
+ <div id="toctitle">Table of Contents</div>
+ <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_name">Name</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>ccache - a fast C/C++ compiler cache</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_synopsis">Synopsis</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><strong>ccache</strong> [<em>options</em>]
+<strong>ccache</strong> <em>compiler</em> [<em>compiler options</em>]
+<em>compiler</em> [<em>compiler options</em>] (via symbolic link)</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">Description</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>ccache is a compiler cache. It speeds up recompilation by caching the result of
+previous compilations and detecting when the same compilation is being done
+again. Supported languages are C, C++, Objective-C and Objective-C++.</p></div>
+<div class="paragraph"><p>ccache has been carefully written to always produce exactly the same compiler
+output that you would get without the cache. The only way you should be able to
+tell that you are using ccache is the speed. Currently known exceptions to this
+goal are listed under <a href="#_caveats">CAVEATS</a>. If you ever discover an
+undocumented case where ccache changes the output of your compiler, please let
+us know.</p></div>
+<div class="sect2">
+<h3 id="_features">Features</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Keeps statistics on hits/misses.
+</p>
+</li>
+<li>
+<p>
+Automatic cache size management.
+</p>
+</li>
+<li>
+<p>
+Can cache compilations that generate warnings.
+</p>
+</li>
+<li>
+<p>
+Easy installation.
+</p>
+</li>
+<li>
+<p>
+Low overhead.
+</p>
+</li>
+<li>
+<p>
+Optionally uses hard links where possible to avoid copies.
+</p>
+</li>
+<li>
+<p>
+Optionally compresses files in the cache to reduce disk space.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_limitations">Limitations</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Only knows how to cache the compilation of a single
+ C/C++/Objective-C/Objective-C++ file. Other types of compilations
+ (multi-file compilation, linking, etc) will silently fall back to running the
+ real compiler.
+</p>
+</li>
+<li>
+<p>
+Only works with GCC and compilers that behave similar enough.
+</p>
+</li>
+<li>
+<p>
+Some compiler flags are not supported. If such a flag is detected, ccache
+ will silently fall back to running the real compiler.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_run_modes">Run modes</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>There are two ways to use ccache. You can either prefix your compilation
+commands with <strong>ccache</strong> or you can let ccache masquerade as the compiler by
+creating a symbolic link (named as the compiler) to ccache. The first method is
+most convenient if you just want to try out ccache or wish to use it for some
+specific projects. The second method is most useful for when you wish to use
+ccache for all your compilations.</p></div>
+<div class="paragraph"><p>To use the first method, just make sure that <strong>ccache</strong> is in your <strong>PATH</strong>.</p></div>
+<div class="paragraph"><p>To use the symlinks method, do something like this:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>cp ccache /usr/local/bin/
+ln -s ccache /usr/local/bin/gcc
+ln -s ccache /usr/local/bin/g++
+ln -s ccache /usr/local/bin/cc
+ln -s ccache /usr/local/bin/c++</code></pre>
+</div></div>
+<div class="paragraph"><p>And so forth. This will work as long as the directory with symlinks comes
+before the path to the compiler (which is usually in <code>/usr/bin</code>). After
+installing you may wish to run &#8220;which gcc&#8221; to make sure that the correct link
+is being used.</p></div>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<div class="title">Warning</div>
+</td>
+<td class="content">The technique of letting ccache masquerade as the compiler works well,
+but currently doesn&#8217;t interact well with other tools that do the same thing.
+See <a href="#_using_ccache_with_other_compiler_wrappers">USING CCACHE WITH OTHER COMPILER WRAPPERS</a>.</td>
+</tr></table>
+</div>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<div class="title">Warning</div>
+</td>
+<td class="content">Do not use a hard link, use a symbolic link. A hard link will cause
+&#8220;interesting&#8221; problems.</td>
+</tr></table>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">Options</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>These options only apply when you invoke ccache as &#8220;ccache&#8221;. When invoked as
+a compiler (via a symlink as described in the previous section), the normal
+compiler options apply and you should refer to the compiler&#8217;s documentation.</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<strong>-c, --cleanup</strong>
+</dt>
+<dd>
+<p>
+ Clean up the cache by removing old cached files until the specified file
+ number and cache size limits are not exceeded. This also recalculates the
+ cache file count and size totals. Normally, there is no need to initiate
+ cleanup manually as ccache keeps the cache below the specified limits at
+ runtime and keeps statistics up to date on each compilation. Forcing a
+ cleanup is mostly useful if you manually modify the cache contents or
+ believe that the cache size statistics may be inaccurate.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>-C, --clear</strong>
+</dt>
+<dd>
+<p>
+ Clear the entire cache, removing all cached files, but keeping the
+ configuration file.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>-F, --max-files</strong>=<em>N</em>
+</dt>
+<dd>
+<p>
+ Set the maximum number of files allowed in the cache. Use 0 for no limit.
+ The value is stored in a configuration file in the cache directory and
+ applies to all future compilations.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>-h, --help</strong>
+</dt>
+<dd>
+<p>
+ Print an options summary page.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>-M, --max-size</strong>=<em>SIZE</em>
+</dt>
+<dd>
+<p>
+ Set the maximum size of the files stored in the cache. <em>SIZE</em> should be a
+ number followed by an optional suffix: k, M, G, T (decimal), Ki, Mi, Gi or
+ Ti (binary). The default suffix is G. Use 0 for no limit. The value is
+ stored in a configuration file in the cache directory and applies to all
+ future compilations.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>-o, --set-config</strong>=<em>KEY=VALUE</em>
+</dt>
+<dd>
+<p>
+ Set configuration <em>KEY</em> to <em>VALUE</em>. See <a href="#_configuration">CONFIGURATION</a>
+ for more information.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>-p, --print-config</strong>
+</dt>
+<dd>
+<p>
+ Print current configuration options and from where they originate
+ (environment variable, configuration file or compile-time default).
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>-s, --show-stats</strong>
+</dt>
+<dd>
+<p>
+ Print the current statistics summary for the cache.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>-V, --version</strong>
+</dt>
+<dd>
+<p>
+ Print version and copyright information.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>-z, --zero-stats</strong>
+</dt>
+<dd>
+<p>
+ Zero the cache statistics (but not the configuration options).
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_extra_options">Extra options</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>When run as a compiler, ccache usually just takes the same command line options
+as the compiler you are using. The only exception to this is the option
+<strong>--ccache-skip</strong>. That option can be used to tell ccache to avoid interpreting
+the next option in any way and to pass it along to the compiler as-is.</p></div>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<div class="title">Note</div>
+</td>
+<td class="content"><strong>--ccache-skip</strong> currently only tells ccache not to interpret the next
+option as a special compiler option&#8201;&#8212;&#8201;the option will still be included in the
+direct mode hash.</td>
+</tr></table>
+</div>
+<div class="paragraph"><p>The reason this can be important is that ccache does need to parse the command
+line and determine what is an input filename and what is a compiler option, as
+it needs the input filename to determine the name of the resulting object file
+(among other things). The heuristic ccache uses when parsing the command line
+is that any argument that exists as a file is treated as an input file name. By
+using <strong>--ccache-skip</strong> you can force an option to not be treated as an input
+file name and instead be passed along to the compiler as a command line option.</p></div>
+<div class="paragraph"><p>Another case where <strong>--ccache-skip</strong> can be useful is if ccache interprets an
+option specially but shouldn&#8217;t, since the option has another meaning for your
+compiler than what ccache thinks.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_configuration">Configuration</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>ccache&#8217;s default behavior can be overridden by configuration file settings,
+which in turn can be overridden by environment variables with names starting
+with <strong>CCACHE_</strong>. ccache normally reads configuration from two files: first a
+system-level configuration file and secondly a cache-specific configuration
+file. The priority of configuration settings is as follows (where 1 is
+highest):</p></div>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+Environment variables.
+</p>
+</li>
+<li>
+<p>
+The cache-specific configuration file <strong>&lt;ccachedir&gt;/ccache.conf</strong> (typically
+ <strong>$HOME/.ccache/ccache.conf</strong>).
+</p>
+</li>
+<li>
+<p>
+The system-wide configuration file <strong>&lt;sysconfdir&gt;/ccache.conf</strong> (typically
+ <strong>/etc/ccache.conf</strong> or <strong>/usr/local/etc/ccache.conf</strong>).
+</p>
+</li>
+<li>
+<p>
+Compile-time defaults.
+</p>
+</li>
+</ol></div>
+<div class="paragraph"><p>As a special case, if the environment variable <strong>CCACHE_CONFIGPATH</strong> is set,
+ccache reads configuration from the specified path instead of the default
+paths.</p></div>
+<div class="sect2">
+<h3 id="_configuration_file_syntax">Configuration file syntax</h3>
+<div class="paragraph"><p>Configuration files are in a simple &#8220;key = value&#8221; format, one setting per
+line. Lines starting with a hash sign are comments. Blank lines are ignored, as
+is whitespace surrounding keys and values. Example:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># Set maximum cache size to 10 GB:
+max_size = 10G</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_boolean_values">Boolean values</h3>
+<div class="paragraph"><p>Some settings are boolean values (i.e. truth values). In a configuration file,
+such values must be set to the string <strong>true</strong> or <strong>false</strong>. For the corresponding
+environment variables, the semantics are a bit different: a set environment
+variable means &#8220;true&#8221; regardless of the value (even if set to the empty
+string), and an unset environment variable means &#8220;false&#8221;. Each boolean
+environment variable also has a negated form starting with <strong>CCACHE_NO</strong>. For
+example, <strong>CCACHE_COMPRESS</strong> can be set to force compression and
+<strong>CCACHE_NOCOMPRESS</strong> can be set to force no compression.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_configuration_settings">Configuration settings</h3>
+<div class="paragraph"><p>Below is a list of available configuration settings. The corresponding
+environment variable name is indicated in parentheses after each configuration
+setting key.</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<strong>base_dir</strong> (<strong>CCACHE_BASEDIR</strong>)
+</dt>
+<dd>
+<p>
+ This setting should be an absolute path to a directory. ccache then
+ rewrites absolute paths into relative paths before computing the hash that
+ identifies the compilation, but only for paths under the specified
+ directory. If set to the empty string (which is the default), no rewriting
+ is done. See also the discussion under
+ <a href="#_compiling_in_different_directories">COMPILING IN DIFFERENT DIRECTORIES</a>.
+ If using GCC or newer versions of Clang, you might want to look into the
+ <strong>-fdebug-prefix-map=old=new</strong> option for relocating debug info to a common
+ prefix (mapping prefix with old=new).
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>cache_dir</strong> (<strong>CCACHE_DIR</strong>)
+</dt>
+<dd>
+<p>
+ This setting specifies where ccache will keep its cached compiler outputs.
+ It will only take effect if set in the system-wide configuration file or as
+ an environment variable. The default is <strong>$HOME/.ccache</strong>.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>cache_dir_levels</strong> (<strong>CCACHE_NLEVELS</strong>)
+</dt>
+<dd>
+<p>
+ This setting allows you to choose the number of directory levels in the
+ cache directory. The default is 2. The minimum is 1 and the maximum is 8.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>compiler</strong> (<strong>CCACHE_CC</strong>)
+</dt>
+<dd>
+<p>
+ This setting can be used to force the name of the compiler to use. If set
+ to the empty string (which is the default), ccache works it out from the
+ command line.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>compiler_check</strong> (<strong>CCACHE_COMPILERCHECK</strong>)
+</dt>
+<dd>
+<p>
+ By default, ccache includes the modification time (&#8220;mtime&#8221;) and size of
+ the compiler in the hash to ensure that results retrieved from the cache
+ are accurate. This setting can be used to select another strategy. Possible
+ values are:
+</p>
+<div class="openblock">
+<div class="content">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<strong>content</strong>
+</dt>
+<dd>
+<p>
+ Hash the content of the compiler binary. This makes ccache very slightly
+ slower compared to the <strong>mtime</strong> setting, but makes it cope better with
+ compiler upgrades during a build bootstrapping process.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>mtime</strong>
+</dt>
+<dd>
+<p>
+ Hash the compiler&#8217;s mtime and size, which is fast. This is the default.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>none</strong>
+</dt>
+<dd>
+<p>
+ Don&#8217;t hash anything. This may be good for situations where you can safely
+ use the cached results even though the compiler&#8217;s mtime or size has changed
+ (e.g. if the compiler is built as part of your build system and the
+ compiler&#8217;s source has not changed, or if the compiler only has changes that
+ don&#8217;t affect code generation). You should only use the <strong>none</strong> setting if
+ you know what you are doing.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>string:value</strong>
+</dt>
+<dd>
+<p>
+ Use <strong>value</strong> as the string to calculate hash from. This can be the compiler
+ revision number you retrieved earlier and set here via environment variable.
+</p>
+</dd>
+<dt class="hdlist1">
+<em>a command string</em>
+</dt>
+<dd>
+<p>
+ Hash the standard output and standard error output of the specified
+ command. The string will be split on whitespace to find out the command and
+ arguments to run. No other interpretation of the command string will be
+ done, except that the special word <strong>%compiler%</strong> will be replaced with the
+ path to the compiler. Several commands can be specified with semicolon as
+ separator. Examples:
+</p>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre><code>%compiler% -v</code></pre>
+</div></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>%compiler% -dumpmachine; %compiler% -dumpversion</code></pre>
+</div></div>
+<div class="paragraph"><p>You should make sure that the specified command is as fast as possible since it
+will be run once for each ccache invocation.</p></div>
+<div class="paragraph"><p>Identifying the compiler using a command is useful if you want to avoid cache
+misses when the compiler has been rebuilt but not changed.</p></div>
+<div class="paragraph"><p>Another case is when the compiler (as seen by ccache) actually isn&#8217;t the real
+compiler but another compiler wrapper&#8201;&#8212;&#8201;in that case, the default <strong>mtime</strong>
+method will hash the mtime and size of the other compiler wrapper, which means
+that ccache won&#8217;t be able to detect a compiler upgrade. Using a suitable
+command to identify the compiler is thus safer, but it&#8217;s also slower, so you
+should consider continue using the <strong>mtime</strong> method in combination with
+the <strong>prefix_command</strong> setting if possible. See
+<a href="#_using_ccache_with_other_compiler_wrappers">USING CCACHE WITH OTHER COMPILER WRAPPERS</a>.</p></div>
+</div></div>
+</dd>
+</dl></div>
+</div></div>
+</dd>
+<dt class="hdlist1">
+<strong>compression</strong> (<strong>CCACHE_COMPRESS</strong> or <strong>CCACHE_NOCOMPRESS</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true, ccache will compress object files and other compiler output it
+ puts in the cache. However, this setting has no effect on how files are
+ retrieved from the cache; compressed and uncompressed results will still be
+ usable regardless of this setting. The default is false.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>compression_level</strong> (<strong>CCACHE_COMPRESSLEVEL</strong>)
+</dt>
+<dd>
+<p>
+ This setting determines the level at which ccache will compress object
+ files. It only has effect if <strong>compression</strong> is enabled. The value defaults
+ to 6, and must be no lower than 1 (fastest, worst compression) and no
+ higher than 9 (slowest, best compression).
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>cpp_extension</strong> (<strong>CCACHE_EXTENSION</strong>)
+</dt>
+<dd>
+<p>
+ This setting can be used to force a certain extension for the intermediate
+ preprocessed file. The default is to automatically determine the extension
+ to use for intermediate preprocessor files based on the type of file being
+ compiled, but that sometimes doesn&#8217;t work. For example, when using the
+ &#8220;aCC&#8221; compiler on HP-UX, set the cpp extension to <strong>i</strong>.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>direct_mode</strong> (<strong>CCACHE_DIRECT</strong> or <strong>CCACHE_NODIRECT</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true, the direct mode will be used. The default is true. See
+ <a href="#_the_direct_mode">THE DIRECT MODE</a>.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>disable</strong> (<strong>CCACHE_DISABLE</strong> or <strong>CCACHE_NODISABLE</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ When true, ccache will just call the real compiler, bypassing the cache
+ completely. The default is false.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>extra_files_to_hash</strong> (<strong>CCACHE_EXTRAFILES</strong>)
+</dt>
+<dd>
+<p>
+ This setting is a list of paths to files that ccache will include in the
+ the hash sum that identifies the build. The list separator is semicolon on
+ Windows systems and colon on other systems.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>hard_link</strong> (<strong>CCACHE_HARDLINK</strong> or <strong>CCACHE_NOHARDLINK</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true, ccache will attempt to use hard links from the cache directory
+ when creating the compiler output rather than using a file copy. Using hard
+ links may be slightly faster in some situations, but can confuse programs
+ like &#8220;make&#8221; that rely on modification times. Another thing to keep in
+ mind is that if the resulting object file is modified in any way, this
+ corrupts the cached object file as well. Hard links are never made for
+ compressed cache files. This means that you should not enable compression
+ if you want to use hard links. The default is false.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>hash_dir</strong> (<strong>CCACHE_HASHDIR</strong> or <strong>CCACHE_NOHASHDIR</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true (which is the default), ccache will include the current working
+ directory (CWD) in the hash that is used to distinguish two compilations
+ when generating debug info (compiler option <strong>-g</strong> with variations).
+ Exception: The CWD will not be included in the hash if <strong>base_dir</strong> is set
+ (and matches the CWD) and the compiler option <strong>-fdebug-prefix-map</strong> is used.
+</p>
+<div class="paragraph"><p>The reason for including the CWD in the hash by default is to prevent a problem
+with the storage of the current working directory in the debug info of an
+object file, which can lead ccache to return a cached object file that has the
+working directory in the debug info set incorrectly.</p></div>
+<div class="paragraph"><p>You can disable this setting to get cache hits when compiling the same source
+code in different directories if you don&#8217;t mind that CWD in the debug info
+might be incorrect.</p></div>
+</dd>
+<dt class="hdlist1">
+<strong>ignore_headers_in_manifest</strong> (<strong>CCACHE_IGNOREHEADERS</strong>)
+</dt>
+<dd>
+<p>
+ This setting is a list of paths to files (or directories with headers) that
+ ccache will <strong>not</strong> include in the manifest list that makes up the direct
+ mode. Note that this can cause stale cache hits if those headers do indeed
+ change. The list separator is semicolon on Windows systems and colon on
+ other systems.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>keep_comments_cpp</strong> (<strong>CCACHE_COMMENTS</strong> or <strong>CCACHE_NOCOMMENTS</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true, ccache will not discard the comments before hashing preprocessor
+ output. This can be used to check documentation with <strong>-Wdocumentation</strong>.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>limit_multiple</strong> (<strong>CCACHE_LIMIT_MULTIPLE</strong>)
+</dt>
+<dd>
+<p>
+ Sets the limit when cleaning up. Files are deleted (in LRU order) until the
+ levels are below the limit. The default is 0.8 (= 80%).
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>log_file</strong> (<strong>CCACHE_LOGFILE</strong>)
+</dt>
+<dd>
+<p>
+ If set to a file path, ccache will write information on what it is doing to
+ the specified file. This is useful for tracking down problems.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>max_files</strong> (<strong>CCACHE_MAXFILES</strong>)
+</dt>
+<dd>
+<p>
+ This option specifies the maximum number of files to keep in the cache. Use
+ 0 for no limit (which is the default).
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>max_size</strong> (<strong>CCACHE_MAXSIZE</strong>)
+</dt>
+<dd>
+<p>
+ This option specifies the maximum size of the cache. Use 0 for no limit.
+ The default value is 5G. Available suffixes: k, M, G, T (decimal) and Ki,
+ Mi, Gi, Ti (binary). The default suffix is "G".
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>path</strong> (<strong>CCACHE_PATH</strong>)
+</dt>
+<dd>
+<p>
+ If set, ccache will search directories in this list when looking for the
+ real compiler. The list separator is semicolon on Windows systems and colon
+ on other systems. If not set, ccache will look for the first executable
+ matching the compiler name in the normal <strong>PATH</strong> that isn&#8217;t a symbolic link
+ to ccache itself.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>prefix_command</strong> (<strong>CCACHE_PREFIX</strong>)
+</dt>
+<dd>
+<p>
+ This option adds a list of prefixes (separated by space) to the command
+ line that ccache uses when invoking the compiler. See also
+ <a href="#_using_ccache_with_other_compiler_wrappers">USING CCACHE WITH OTHER COMPILER WRAPPERS</a>.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>prefix_command_cpp</strong> (<strong>CCACHE_PREFIX_CPP</strong>)
+</dt>
+<dd>
+<p>
+ This option adds a list of prefixes (separated by space) to the command
+ line that ccache uses when invoking the preprocessor.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>read_only</strong> (<strong>CCACHE_READONLY</strong> or <strong>CCACHE_NOREADONLY</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true, ccache will attempt to use existing cached object files, but it
+ will not to try to add anything new to the cache. If you are using this
+ because your ccache directory is read-only, then you need to set
+ <strong>temporary_dir</strong> as otherwise ccache will fail to create temporary files.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>read_only_direct</strong> (<strong>CCACHE_READONLY_DIRECT</strong> or <strong>CCACHE_NOREADONLY_DIRECT</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ Just like <strong>read_only</strong> except that ccache will only try to retrieve results
+ from the cache using the direct mode, not the preprocessor mode. See
+ documentation for <strong>read_only</strong> regarding using a read-only ccache directory.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>recache</strong> (<strong>CCACHE_RECACHE</strong> or <strong>CCACHE_NORECACHE</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true, ccache will not use any previously stored result. New results will
+ still be cached, possibly overwriting any pre-existing results.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>run_second_cpp</strong> (<strong>CCACHE_CPP2</strong> or <strong>CCACHE_NOCPP2</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true, ccache will first run the preprocessor to preprocess the source
+ code (see <a href="#_the_preprocessor_mode">THE PREPROCESSOR MODE</a>) and then on a
+ cache miss run the compiler on the source code to get hold of the object
+ file. This is the default.
+</p>
+<div class="paragraph"><p>If false, ccache will first run preprocessor to preprocess the source code and
+then on a cache miss run the compiler on the <em>preprocessed source code</em> instead
+of the original source code. This makes cache misses slightly faster since the
+source code only has to be preprocessed once. The downside is that some
+compilers won&#8217;t produce the same result (for instance diagnostics warnings)
+when compiling preprocessed source code.</p></div>
+</dd>
+<dt class="hdlist1">
+<strong>sloppiness</strong> (<strong>CCACHE_SLOPPINESS</strong>)
+</dt>
+<dd>
+<p>
+ By default, ccache tries to give as few false cache hits as possible.
+ However, in certain situations it&#8217;s possible that you know things that
+ ccache can&#8217;t take for granted. This setting makes it possible to tell
+ ccache to relax some checks in order to increase the hit rate. The value
+ should be a comma-separated string with options. Available options are:
+</p>
+<div class="openblock">
+<div class="content">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<strong>file_macro</strong>
+</dt>
+<dd>
+<p>
+ Ignore <strong>__FILE__</strong> being present in the source.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>file_stat_matches</strong>
+</dt>
+<dd>
+<p>
+ ccache normally examines a file&#8217;s contents to determine whether it matches
+ the cached version. With this option set, ccache will consider a file as
+ matching its cached version if the sizes, mtimes and ctimes match.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>include_file_ctime</strong>
+</dt>
+<dd>
+<p>
+ By default, ccache also will not cache a file if it includes a header whose
+ ctime is too new. This option disables that check.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>include_file_mtime</strong>
+</dt>
+<dd>
+<p>
+ By default, ccache will not cache a file if it includes a header whose
+ mtime is too new. This option disables that check.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>no_system_headers</strong>
+</dt>
+<dd>
+<p>
+ By default, ccache will also include all system headers in the manifest.
+ With this option set, ccache will only include system headers in the hash
+ but not add the system header files to the list of include files.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>pch_defines</strong>
+</dt>
+<dd>
+<p>
+ Be sloppy about #defines when precompiling a header file. See
+ <a href="#_precompiled_headers">PRECOMPILED HEADERS</a> for more information.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>time_macros</strong>
+</dt>
+<dd>
+<p>
+ Ignore <strong>__DATE__</strong> and <strong>__TIME__</strong> being present in the source code.
+</p>
+</dd>
+</dl></div>
+</div></div>
+<div class="paragraph"><p>See the discussion under <a href="#_troubleshooting">TROUBLESHOOTING</a> for more
+information.</p></div>
+</dd>
+<dt class="hdlist1">
+<strong>stats</strong> (<strong>CCACHE_STATS</strong> or <strong>CCACHE_NOSTATS</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true, ccache will update the statistics counters on each compilation.
+ The default is true.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>temporary_dir</strong> (<strong>CCACHE_TEMPDIR</strong>)
+</dt>
+<dd>
+<p>
+ This setting specifies where ccache will put temporary files. The default
+ is <strong>&lt;cache_dir&gt;/tmp</strong>.
+</p>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<div class="title">Note</div>
+</td>
+<td class="content">In previous versions of ccache, <strong>CCACHE_TEMPDIR</strong> had to be on the same
+ filesystem as the <strong>CCACHE_DIR</strong> path, but this requirement has been
+ relaxed.)</td>
+</tr></table>
+</div>
+</dd>
+<dt class="hdlist1">
+<strong>umask</strong> (<strong>CCACHE_UMASK</strong>)
+</dt>
+<dd>
+<p>
+ This setting specifies the umask for ccache and all child processes (such
+ as the compiler). This is mostly useful when you wish to share your cache
+ with other users. Note that this also affects the file permissions set on
+ the object files created from your compilations.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>unify</strong> (<strong>CCACHE_UNIFY</strong> or <strong>CCACHE_NOUNIFY</strong>, see <a href="#_boolean_values">Boolean values</a> above)
+</dt>
+<dd>
+<p>
+ If true, ccache will use a C/C++ unifier when hashing the preprocessor
+ output if the <strong>-g</strong> option is not used. The unifier is slower than a normal
+ hash, so setting this environment variable loses a little bit of speed, but
+ it means that ccache can take advantage of not recompiling when the changes
+ to the source code consist of reformatting only. Note that enabling the
+ unifier changes the hash, so cached compilations produced when the unifier
+ is enabled cannot be reused when the unifier is disabled, and vice versa.
+ Enabling the unifier may result in incorrect line number information in
+ compiler warning messages and expansions of the <strong>__LINE__</strong> macro. Also
+ note that enabling the unifier implies turning off the direct mode.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_cache_size_management">Cache size management</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>By default, ccache has a five gigabyte limit on the total size of files in the
+cache and no maximum number of files. You can set different limits using the
+<strong>-M</strong>/<strong>--max-size</strong> and <strong>-F</strong>/<strong>--max-files</strong> options. Use <strong>ccache -s/--show-stats</strong>
+to see the cache size and the currently configured limits (in addition to other
+various statistics).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_cache_compression">Cache compression</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>ccache can optionally compress all files it puts into the cache using the
+compression library zlib. While this may involve a tiny performance slowdown,
+it increases the number of files that fit in the cache. You can turn on
+compression with the <strong>compression</strong> configuration setting and you can also tweak
+the compression level with <strong>compression_level</strong>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_cache_statistics">Cache statistics</h2>
+<div class="sectionbody">
+<div class="paragraph"><p><strong>ccache -s/--show-stats</strong> can show the following statistics:</p></div>
+<div class="tableblock">
+<table rules="all"
+width="100%"
+frame="border"
+cellspacing="0" cellpadding="4">
+<col width="30%" />
+<col width="70%" />
+<thead>
+<tr>
+<th align="left" valign="top">Name </th>
+<th align="left" valign="top"> Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left" valign="top"><p class="table">autoconf compile/link</p></td>
+<td align="left" valign="top"><p class="table">Uncachable compilation or linking by an autoconf test.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">bad compiler arguments</p></td>
+<td align="left" valign="top"><p class="table">Malformed compiler argument, e.g. missing a value for an option that requires
+an argument or failure to read a file specified by an option argument.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">cache file missing</p></td>
+<td align="left" valign="top"><p class="table">A file was unexpectedly missing from the cache. This only happens in rare
+situations, e.g. if one ccache instance is about to get a file from the cache
+while another instance removed the file as part of cache cleanup.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">cache hit (direct)</p></td>
+<td align="left" valign="top"><p class="table">A result was successfully found using <a href="#_the_direct_mode">the direct mode</a>.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">cache hit (preprocessed)</p></td>
+<td align="left" valign="top"><p class="table">A result was successfully found using <a href="#_the_preprocessor_mode">the preprocessor mode</a>.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">cache miss</p></td>
+<td align="left" valign="top"><p class="table">No result was found.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">cache size</p></td>
+<td align="left" valign="top"><p class="table">Current size of the cache.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">called for link</p></td>
+<td align="left" valign="top"><p class="table">The compiler was called for linking, not compiling.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">called for preprocessing</p></td>
+<td align="left" valign="top"><p class="table">The compiler was called for preprocessing, not compiling.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">can&#8217;t use precompiled header</p></td>
+<td align="left" valign="top"><p class="table">Preconditions for using <a href="#_precompiled_headers">precompiled headers</a> were not
+fulfilled.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">ccache internal error</p></td>
+<td align="left" valign="top"><p class="table">Unexpected failure, e.g. due to problems reading/writing the cache.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">cleanups performed</p></td>
+<td align="left" valign="top"><p class="table">Number of cleanups performed, either implicitly due to the cache size limit
+being reached or due to explicit <strong>ccache -c/--cleanup</strong> calls.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">compile failed</p></td>
+<td align="left" valign="top"><p class="table">The compilation failed. No result stored in the cache.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">compiler check failed</p></td>
+<td align="left" valign="top"><p class="table">A compiler check program specified by <strong>compiler_check</strong> (<strong>CCACHE_COMPILERCHECK</strong>)
+failed.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">compiler produced empty output</p></td>
+<td align="left" valign="top"><p class="table">The compiler&#8217;s output file (typically an object file) was empty after
+compilation.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">compiler produced no output</p></td>
+<td align="left" valign="top"><p class="table">The compiler&#8217;s output file (typically an object file) was missing after
+compilation.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">compiler produced stdout</p></td>
+<td align="left" valign="top"><p class="table">The compiler wrote data to standard output. This is something that compilers
+normally never do, so ccache is not designed to store such output in the cache.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">couldn&#8217;t find the compiler</p></td>
+<td align="left" valign="top"><p class="table">The compiler to execute could not be found.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">error hashing extra file</p></td>
+<td align="left" valign="top"><p class="table">Failure reading a file specified by <strong>extra_files_to_hash</strong>
+(<strong>CCACHE_EXTRAFILES</strong>).</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">files in cache</p></td>
+<td align="left" valign="top"><p class="table">Current number of files in the cache.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">multiple source files</p></td>
+<td align="left" valign="top"><p class="table">The compiler was called to compile multiple source files in one go. This is not
+supported by ccache.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">no input file</p></td>
+<td align="left" valign="top"><p class="table">No input file was specified to the compiler.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">output to a non-regular file</p></td>
+<td align="left" valign="top"><p class="table">The output path specified with <strong>-o</strong> is not a file (e.g. a directory or a device
+node).</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">output to stdout</p></td>
+<td align="left" valign="top"><p class="table">The compiler was instructed to write its output to standard output using <strong>-o
+-</strong>. This is not supported by ccache.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">preprocessor error</p></td>
+<td align="left" valign="top"><p class="table">Preprocessing the source code using the compiler&#8217;s <strong>-E</strong> option failed.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">unsupported code directive</p></td>
+<td align="left" valign="top"><p class="table">Code like the assembler &#8220;.incbin&#8221; directive was found. This is not supported
+by ccache.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">unsupported compiler option</p></td>
+<td align="left" valign="top"><p class="table">A compiler option not supported by ccache was found.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">unsupported source language</p></td>
+<td align="left" valign="top"><p class="table">A source language e.g. specified with <strong>-x</strong> was unsupported by ccache.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_how_ccache_works">How ccache works</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The basic idea is to detect when you are compiling exactly the same code a
+second time and reuse the previously produced output. The detection is done by
+hashing different kinds of information that should be unique for the
+compilation and then using the hash sum to identify the cached output. ccache
+uses MD4, a very fast cryptographic hash algorithm, for the hashing. (MD4 is
+nowadays too weak to be useful in cryptographic contexts, but it should be safe
+enough to be used to identify recompilations.) On a cache hit, ccache is able
+to supply all of the correct compiler outputs (including all warnings,
+dependency file, etc) from the cache.</p></div>
+<div class="paragraph"><p>ccache has two ways of doing the detection:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+the <strong>direct mode</strong>, where ccache hashes the source code and include files
+ directly
+</p>
+</li>
+<li>
+<p>
+the <strong>preprocessor mode</strong>, where ccache runs the preprocessor on the source
+ code and hashes the result
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>The direct mode is generally faster since running the preprocessor has some
+overhead.</p></div>
+<div class="sect2">
+<h3 id="_common_hashed_information">Common hashed information</h3>
+<div class="paragraph"><p>For both modes, the following information is included in the hash:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+the extension used by the compiler for a file with preprocessor output
+ (normally <strong>.i</strong> for C code and <strong>.ii</strong> for C++ code)
+</p>
+</li>
+<li>
+<p>
+the compiler&#8217;s size and modification time (or other compiler-specific
+ information specified by the <strong>compiler_check</strong> setting)
+</p>
+</li>
+<li>
+<p>
+the name of the compiler
+</p>
+</li>
+<li>
+<p>
+the current directory (if the <strong>hash_dir</strong> setting is enabled)
+</p>
+</li>
+<li>
+<p>
+contents of files specified by the <strong>extra_files_to_hash</strong> setting (if any)
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_the_direct_mode">The direct mode</h3>
+<div class="paragraph"><p>In the direct mode, the hash is formed of the common information and:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+the input source file
+</p>
+</li>
+<li>
+<p>
+the command line options
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>Based on the hash, a data structure called &#8220;manifest&#8221; is looked up in the
+cache. The manifest contains:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+references to cached compilation results (object file, dependency file, etc)
+ that were produced by previous compilations that matched the hash
+</p>
+</li>
+<li>
+<p>
+paths to the include files that were read at the time the compilation results
+ were stored in the cache
+</p>
+</li>
+<li>
+<p>
+hash sums of the include files at the time the compilation results were
+ stored in the cache
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>The current contents of the include files are then hashed and compared to the
+information in the manifest. If there is a match, ccache knows the result of
+the compilation. If there is no match, ccache falls back to running the
+preprocessor. The output from the preprocessor is parsed to find the include
+files that were read. The paths and hash sums of those include files are then
+stored in the manifest along with information about the produced compilation
+result.</p></div>
+<div class="paragraph"><p>There is a catch with the direct mode: header files that were used by the
+compiler are recorded, but header files that were <strong>not</strong> used, but would have
+been used if they existed, are not. So, when ccache checks if a result can be
+taken from the cache, it currently can&#8217;t check if the existence of a new header
+file should invalidate the result. In practice, the direct mode is safe to use
+in the absolute majority of cases.</p></div>
+<div class="paragraph"><p>The direct mode will be disabled if any of the following holds:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+the configuration setting <strong>direct_mode</strong> is false
+</p>
+</li>
+<li>
+<p>
+a modification time of one of the include files is too new (needed to avoid a
+ race condition)
+</p>
+</li>
+<li>
+<p>
+the unifier is enabled (the configuration setting <strong>unify</strong> is true)
+</p>
+</li>
+<li>
+<p>
+a compiler option not supported by the direct mode is used:
+</p>
+<div class="ulist"><ul>
+<li>
+<p>
+a <strong>-Wp,<em>X</em></strong> compiler option other than <strong>-Wp,-MD,<em>path</em></strong>,
+ <strong>-Wp,-MMD,<em>path</em></strong> and <strong>-Wp,-D_define_</strong>
+</p>
+</li>
+<li>
+<p>
+<strong>-Xpreprocessor</strong>
+</p>
+</li>
+</ul></div>
+</li>
+<li>
+<p>
+the string &#8220;__TIME__&#8221; is present in the source code
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_the_preprocessor_mode">The preprocessor mode</h3>
+<div class="paragraph"><p>In the preprocessor mode, the hash is formed of the common information and:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+the preprocessor output from running the compiler with <strong>-E</strong>
+</p>
+</li>
+<li>
+<p>
+the command line options except options that affect include files (<strong>-I</strong>,
+ <strong>-include</strong>, <strong>-D</strong>, etc; the theory is that these options will change the
+ preprocessor output if they have any effect at all)
+</p>
+</li>
+<li>
+<p>
+any standard error output generated by the preprocessor
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>Based on the hash, the cached compilation result can be looked up directly in
+the cache.</p></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_compiling_in_different_directories">Compiling in different directories</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Some information included in the hash that identifies a unique compilation may
+contain absolute paths:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+The preprocessed source code may contain absolute paths to include files if
+ the compiler option <strong>-g</strong> is used or if absolute paths are given to <strong>-I</strong> and
+ similar compiler options.
+</p>
+</li>
+<li>
+<p>
+Paths specified by compiler options (such as <strong>-I</strong>, <strong>-MF</strong>, etc) may be
+ absolute.
+</p>
+</li>
+<li>
+<p>
+The source code file path may be absolute, and that path may substituted for
+ <strong>__FILE__</strong> macros in the source code or included in warnings emitted to
+ standard error by the preprocessor.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>This means that if you compile the same code in different locations, you can&#8217;t
+share compilation results between the different build directories since you get
+cache misses because of the absolute build directory paths that are part of the
+hash. To mitigate this problem, you can specify a &#8220;base directory&#8221; in the
+configuration setting <strong>base_dir</strong> to an absolute path to the directory. ccache
+will then rewrite absolute paths that are under the base directory (i.e., paths
+that have the base directory as a prefix) to relative paths when constructing
+the hash. A typical path to use as the base directory is your home directory or
+another directory that is a parent of your build directories. (Don&#8217;t use <code>/</code> as
+the base directory since that will make ccache also rewrite paths to system
+header files, which doesn&#8217;t gain anything.)</p></div>
+<div class="paragraph"><p>The drawbacks of using a base directory are:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+If you specify an absolute path to the source code file, <strong>__FILE__</strong> macros
+ will be expanded to a relative path instead.
+</p>
+</li>
+<li>
+<p>
+If you specify an absolute path to the source code file and compile with
+ <strong>-g</strong>, the source code path stored in the object file may point to the wrong
+ directory, which may prevent debuggers like GDB from finding the source code.
+ Sometimes, a work-around is to change the directory explicitly with the
+ &#8220;cd&#8221; command in GDB.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_precompiled_headers">Precompiled headers</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>ccache has support for GCC&#8217;s precompiled headers. However, you have to do some
+things to make it work properly:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+You must set <strong>sloppiness</strong> to <strong>pch_defines,time_macros</strong>. The reason is that
+ ccache can&#8217;t tell whether <strong>__TIME__</strong> or <strong>__DATE__</strong> is used when using a
+ precompiled header. Further, it can&#8217;t detect changes in #defines in the
+ source code because of how preprocessing works in combination with
+ precompiled headers.
+</p>
+</li>
+<li>
+<p>
+You must either:
+</p>
+<div class="openblock">
+<div class="content">
+<div class="ulist"><ul>
+<li>
+<p>
+use the <strong>-include</strong> compiler option to include the precompiled header
+ (i.e., don&#8217;t use <strong>#include</strong> in the source code to include the header); or
+</p>
+</li>
+<li>
+<p>
+(for the Clang compiler) use the <strong>-include-pch</strong> compiler option to include
+ the PCH file generated from the precompiled header; or
+</p>
+</li>
+<li>
+<p>
+add the <strong>-fpch-preprocess</strong> compiler option when compiling.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>If you don&#8217;t do this, either the non-precompiled version of the header file
+will be used (if available) or ccache will fall back to running the real
+compiler and increase the statistics counter &#8220;preprocessor error&#8221; (if the
+non-precompiled header file is not available).</p></div>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_sharing_a_cache">Sharing a cache</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>A group of developers can increase the cache hit rate by sharing a cache
+directory. To share a cache without unpleasant side effects, the following
+conditions should to be met:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Use the same cache directory.
+</p>
+</li>
+<li>
+<p>
+Make sure that the configuration setting <strong>hard_link</strong> is false (which is the
+ default).
+</p>
+</li>
+<li>
+<p>
+Make sure that all users are in the same group.
+</p>
+</li>
+<li>
+<p>
+Set the configuration setting <strong>umask</strong> to 002. This ensures that cached files
+ are accessible to everyone in the group.
+</p>
+</li>
+<li>
+<p>
+Make sure that all users have write permission in the entire cache directory
+ (and that you trust all users of the shared cache).
+</p>
+</li>
+<li>
+<p>
+Make sure that the setgid bit is set on all directories in the cache. This
+ tells the filesystem to inherit group ownership for new directories. The
+ following command might be useful for this:
+</p>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre><code>find $CCACHE_DIR -type d | xargs chmod g+s</code></pre>
+</div></div>
+</div></div>
+</li>
+</ul></div>
+<div class="paragraph"><p>The reason to avoid the hard link mode is that the hard links cause unwanted
+side effects, as all links to a cached file share the file&#8217;s modification
+timestamp. This results in false dependencies to be triggered by
+timestamp-based build systems whenever another user links to an existing file.
+Typically, users will see that their libraries and binaries are relinked
+without reason.</p></div>
+<div class="paragraph"><p>You may also want to make sure that a base directory is set appropriately, as
+discussed in a previous section.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_sharing_a_cache_on_nfs">Sharing a cache on NFS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>It is possible to put the cache directory on an NFS filesystem (or similar
+filesystems), but keep in mind that:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Having the cache on NFS may slow down compilation. Make sure to do some
+ benchmarking to see if it&#8217;s worth it.
+</p>
+</li>
+<li>
+<p>
+ccache hasn&#8217;t been tested very thoroughly on NFS.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>A tip is to set <strong>temporary_dir</strong> to a directory on the local host to avoid NFS
+traffic for temporary files.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_using_ccache_with_other_compiler_wrappers">Using ccache with other compiler wrappers</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The recommended way of combining ccache with another compiler wrapper (such as
+&#8220;distcc&#8221;) is by letting ccache execute the compiler wrapper. This is
+accomplished by defining the configuration setting <strong>prefix_command</strong>, for
+example by setting the environment variable <strong>CCACHE_PREFIX</strong> to the name of the
+wrapper (e.g. <strong>distcc</strong>). ccache will then prefix the command line with the
+specified command when running the compiler. To specify several prefix
+commands, set <strong>prefix_command</strong> to a colon-separated list of commands.</p></div>
+<div class="paragraph"><p>Unless you set <strong>compiler_check</strong> to a suitable command (see the description of
+that configuration option), it is not recommended to use the form <strong>ccache
+anotherwrapper compiler args</strong> as the compilation command. It&#8217;s also not
+recommended to use the masquerading technique for the other compiler wrapper.
+The reason is that by default, ccache will in both cases hash the mtime and
+size of the other wrapper instead of the real compiler, which means that:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Compiler upgrades will not be detected properly.
+</p>
+</li>
+<li>
+<p>
+The cached results will not be shared between compilations with and without
+ the other wrapper.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>Another minor thing is that if <strong>prefix_command</strong> is used, ccache will not invoke
+the other wrapper when running the preprocessor, which increases performance.
+You can use the <strong>prefix_command_cpp</strong> configuration setting if you also want to
+invoke the other wrapper when doing preprocessing (normally by adding <strong>-E</strong>).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_caveats">Caveats</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+The direct mode fails to pick up new header files in some rare scenarios. See
+ <a href="#_the_direct_mode">THE DIRECT MODE</a> above.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_troubleshooting">Troubleshooting</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_general">General</h3>
+<div class="paragraph"><p>A general tip for getting information about what ccache is doing is to enable
+debug logging by setting <strong>log_file</strong>. The log contains executed commands,
+important decisions that ccache makes, read and written files, etc. Another way
+of keeping track of what is happening is to check the output of <strong>ccache -s</strong>.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_performance">Performance</h3>
+<div class="paragraph"><p>ccache has been written to perform well out of the box, but sometimes you may
+have to do some adjustments of how you use the compiler and ccache in order to
+improve performance.</p></div>
+<div class="paragraph"><p>Since ccache works best when I/O is fast, put the cache directory on a fast
+storage device if possible. Having lots of free memory so that files in the
+cache directory stay in the disk cache is also preferable.</p></div>
+<div class="paragraph"><p>A good way of monitoring how well ccache works is to run <strong>ccache -s</strong> before and
+after your build and then compare the statistics counters. Here are some common
+problems and what may be done to increase the hit rate:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+If &#8220;cache hit (preprocessed)&#8221; has been incremented instead of &#8220;cache hit
+ (direct)&#8221;, ccache has fallen back to preprocessor mode, which is generally
+ slower. Some possible reasons are:
+</p>
+<div class="ulist"><ul>
+<li>
+<p>
+The source code has been modified in such a way that the preprocessor output
+ is not affected.
+</p>
+</li>
+<li>
+<p>
+Compiler arguments that are hashed in the direct mode but not in the
+ preprocessor mode have changed (<strong>-I</strong>, <strong>-include</strong>, <strong>-D</strong>, etc) and they didn&#8217;t
+ affect the preprocessor output.
+</p>
+</li>
+<li>
+<p>
+The compiler option <strong>-Xpreprocessor</strong> or <strong>-Wp,<em>X</em></strong> (except <strong>-Wp,-MD,<em>path</em></strong>,
+ <strong>-Wp,-MMD,<em>path</em></strong>, and <strong>-Wp,-D_define_</strong>) is used.
+</p>
+</li>
+<li>
+<p>
+This was the first compilation with a new value of the base directory
+ setting.
+</p>
+</li>
+<li>
+<p>
+A modification time of one of the include files is too new (created the same
+ second as the compilation is being done). This check is made to avoid a race
+ condition. To fix this, create the include file earlier in the build
+ process, if possible, or set <strong>sloppiness</strong> to <strong>include_file_mtime</strong> if you are
+ willing to take the risk. (The race condition consists of these events: the
+ preprocessor is run; an include file is modified by someone; the new include
+ file is hashed by ccache; the real compiler is run on the preprocessor&#8217;s
+ output, which contains data from the old header file; the wrong object file
+ is stored in the cache.)
+</p>
+</li>
+<li>
+<p>
+The <strong>__TIME__</strong> preprocessor macro is (potentially) being used. ccache
+ turns off direct mode if &#8220;__TIME__&#8221; is present in the source code. This
+ is done as a safety measure since the string indicates that a <strong>__TIME__</strong>
+ macro <em>may</em> affect the output. (To be sure, ccache would have to run the
+ preprocessor, but the sole point of the direct mode is to avoid that.) If
+ you know that <strong>__TIME__</strong> isn&#8217;t used in practise, or don&#8217;t care if ccache
+ produces objects where <strong>__TIME__</strong> is expanded to something in the past,
+ you can set <strong>sloppiness</strong> to <strong>time_macros</strong>.
+</p>
+</li>
+<li>
+<p>
+The <strong>__DATE__</strong> preprocessor macro is (potentially) being used and the
+ date has changed. This is similar to how <strong>__TIME__</strong> is handled. If
+ &#8220;__DATE__&#8221; is present in the source code, ccache hashes the current
+ date in order to be able to produce the correct object file if the
+ <strong>__DATE__</strong> macro affects the output. If you know that <strong>__DATE__</strong> isn&#8217;t
+ used in practise, or don&#8217;t care if ccache produces objects where
+ <strong>__DATE__</strong> is expanded to something in the past, you can set <strong>sloppiness</strong>
+ to <strong>time_macros</strong>.
+</p>
+</li>
+<li>
+<p>
+The <strong>__FILE__</strong> preprocessor macro is (potentially) being used and the
+ file path has changed. If &#8220;__FILE__&#8221; is present in the source code,
+ ccache hashes the current input file path in order to be able to produce the
+ correct object file if the <strong>__FILE__</strong> macro affects the output. If you
+ know that <strong>__FILE__</strong> isn&#8217;t used in practise, or don&#8217;t care if ccache
+ produces objects where <strong>__FILE__</strong> is expanded to the wrong path, you can
+ set <strong>sloppiness</strong> to <strong>file_macro</strong>.
+</p>
+</li>
+</ul></div>
+</li>
+<li>
+<p>
+If &#8220;cache miss&#8221; has been incremented even though the same code has been
+ compiled and cached before, ccache has either detected that something has
+ changed anyway or a cleanup has been performed (either explicitly or
+ implicitly when a cache limit has been reached). Some perhaps unobvious
+ things that may result in a cache miss are usage of <strong>__TIME__</strong> or
+ <strong>__DATE__</strong> macros, or use of automatically generated code that contains a
+ timestamp, build counter or other volatile information.
+</p>
+</li>
+<li>
+<p>
+If &#8220;multiple source files&#8221; has been incremented, it&#8217;s an indication that
+ the compiler has been invoked on several source code files at once. ccache
+ doesn&#8217;t support that. Compile the source code files separately if possible.
+</p>
+</li>
+<li>
+<p>
+If &#8220;unsupported compiler option&#8221; has been incremented, enable debug logging
+ and check which option was rejected.
+</p>
+</li>
+<li>
+<p>
+If &#8220;preprocessor error&#8221; has been incremented, one possible reason is that
+ precompiled headers are being used. See <a href="#_precompiled_headers">PRECOMPILED HEADERS</a> for how to remedy this.
+</p>
+</li>
+<li>
+<p>
+If &#8220;can&#8217;t use precompiled header&#8221; has been incremented, see
+ <a href="#_precompiled_headers">PRECOMPILED HEADERS</a>.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_corrupt_object_files">Corrupt object files</h3>
+<div class="paragraph"><p>It should be noted that ccache is susceptible to general storage problems. If a
+bad object file sneaks into the cache for some reason, it will of course stay
+bad. Some possible reasons for erroneous object files are bad hardware (disk
+drive, disk controller, memory, etc), buggy drivers or file systems, a bad
+<strong>prefix_command</strong> or compiler wrapper. If this happens, the easiest way of
+fixing it is this:</p></div>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+Build so that the bad object file ends up in the build tree.
+</p>
+</li>
+<li>
+<p>
+Remove the bad object file from the build tree.
+</p>
+</li>
+<li>
+<p>
+Rebuild with <strong>CCACHE_RECACHE</strong> set.
+</p>
+</li>
+</ol></div>
+<div class="paragraph"><p>An alternative is to clear the whole cache with <strong>ccache -C</strong> if you don&#8217;t mind
+losing other cached results.</p></div>
+<div class="paragraph"><p>There are no reported issues about ccache producing broken object files
+reproducibly. That doesn&#8217;t mean it can&#8217;t happen, so if you find a repeatable
+case, please report it.</p></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_more_information">More information</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Credits, mailing list information, bug reporting instructions, source code,
+etc, can be found on ccache&#8217;s web site: <a href="https://ccache.samba.org">https://ccache.samba.org</a>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_author">Author</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>ccache was originally written by Andrew Tridgell and is currently developed and
+maintained by Joel Rosdahl. See AUTHORS.txt or AUTHORS.html and
+<a href="https://ccache.samba.org/credits.html">https://ccache.samba.org/credits.html</a> for a list of contributors.</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Version 3.3.4<br />
+Last updated
+ 2017-02-12 14:58:39 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/MANUAL.txt b/MANUAL.txt
new file mode 100644
index 0000000..c960979
--- /dev/null
+++ b/MANUAL.txt
@@ -0,0 +1,1053 @@
+CCACHE(1)
+=========
+:man source: ccache
+:man version: {revnumber}
+:man manual: ccache Manual
+
+
+Name
+----
+
+ccache - a fast C/C++ compiler cache
+
+
+Synopsis
+--------
+
+[verse]
+*ccache* ['options']
+*ccache* 'compiler' ['compiler options']
+'compiler' ['compiler options'] (via symbolic link)
+
+
+Description
+-----------
+
+ccache is a compiler cache. It speeds up recompilation by caching the result of
+previous compilations and detecting when the same compilation is being done
+again. Supported languages are C, C\+\+, Objective-C and Objective-C++.
+
+ccache has been carefully written to always produce exactly the same compiler
+output that you would get without the cache. The only way you should be able to
+tell that you are using ccache is the speed. Currently known exceptions to this
+goal are listed under <<_caveats,CAVEATS>>. If you ever discover an
+undocumented case where ccache changes the output of your compiler, please let
+us know.
+
+
+Features
+~~~~~~~~
+
+* Keeps statistics on hits/misses.
+* Automatic cache size management.
+* Can cache compilations that generate warnings.
+* Easy installation.
+* Low overhead.
+* Optionally uses hard links where possible to avoid copies.
+* Optionally compresses files in the cache to reduce disk space.
+
+
+Limitations
+~~~~~~~~~~~
+
+* Only knows how to cache the compilation of a single
+ C/C\+\+/Objective-C/Objective-C++ file. Other types of compilations
+ (multi-file compilation, linking, etc) will silently fall back to running the
+ real compiler.
+* Only works with GCC and compilers that behave similar enough.
+* Some compiler flags are not supported. If such a flag is detected, ccache
+ will silently fall back to running the real compiler.
+
+
+Run modes
+---------
+
+There are two ways to use ccache. You can either prefix your compilation
+commands with *ccache* or you can let ccache masquerade as the compiler by
+creating a symbolic link (named as the compiler) to ccache. The first method is
+most convenient if you just want to try out ccache or wish to use it for some
+specific projects. The second method is most useful for when you wish to use
+ccache for all your compilations.
+
+To use the first method, just make sure that *ccache* is in your *PATH*.
+
+To use the symlinks method, do something like this:
+
+-------------------------------------------------------------------------------
+cp ccache /usr/local/bin/
+ln -s ccache /usr/local/bin/gcc
+ln -s ccache /usr/local/bin/g++
+ln -s ccache /usr/local/bin/cc
+ln -s ccache /usr/local/bin/c++
+-------------------------------------------------------------------------------
+
+And so forth. This will work as long as the directory with symlinks comes
+before the path to the compiler (which is usually in +/usr/bin+). After
+installing you may wish to run ``which gcc'' to make sure that the correct link
+is being used.
+
+WARNING: The technique of letting ccache masquerade as the compiler works well,
+but currently doesn't interact well with other tools that do the same thing.
+See <<_using_ccache_with_other_compiler_wrappers,USING CCACHE WITH OTHER
+COMPILER WRAPPERS>>.
+
+WARNING: Do not use a hard link, use a symbolic link. A hard link will cause
+``interesting'' problems.
+
+Options
+-------
+
+These options only apply when you invoke ccache as ``ccache''. When invoked as
+a compiler (via a symlink as described in the previous section), the normal
+compiler options apply and you should refer to the compiler's documentation.
+
+*-c, --cleanup*::
+
+ Clean up the cache by removing old cached files until the specified file
+ number and cache size limits are not exceeded. This also recalculates the
+ cache file count and size totals. Normally, there is no need to initiate
+ cleanup manually as ccache keeps the cache below the specified limits at
+ runtime and keeps statistics up to date on each compilation. Forcing a
+ cleanup is mostly useful if you manually modify the cache contents or
+ believe that the cache size statistics may be inaccurate.
+
+*-C, --clear*::
+
+ Clear the entire cache, removing all cached files, but keeping the
+ configuration file.
+
+*-F, --max-files*='N'::
+
+ Set the maximum number of files allowed in the cache. Use 0 for no limit.
+ The value is stored in a configuration file in the cache directory and
+ applies to all future compilations.
+
+*-h, --help*::
+
+ Print an options summary page.
+
+*-M, --max-size*='SIZE'::
+
+ Set the maximum size of the files stored in the cache. 'SIZE' should be a
+ number followed by an optional suffix: k, M, G, T (decimal), Ki, Mi, Gi or
+ Ti (binary). The default suffix is G. Use 0 for no limit. The value is
+ stored in a configuration file in the cache directory and applies to all
+ future compilations.
+
+*-o, --set-config*='KEY=VALUE'::
+
+ Set configuration 'KEY' to 'VALUE'. See <<_configuration,CONFIGURATION>>
+ for more information.
+
+*-p, --print-config*::
+
+ Print current configuration options and from where they originate
+ (environment variable, configuration file or compile-time default).
+
+*-s, --show-stats*::
+
+ Print the current statistics summary for the cache.
+
+*-V, --version*::
+
+ Print version and copyright information.
+
+*-z, --zero-stats*::
+
+ Zero the cache statistics (but not the configuration options).
+
+
+Extra options
+-------------
+
+When run as a compiler, ccache usually just takes the same command line options
+as the compiler you are using. The only exception to this is the option
+*--ccache-skip*. That option can be used to tell ccache to avoid interpreting
+the next option in any way and to pass it along to the compiler as-is.
+
+NOTE: *--ccache-skip* currently only tells ccache not to interpret the next
+option as a special compiler option -- the option will still be included in the
+direct mode hash.
+
+The reason this can be important is that ccache does need to parse the command
+line and determine what is an input filename and what is a compiler option, as
+it needs the input filename to determine the name of the resulting object file
+(among other things). The heuristic ccache uses when parsing the command line
+is that any argument that exists as a file is treated as an input file name. By
+using *--ccache-skip* you can force an option to not be treated as an input
+file name and instead be passed along to the compiler as a command line option.
+
+Another case where *--ccache-skip* can be useful is if ccache interprets an
+option specially but shouldn't, since the option has another meaning for your
+compiler than what ccache thinks.
+
+
+Configuration
+-------------
+
+ccache's default behavior can be overridden by configuration file settings,
+which in turn can be overridden by environment variables with names starting
+with *CCACHE_*. ccache normally reads configuration from two files: first a
+system-level configuration file and secondly a cache-specific configuration
+file. The priority of configuration settings is as follows (where 1 is
+highest):
+
+1. Environment variables.
+2. The cache-specific configuration file *<ccachedir>/ccache.conf* (typically
+ *$HOME/.ccache/ccache.conf*).
+3. The system-wide configuration file *<sysconfdir>/ccache.conf* (typically
+ */etc/ccache.conf* or */usr/local/etc/ccache.conf*).
+4. Compile-time defaults.
+
+As a special case, if the environment variable *CCACHE_CONFIGPATH* is set,
+ccache reads configuration from the specified path instead of the default
+paths.
+
+
+Configuration file syntax
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Configuration files are in a simple ``key = value'' format, one setting per
+line. Lines starting with a hash sign are comments. Blank lines are ignored, as
+is whitespace surrounding keys and values. Example:
+
+-------------------------------------------------------------------------------
+# Set maximum cache size to 10 GB:
+max_size = 10G
+-------------------------------------------------------------------------------
+
+Boolean values
+~~~~~~~~~~~~~~
+
+Some settings are boolean values (i.e. truth values). In a configuration file,
+such values must be set to the string *true* or *false*. For the corresponding
+environment variables, the semantics are a bit different: a set environment
+variable means ``true'' regardless of the value (even if set to the empty
+string), and an unset environment variable means ``false''. Each boolean
+environment variable also has a negated form starting with *CCACHE_NO*. For
+example, *CCACHE_COMPRESS* can be set to force compression and
+*CCACHE_NOCOMPRESS* can be set to force no compression.
+
+
+Configuration settings
+~~~~~~~~~~~~~~~~~~~~~~
+
+Below is a list of available configuration settings. The corresponding
+environment variable name is indicated in parentheses after each configuration
+setting key.
+
+*base_dir* (*CCACHE_BASEDIR*)::
+
+ This setting should be an absolute path to a directory. ccache then
+ rewrites absolute paths into relative paths before computing the hash that
+ identifies the compilation, but only for paths under the specified
+ directory. If set to the empty string (which is the default), no rewriting
+ is done. See also the discussion under
+ <<_compiling_in_different_directories,COMPILING IN DIFFERENT DIRECTORIES>>.
+ If using GCC or newer versions of Clang, you might want to look into the
+ *-fdebug-prefix-map=old=new* option for relocating debug info to a common
+ prefix (mapping prefix with old=new).
+
+*cache_dir* (*CCACHE_DIR*)::
+
+ This setting specifies where ccache will keep its cached compiler outputs.
+ It will only take effect if set in the system-wide configuration file or as
+ an environment variable. The default is *$HOME/.ccache*.
+
+*cache_dir_levels* (*CCACHE_NLEVELS*)::
+
+ This setting allows you to choose the number of directory levels in the
+ cache directory. The default is 2. The minimum is 1 and the maximum is 8.
+
+*compiler* (*CCACHE_CC*)::
+
+ This setting can be used to force the name of the compiler to use. If set
+ to the empty string (which is the default), ccache works it out from the
+ command line.
+
+*compiler_check* (*CCACHE_COMPILERCHECK*)::
+
+ By default, ccache includes the modification time (``mtime'') and size of
+ the compiler in the hash to ensure that results retrieved from the cache
+ are accurate. This setting can be used to select another strategy. Possible
+ values are:
++
+--
+*content*::
+ Hash the content of the compiler binary. This makes ccache very slightly
+ slower compared to the *mtime* setting, but makes it cope better with
+ compiler upgrades during a build bootstrapping process.
+*mtime*::
+ Hash the compiler's mtime and size, which is fast. This is the default.
+*none*::
+ Don't hash anything. This may be good for situations where you can safely
+ use the cached results even though the compiler's mtime or size has changed
+ (e.g. if the compiler is built as part of your build system and the
+ compiler's source has not changed, or if the compiler only has changes that
+ don't affect code generation). You should only use the *none* setting if
+ you know what you are doing.
+*string:value*::
+ Use *value* as the string to calculate hash from. This can be the compiler
+ revision number you retrieved earlier and set here via environment variable.
+_a command string_::
+ Hash the standard output and standard error output of the specified
+ command. The string will be split on whitespace to find out the command and
+ arguments to run. No other interpretation of the command string will be
+ done, except that the special word *%compiler%* will be replaced with the
+ path to the compiler. Several commands can be specified with semicolon as
+ separator. Examples:
++
+--
+
+----
+%compiler% -v
+----
+
+----
+%compiler% -dumpmachine; %compiler% -dumpversion
+----
+
+You should make sure that the specified command is as fast as possible since it
+will be run once for each ccache invocation.
+
+Identifying the compiler using a command is useful if you want to avoid cache
+misses when the compiler has been rebuilt but not changed.
+
+Another case is when the compiler (as seen by ccache) actually isn't the real
+compiler but another compiler wrapper -- in that case, the default *mtime*
+method will hash the mtime and size of the other compiler wrapper, which means
+that ccache won't be able to detect a compiler upgrade. Using a suitable
+command to identify the compiler is thus safer, but it's also slower, so you
+should consider continue using the *mtime* method in combination with
+the *prefix_command* setting if possible. See
+<<_using_ccache_with_other_compiler_wrappers,USING CCACHE WITH OTHER COMPILER
+WRAPPERS>>.
+--
+--
+
+*compression* (*CCACHE_COMPRESS* or *CCACHE_NOCOMPRESS*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, ccache will compress object files and other compiler output it
+ puts in the cache. However, this setting has no effect on how files are
+ retrieved from the cache; compressed and uncompressed results will still be
+ usable regardless of this setting. The default is false.
+
+*compression_level* (*CCACHE_COMPRESSLEVEL*)::
+
+ This setting determines the level at which ccache will compress object
+ files. It only has effect if *compression* is enabled. The value defaults
+ to 6, and must be no lower than 1 (fastest, worst compression) and no
+ higher than 9 (slowest, best compression).
+
+*cpp_extension* (*CCACHE_EXTENSION*)::
+
+ This setting can be used to force a certain extension for the intermediate
+ preprocessed file. The default is to automatically determine the extension
+ to use for intermediate preprocessor files based on the type of file being
+ compiled, but that sometimes doesn't work. For example, when using the
+ ``aCC'' compiler on HP-UX, set the cpp extension to *i*.
+
+*direct_mode* (*CCACHE_DIRECT* or *CCACHE_NODIRECT*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, the direct mode will be used. The default is true. See
+ <<_the_direct_mode,THE DIRECT MODE>>.
+
+*disable* (*CCACHE_DISABLE* or *CCACHE_NODISABLE*, see <<_boolean_values,Boolean values>> above)::
+
+ When true, ccache will just call the real compiler, bypassing the cache
+ completely. The default is false.
+
+*extra_files_to_hash* (*CCACHE_EXTRAFILES*)::
+
+ This setting is a list of paths to files that ccache will include in the
+ the hash sum that identifies the build. The list separator is semicolon on
+ Windows systems and colon on other systems.
+
+*hard_link* (*CCACHE_HARDLINK* or *CCACHE_NOHARDLINK*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, ccache will attempt to use hard links from the cache directory
+ when creating the compiler output rather than using a file copy. Using hard
+ links may be slightly faster in some situations, but can confuse programs
+ like ``make'' that rely on modification times. Another thing to keep in
+ mind is that if the resulting object file is modified in any way, this
+ corrupts the cached object file as well. Hard links are never made for
+ compressed cache files. This means that you should not enable compression
+ if you want to use hard links. The default is false.
+
+*hash_dir* (*CCACHE_HASHDIR* or *CCACHE_NOHASHDIR*, see <<_boolean_values,Boolean values>> above)::
+
+ If true (which is the default), ccache will include the current working
+ directory (CWD) in the hash that is used to distinguish two compilations
+ when generating debug info (compiler option *-g* with variations).
+ Exception: The CWD will not be included in the hash if *base_dir* is set
+ (and matches the CWD) and the compiler option *-fdebug-prefix-map* is used.
++
+The reason for including the CWD in the hash by default is to prevent a problem
+with the storage of the current working directory in the debug info of an
+object file, which can lead ccache to return a cached object file that has the
+working directory in the debug info set incorrectly.
++
+You can disable this setting to get cache hits when compiling the same source
+code in different directories if you don't mind that CWD in the debug info
+might be incorrect.
+
+*ignore_headers_in_manifest* (*CCACHE_IGNOREHEADERS*)::
+
+ This setting is a list of paths to files (or directories with headers) that
+ ccache will *not* include in the manifest list that makes up the direct
+ mode. Note that this can cause stale cache hits if those headers do indeed
+ change. The list separator is semicolon on Windows systems and colon on
+ other systems.
+
+*keep_comments_cpp* (*CCACHE_COMMENTS* or *CCACHE_NOCOMMENTS*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, ccache will not discard the comments before hashing preprocessor
+ output. This can be used to check documentation with *-Wdocumentation*.
+
+*limit_multiple* (*CCACHE_LIMIT_MULTIPLE*)::
+
+ Sets the limit when cleaning up. Files are deleted (in LRU order) until the
+ levels are below the limit. The default is 0.8 (= 80%).
+
+*log_file* (*CCACHE_LOGFILE*)::
+
+ If set to a file path, ccache will write information on what it is doing to
+ the specified file. This is useful for tracking down problems.
+
+*max_files* (*CCACHE_MAXFILES*)::
+
+ This option specifies the maximum number of files to keep in the cache. Use
+ 0 for no limit (which is the default).
+
+*max_size* (*CCACHE_MAXSIZE*)::
+
+ This option specifies the maximum size of the cache. Use 0 for no limit.
+ The default value is 5G. Available suffixes: k, M, G, T (decimal) and Ki,
+ Mi, Gi, Ti (binary). The default suffix is "G".
+
+*path* (*CCACHE_PATH*)::
+
+ If set, ccache will search directories in this list when looking for the
+ real compiler. The list separator is semicolon on Windows systems and colon
+ on other systems. If not set, ccache will look for the first executable
+ matching the compiler name in the normal *PATH* that isn't a symbolic link
+ to ccache itself.
+
+*prefix_command* (*CCACHE_PREFIX*)::
+
+ This option adds a list of prefixes (separated by space) to the command
+ line that ccache uses when invoking the compiler. See also
+ <<_using_ccache_with_other_compiler_wrappers,USING CCACHE WITH OTHER
+ COMPILER WRAPPERS>>.
+
+*prefix_command_cpp* (*CCACHE_PREFIX_CPP*)::
+
+ This option adds a list of prefixes (separated by space) to the command
+ line that ccache uses when invoking the preprocessor.
+
+*read_only* (*CCACHE_READONLY* or *CCACHE_NOREADONLY*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, ccache will attempt to use existing cached object files, but it
+ will not to try to add anything new to the cache. If you are using this
+ because your ccache directory is read-only, then you need to set
+ *temporary_dir* as otherwise ccache will fail to create temporary files.
+
+*read_only_direct* (*CCACHE_READONLY_DIRECT* or *CCACHE_NOREADONLY_DIRECT*, see <<_boolean_values,Boolean values>> above)::
+
+ Just like *read_only* except that ccache will only try to retrieve results
+ from the cache using the direct mode, not the preprocessor mode. See
+ documentation for *read_only* regarding using a read-only ccache directory.
+
+*recache* (*CCACHE_RECACHE* or *CCACHE_NORECACHE*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, ccache will not use any previously stored result. New results will
+ still be cached, possibly overwriting any pre-existing results.
+
+*run_second_cpp* (*CCACHE_CPP2* or *CCACHE_NOCPP2*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, ccache will first run the preprocessor to preprocess the source
+ code (see <<_the_preprocessor_mode,THE PREPROCESSOR MODE>>) and then on a
+ cache miss run the compiler on the source code to get hold of the object
+ file. This is the default.
++
+If false, ccache will first run preprocessor to preprocess the source code and
+then on a cache miss run the compiler on the _preprocessed source code_ instead
+of the original source code. This makes cache misses slightly faster since the
+source code only has to be preprocessed once. The downside is that some
+compilers won't produce the same result (for instance diagnostics warnings)
+when compiling preprocessed source code.
+
+*sloppiness* (*CCACHE_SLOPPINESS*)::
+
+ By default, ccache tries to give as few false cache hits as possible.
+ However, in certain situations it's possible that you know things that
+ ccache can't take for granted. This setting makes it possible to tell
+ ccache to relax some checks in order to increase the hit rate. The value
+ should be a comma-separated string with options. Available options are:
++
+--
+*file_macro*::
+ Ignore *\_\_FILE__* being present in the source.
+*file_stat_matches*::
+ ccache normally examines a file's contents to determine whether it matches
+ the cached version. With this option set, ccache will consider a file as
+ matching its cached version if the sizes, mtimes and ctimes match.
+*include_file_ctime*::
+ By default, ccache also will not cache a file if it includes a header whose
+ ctime is too new. This option disables that check.
+*include_file_mtime*::
+ By default, ccache will not cache a file if it includes a header whose
+ mtime is too new. This option disables that check.
+*no_system_headers*::
+ By default, ccache will also include all system headers in the manifest.
+ With this option set, ccache will only include system headers in the hash
+ but not add the system header files to the list of include files.
+*pch_defines*::
+ Be sloppy about #defines when precompiling a header file. See
+ <<_precompiled_headers,PRECOMPILED HEADERS>> for more information.
+*time_macros*::
+ Ignore *\_\_DATE\__* and *\_\_TIME__* being present in the source code.
+--
++
+See the discussion under <<_troubleshooting,TROUBLESHOOTING>> for more
+information.
+
+*stats* (*CCACHE_STATS* or *CCACHE_NOSTATS*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, ccache will update the statistics counters on each compilation.
+ The default is true.
+
+*temporary_dir* (*CCACHE_TEMPDIR*)::
+
+ This setting specifies where ccache will put temporary files. The default
+ is *<cache_dir>/tmp*.
++
+NOTE: In previous versions of ccache, *CCACHE_TEMPDIR* had to be on the same
+ filesystem as the *CCACHE_DIR* path, but this requirement has been
+ relaxed.)
+
+*umask* (*CCACHE_UMASK*)::
+
+ This setting specifies the umask for ccache and all child processes (such
+ as the compiler). This is mostly useful when you wish to share your cache
+ with other users. Note that this also affects the file permissions set on
+ the object files created from your compilations.
+
+*unify* (*CCACHE_UNIFY* or *CCACHE_NOUNIFY*, see <<_boolean_values,Boolean values>> above)::
+
+ If true, ccache will use a C/C++ unifier when hashing the preprocessor
+ output if the *-g* option is not used. The unifier is slower than a normal
+ hash, so setting this environment variable loses a little bit of speed, but
+ it means that ccache can take advantage of not recompiling when the changes
+ to the source code consist of reformatting only. Note that enabling the
+ unifier changes the hash, so cached compilations produced when the unifier
+ is enabled cannot be reused when the unifier is disabled, and vice versa.
+ Enabling the unifier may result in incorrect line number information in
+ compiler warning messages and expansions of the *\_\_LINE__* macro. Also
+ note that enabling the unifier implies turning off the direct mode.
+
+
+Cache size management
+---------------------
+
+By default, ccache has a five gigabyte limit on the total size of files in the
+cache and no maximum number of files. You can set different limits using the
+*-M*/*--max-size* and *-F*/*--max-files* options. Use *ccache -s/--show-stats*
+to see the cache size and the currently configured limits (in addition to other
+various statistics).
+
+
+Cache compression
+-----------------
+
+ccache can optionally compress all files it puts into the cache using the
+compression library zlib. While this may involve a tiny performance slowdown,
+it increases the number of files that fit in the cache. You can turn on
+compression with the *compression* configuration setting and you can also tweak
+the compression level with *compression_level*.
+
+
+Cache statistics
+----------------
+
+*ccache -s/--show-stats* can show the following statistics:
+
+[options="header",cols="30%,70%"]
+|==============================================================================
+|Name | Description
+| autoconf compile/link |
+Uncachable compilation or linking by an autoconf test.
+
+| bad compiler arguments |
+Malformed compiler argument, e.g. missing a value for an option that requires
+an argument or failure to read a file specified by an option argument.
+
+| cache file missing |
+A file was unexpectedly missing from the cache. This only happens in rare
+situations, e.g. if one ccache instance is about to get a file from the cache
+while another instance removed the file as part of cache cleanup.
+
+| cache hit (direct) |
+A result was successfully found using <<_the_direct_mode,the direct mode>>.
+
+| cache hit (preprocessed) |
+A result was successfully found using <<_the_preprocessor_mode,the preprocessor
+mode>>.
+
+| cache miss |
+No result was found.
+
+| cache size |
+Current size of the cache.
+
+| called for link |
+The compiler was called for linking, not compiling.
+
+| called for preprocessing |
+The compiler was called for preprocessing, not compiling.
+
+| can't use precompiled header |
+Preconditions for using <<_precompiled_headers,precompiled headers>> were not
+fulfilled.
+
+| ccache internal error |
+Unexpected failure, e.g. due to problems reading/writing the cache.
+
+| cleanups performed |
+Number of cleanups performed, either implicitly due to the cache size limit
+being reached or due to explicit *ccache -c/--cleanup* calls.
+
+| compile failed |
+The compilation failed. No result stored in the cache.
+
+| compiler check failed |
+A compiler check program specified by *compiler_check* (*CCACHE_COMPILERCHECK*)
+failed.
+
+| compiler produced empty output |
+The compiler's output file (typically an object file) was empty after
+compilation.
+
+| compiler produced no output |
+The compiler's output file (typically an object file) was missing after
+compilation.
+
+| compiler produced stdout |
+The compiler wrote data to standard output. This is something that compilers
+normally never do, so ccache is not designed to store such output in the cache.
+
+| couldn't find the compiler |
+The compiler to execute could not be found.
+
+| error hashing extra file |
+Failure reading a file specified by *extra_files_to_hash*
+(*CCACHE_EXTRAFILES*).
+
+| files in cache |
+Current number of files in the cache.
+
+| multiple source files |
+The compiler was called to compile multiple source files in one go. This is not
+supported by ccache.
+
+| no input file |
+No input file was specified to the compiler.
+
+| output to a non-regular file |
+The output path specified with *-o* is not a file (e.g. a directory or a device
+node).
+
+| output to stdout |
+The compiler was instructed to write its output to standard output using *-o
+-*. This is not supported by ccache.
+
+| preprocessor error |
+Preprocessing the source code using the compiler's *-E* option failed.
+
+| unsupported code directive |
+Code like the assembler ``.incbin'' directive was found. This is not supported
+by ccache.
+
+| unsupported compiler option |
+A compiler option not supported by ccache was found.
+
+| unsupported source language |
+A source language e.g. specified with *-x* was unsupported by ccache.
+
+|==============================================================================
+
+
+How ccache works
+----------------
+
+The basic idea is to detect when you are compiling exactly the same code a
+second time and reuse the previously produced output. The detection is done by
+hashing different kinds of information that should be unique for the
+compilation and then using the hash sum to identify the cached output. ccache
+uses MD4, a very fast cryptographic hash algorithm, for the hashing. (MD4 is
+nowadays too weak to be useful in cryptographic contexts, but it should be safe
+enough to be used to identify recompilations.) On a cache hit, ccache is able
+to supply all of the correct compiler outputs (including all warnings,
+dependency file, etc) from the cache.
+
+ccache has two ways of doing the detection:
+
+* the *direct mode*, where ccache hashes the source code and include files
+ directly
+* the *preprocessor mode*, where ccache runs the preprocessor on the source
+ code and hashes the result
+
+The direct mode is generally faster since running the preprocessor has some
+overhead.
+
+
+Common hashed information
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For both modes, the following information is included in the hash:
+
+* the extension used by the compiler for a file with preprocessor output
+ (normally *.i* for C code and *.ii* for C++ code)
+* the compiler's size and modification time (or other compiler-specific
+ information specified by the *compiler_check* setting)
+* the name of the compiler
+* the current directory (if the *hash_dir* setting is enabled)
+* contents of files specified by the *extra_files_to_hash* setting (if any)
+
+
+The direct mode
+~~~~~~~~~~~~~~~
+
+In the direct mode, the hash is formed of the common information and:
+
+* the input source file
+* the command line options
+
+Based on the hash, a data structure called ``manifest'' is looked up in the
+cache. The manifest contains:
+
+* references to cached compilation results (object file, dependency file, etc)
+ that were produced by previous compilations that matched the hash
+* paths to the include files that were read at the time the compilation results
+ were stored in the cache
+* hash sums of the include files at the time the compilation results were
+ stored in the cache
+
+The current contents of the include files are then hashed and compared to the
+information in the manifest. If there is a match, ccache knows the result of
+the compilation. If there is no match, ccache falls back to running the
+preprocessor. The output from the preprocessor is parsed to find the include
+files that were read. The paths and hash sums of those include files are then
+stored in the manifest along with information about the produced compilation
+result.
+
+There is a catch with the direct mode: header files that were used by the
+compiler are recorded, but header files that were *not* used, but would have
+been used if they existed, are not. So, when ccache checks if a result can be
+taken from the cache, it currently can't check if the existence of a new header
+file should invalidate the result. In practice, the direct mode is safe to use
+in the absolute majority of cases.
+
+The direct mode will be disabled if any of the following holds:
+
+* the configuration setting *direct_mode* is false
+* a modification time of one of the include files is too new (needed to avoid a
+ race condition)
+* the unifier is enabled (the configuration setting *unify* is true)
+* a compiler option not supported by the direct mode is used:
+** a *-Wp,_X_* compiler option other than *-Wp,-MD,_path_*,
+ *-Wp,-MMD,_path_* and *-Wp,-D_define_*
+** *-Xpreprocessor*
+* the string ``\_\_TIME__'' is present in the source code
+
+
+The preprocessor mode
+~~~~~~~~~~~~~~~~~~~~~
+
+In the preprocessor mode, the hash is formed of the common information and:
+
+* the preprocessor output from running the compiler with *-E*
+* the command line options except options that affect include files (*-I*,
+ *-include*, *-D*, etc; the theory is that these options will change the
+ preprocessor output if they have any effect at all)
+* any standard error output generated by the preprocessor
+
+Based on the hash, the cached compilation result can be looked up directly in
+the cache.
+
+
+Compiling in different directories
+----------------------------------
+
+Some information included in the hash that identifies a unique compilation may
+contain absolute paths:
+
+* The preprocessed source code may contain absolute paths to include files if
+ the compiler option *-g* is used or if absolute paths are given to *-I* and
+ similar compiler options.
+* Paths specified by compiler options (such as *-I*, *-MF*, etc) may be
+ absolute.
+* The source code file path may be absolute, and that path may substituted for
+ *\_\_FILE__* macros in the source code or included in warnings emitted to
+ standard error by the preprocessor.
+
+This means that if you compile the same code in different locations, you can't
+share compilation results between the different build directories since you get
+cache misses because of the absolute build directory paths that are part of the
+hash. To mitigate this problem, you can specify a ``base directory'' in the
+configuration setting *base_dir* to an absolute path to the directory. ccache
+will then rewrite absolute paths that are under the base directory (i.e., paths
+that have the base directory as a prefix) to relative paths when constructing
+the hash. A typical path to use as the base directory is your home directory or
+another directory that is a parent of your build directories. (Don't use +/+ as
+the base directory since that will make ccache also rewrite paths to system
+header files, which doesn't gain anything.)
+
+The drawbacks of using a base directory are:
+
+* If you specify an absolute path to the source code file, *\_\_FILE__* macros
+ will be expanded to a relative path instead.
+* If you specify an absolute path to the source code file and compile with
+ *-g*, the source code path stored in the object file may point to the wrong
+ directory, which may prevent debuggers like GDB from finding the source code.
+ Sometimes, a work-around is to change the directory explicitly with the
+ ``cd'' command in GDB.
+
+
+Precompiled headers
+-------------------
+
+ccache has support for GCC's precompiled headers. However, you have to do some
+things to make it work properly:
+
+* You must set *sloppiness* to *pch_defines,time_macros*. The reason is that
+ ccache can't tell whether *\_\_TIME\__* or *\_\_DATE__* is used when using a
+ precompiled header. Further, it can't detect changes in #defines in the
+ source code because of how preprocessing works in combination with
+ precompiled headers.
+* You must either:
++
+--
+** use the *-include* compiler option to include the precompiled header
+ (i.e., don't use *#include* in the source code to include the header); or
+** (for the Clang compiler) use the *-include-pch* compiler option to include
+ the PCH file generated from the precompiled header; or
+** add the *-fpch-preprocess* compiler option when compiling.
+
+If you don't do this, either the non-precompiled version of the header file
+will be used (if available) or ccache will fall back to running the real
+compiler and increase the statistics counter ``preprocessor error'' (if the
+non-precompiled header file is not available).
+--
+
+
+Sharing a cache
+---------------
+
+A group of developers can increase the cache hit rate by sharing a cache
+directory. To share a cache without unpleasant side effects, the following
+conditions should to be met:
+
+* Use the same cache directory.
+* Make sure that the configuration setting *hard_link* is false (which is the
+ default).
+* Make sure that all users are in the same group.
+* Set the configuration setting *umask* to 002. This ensures that cached files
+ are accessible to everyone in the group.
+* Make sure that all users have write permission in the entire cache directory
+ (and that you trust all users of the shared cache).
+* Make sure that the setgid bit is set on all directories in the cache. This
+ tells the filesystem to inherit group ownership for new directories. The
+ following command might be useful for this:
++
+--
+----
+find $CCACHE_DIR -type d | xargs chmod g+s
+----
+--
+
+The reason to avoid the hard link mode is that the hard links cause unwanted
+side effects, as all links to a cached file share the file's modification
+timestamp. This results in false dependencies to be triggered by
+timestamp-based build systems whenever another user links to an existing file.
+Typically, users will see that their libraries and binaries are relinked
+without reason.
+
+You may also want to make sure that a base directory is set appropriately, as
+discussed in a previous section.
+
+
+Sharing a cache on NFS
+----------------------
+
+It is possible to put the cache directory on an NFS filesystem (or similar
+filesystems), but keep in mind that:
+
+* Having the cache on NFS may slow down compilation. Make sure to do some
+ benchmarking to see if it's worth it.
+* ccache hasn't been tested very thoroughly on NFS.
+
+A tip is to set *temporary_dir* to a directory on the local host to avoid NFS
+traffic for temporary files.
+
+
+Using ccache with other compiler wrappers
+-----------------------------------------
+
+The recommended way of combining ccache with another compiler wrapper (such as
+``distcc'') is by letting ccache execute the compiler wrapper. This is
+accomplished by defining the configuration setting *prefix_command*, for
+example by setting the environment variable *CCACHE_PREFIX* to the name of the
+wrapper (e.g. *distcc*). ccache will then prefix the command line with the
+specified command when running the compiler. To specify several prefix
+commands, set *prefix_command* to a colon-separated list of commands.
+
+Unless you set *compiler_check* to a suitable command (see the description of
+that configuration option), it is not recommended to use the form *ccache
+anotherwrapper compiler args* as the compilation command. It's also not
+recommended to use the masquerading technique for the other compiler wrapper.
+The reason is that by default, ccache will in both cases hash the mtime and
+size of the other wrapper instead of the real compiler, which means that:
+
+* Compiler upgrades will not be detected properly.
+* The cached results will not be shared between compilations with and without
+ the other wrapper.
+
+Another minor thing is that if *prefix_command* is used, ccache will not invoke
+the other wrapper when running the preprocessor, which increases performance.
+You can use the *prefix_command_cpp* configuration setting if you also want to
+invoke the other wrapper when doing preprocessing (normally by adding *-E*).
+
+
+Caveats
+-------
+
+* The direct mode fails to pick up new header files in some rare scenarios. See
+ <<_the_direct_mode,THE DIRECT MODE>> above.
+
+
+Troubleshooting
+---------------
+
+General
+~~~~~~~
+
+A general tip for getting information about what ccache is doing is to enable
+debug logging by setting *log_file*. The log contains executed commands,
+important decisions that ccache makes, read and written files, etc. Another way
+of keeping track of what is happening is to check the output of *ccache -s*.
+
+
+Performance
+~~~~~~~~~~~
+
+ccache has been written to perform well out of the box, but sometimes you may
+have to do some adjustments of how you use the compiler and ccache in order to
+improve performance.
+
+Since ccache works best when I/O is fast, put the cache directory on a fast
+storage device if possible. Having lots of free memory so that files in the
+cache directory stay in the disk cache is also preferable.
+
+A good way of monitoring how well ccache works is to run *ccache -s* before and
+after your build and then compare the statistics counters. Here are some common
+problems and what may be done to increase the hit rate:
+
+* If ``cache hit (preprocessed)'' has been incremented instead of ``cache hit
+ (direct)'', ccache has fallen back to preprocessor mode, which is generally
+ slower. Some possible reasons are:
+** The source code has been modified in such a way that the preprocessor output
+ is not affected.
+** Compiler arguments that are hashed in the direct mode but not in the
+ preprocessor mode have changed (*-I*, *-include*, *-D*, etc) and they didn't
+ affect the preprocessor output.
+** The compiler option *-Xpreprocessor* or *-Wp,_X_* (except *-Wp,-MD,_path_*,
+ *-Wp,-MMD,_path_*, and *-Wp,-D_define_*) is used.
+** This was the first compilation with a new value of the base directory
+ setting.
+** A modification time of one of the include files is too new (created the same
+ second as the compilation is being done). This check is made to avoid a race
+ condition. To fix this, create the include file earlier in the build
+ process, if possible, or set *sloppiness* to *include_file_mtime* if you are
+ willing to take the risk. (The race condition consists of these events: the
+ preprocessor is run; an include file is modified by someone; the new include
+ file is hashed by ccache; the real compiler is run on the preprocessor's
+ output, which contains data from the old header file; the wrong object file
+ is stored in the cache.)
+** The *\_\_TIME\__* preprocessor macro is (potentially) being used. ccache
+ turns off direct mode if ``\_\_TIME\__'' is present in the source code. This
+ is done as a safety measure since the string indicates that a *\_\_TIME\__*
+ macro _may_ affect the output. (To be sure, ccache would have to run the
+ preprocessor, but the sole point of the direct mode is to avoid that.) If
+ you know that *\_\_TIME\__* isn't used in practise, or don't care if ccache
+ produces objects where *\_\_TIME__* is expanded to something in the past,
+ you can set *sloppiness* to *time_macros*.
+** The *\_\_DATE\__* preprocessor macro is (potentially) being used and the
+ date has changed. This is similar to how *\_\_TIME\__* is handled. If
+ ``\_\_DATE\__'' is present in the source code, ccache hashes the current
+ date in order to be able to produce the correct object file if the
+ *\_\_DATE\__* macro affects the output. If you know that *\_\_DATE\__* isn't
+ used in practise, or don't care if ccache produces objects where
+ *\_\_DATE__* is expanded to something in the past, you can set *sloppiness*
+ to *time_macros*.
+** The *\_\_FILE\__* preprocessor macro is (potentially) being used and the
+ file path has changed. If ``\_\_FILE\__'' is present in the source code,
+ ccache hashes the current input file path in order to be able to produce the
+ correct object file if the *\_\_FILE\__* macro affects the output. If you
+ know that *\_\_FILE\__* isn't used in practise, or don't care if ccache
+ produces objects where *\_\_FILE__* is expanded to the wrong path, you can
+ set *sloppiness* to *file_macro*.
+* If ``cache miss'' has been incremented even though the same code has been
+ compiled and cached before, ccache has either detected that something has
+ changed anyway or a cleanup has been performed (either explicitly or
+ implicitly when a cache limit has been reached). Some perhaps unobvious
+ things that may result in a cache miss are usage of *\_\_TIME\__* or
+ *\_\_DATE__* macros, or use of automatically generated code that contains a
+ timestamp, build counter or other volatile information.
+* If ``multiple source files'' has been incremented, it's an indication that
+ the compiler has been invoked on several source code files at once. ccache
+ doesn't support that. Compile the source code files separately if possible.
+* If ``unsupported compiler option'' has been incremented, enable debug logging
+ and check which option was rejected.
+* If ``preprocessor error'' has been incremented, one possible reason is that
+ precompiled headers are being used. See <<_precompiled_headers,PRECOMPILED
+ HEADERS>> for how to remedy this.
+* If ``can't use precompiled header'' has been incremented, see
+ <<_precompiled_headers,PRECOMPILED HEADERS>>.
+
+
+Corrupt object files
+~~~~~~~~~~~~~~~~~~~~
+
+It should be noted that ccache is susceptible to general storage problems. If a
+bad object file sneaks into the cache for some reason, it will of course stay
+bad. Some possible reasons for erroneous object files are bad hardware (disk
+drive, disk controller, memory, etc), buggy drivers or file systems, a bad
+*prefix_command* or compiler wrapper. If this happens, the easiest way of
+fixing it is this:
+
+1. Build so that the bad object file ends up in the build tree.
+2. Remove the bad object file from the build tree.
+3. Rebuild with *CCACHE_RECACHE* set.
+
+An alternative is to clear the whole cache with *ccache -C* if you don't mind
+losing other cached results.
+
+There are no reported issues about ccache producing broken object files
+reproducibly. That doesn't mean it can't happen, so if you find a repeatable
+case, please report it.
+
+
+More information
+----------------
+
+Credits, mailing list information, bug reporting instructions, source code,
+etc, can be found on ccache's web site: <https://ccache.samba.org>.
+
+
+Author
+------
+
+ccache was originally written by Andrew Tridgell and is currently developed and
+maintained by Joel Rosdahl. See AUTHORS.txt or AUTHORS.html and
+<https://ccache.samba.org/credits.html> for a list of contributors.
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..5aee02d
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,133 @@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+mandir = @mandir@
+datarootdir = @datarootdir@
+sysconfdir = @sysconfdir@
+installcmd = @INSTALL@
+
+AR = @AR@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+EXEEXT = @EXEEXT@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+RANLIB = @RANLIB@
+
+all_cflags = $(CFLAGS)
+all_cppflags = @DEFS@ -DSYSCONFDIR=$(sysconfdir) -I. -I$(srcdir) $(CPPFLAGS)
+extra_libs = @extra_libs@
+
+non_3pp_sources = \
+ args.c \
+ ccache.c \
+ cleanup.c \
+ compopt.c \
+ conf.c \
+ counters.c \
+ execute.c \
+ exitfn.c \
+ hash.c \
+ hashutil.c \
+ language.c \
+ lockfile.c \
+ manifest.c \
+ mdfour.c \
+ stats.c \
+ unify.c \
+ util.c \
+ version.c
+3pp_sources = \
+ getopt_long.c \
+ hashtable.c \
+ hashtable_itr.c \
+ murmurhashneutral2.c \
+ snprintf.c
+base_sources = $(non_3pp_sources) $(3pp_sources)
+base_objs = $(base_sources:.c=.o)
+
+ccache_sources = main.c $(base_sources)
+ccache_objs = $(ccache_sources:.c=.o)
+
+zlib_sources = \
+ zlib/adler32.c zlib/crc32.c zlib/deflate.c zlib/gzclose.c zlib/gzlib.c \
+ zlib/gzread.c zlib/gzwrite.c zlib/inffast.c zlib/inflate.c \
+ zlib/inftrees.c zlib/trees.c zlib/zutil.c
+zlib_objs = $(zlib_sources:.c=.o)
+
+test_suites = @test_suites@
+test_sources = test/main.c test/framework.c test/util.c $(test_suites)
+test_objs = $(test_sources:.c=.o)
+
+all_sources = $(ccache_sources) $(test_sources)
+all_objs = $(ccache_objs) $(test_objs) $(zlib_objs)
+
+files_to_clean = $(all_objs) ccache$(EXEEXT) test/main$(EXEEXT) *~ testdir.*
+files_to_distclean = Makefile config.h config.log config.status
+
+.PHONY: all
+all: ccache$(EXEEXT)
+
+ccache$(EXEEXT): $(ccache_objs) $(extra_libs)
+ $(CC) $(all_cflags) -o $@ $(ccache_objs) $(LDFLAGS) $(extra_libs) $(LIBS)
+
+.PHONY: install
+install: all $(srcdir)/ccache.1
+ $(installcmd) -d $(DESTDIR)$(bindir)
+ $(installcmd) -m 755 ccache$(EXEEXT) $(DESTDIR)$(bindir)
+ $(installcmd) -d $(DESTDIR)$(mandir)/man1
+ -$(installcmd) -m 644 $(srcdir)/ccache.1 $(DESTDIR)$(mandir)/man1/
+
+.PHONY: clean
+clean:
+ rm -rf $(files_to_clean)
+
+conf.c: confitems_lookup.c envtoconfitems_lookup.c
+
+$(zlib_objs): CPPFLAGS += -include config.h
+
+zlib/libz.a: $(zlib_objs)
+ $(AR) cr $@ $(zlib_objs)
+ $(RANLIB) $@
+
+.PHONY: perf
+perf: ccache$(EXEEXT)
+ $(srcdir)/perf.py --ccache ccache$(EXEEXT) $(CC) $(all_cppflags) $(all_cflags) $(srcdir)/ccache.c
+
+.PHONY: test
+test: ccache$(EXEEXT) test/main$(EXEEXT)
+ test/main$(EXEEXT)
+ CC='$(CC)' $(srcdir)/test.sh
+
+.PHONY: quicktest
+quicktest: test/main$(EXEEXT)
+ test/main$(EXEEXT)
+
+test/main$(EXEEXT): $(base_objs) $(test_objs) $(extra_libs)
+ $(CC) $(all_cflags) -o $@ $(base_objs) $(test_objs) $(LDFLAGS) $(extra_libs) $(LIBS)
+
+test/main.o: test/suites.h
+
+test/suites.h: $(test_suites) Makefile
+ sed -n 's/TEST_SUITE(\(.*\))/SUITE(\1)/p' $(test_suites) >$@
+
+.PHONY: check
+check: test
+
+.PHONY: distclean
+distclean: clean
+ rm -rf $(files_to_distclean)
+
+.PHONY: installcheck
+installcheck: ccache$(EXEEXT) test/main$(EXEEXT)
+ test/main$(EXEEXT)
+ CCACHE=$(bindir)/ccache CC='$(CC)' $(srcdir)/test.sh
+
+.c.o:
+ $(CC) $(all_cppflags) $(all_cflags) -c -o $@ $<
+
+@include_dev_mk@
diff --git a/NEWS.html b/NEWS.html
new file mode 100644
index 0000000..6e8af4f
--- /dev/null
+++ b/NEWS.html
@@ -0,0 +1,2742 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.9" />
+<title>ccache news</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install(2);
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>ccache news</h1>
+<span id="revnumber">version 3.3.4</span>
+<div id="toc">
+ <div id="toctitle">Table of Contents</div>
+ <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_ccache_3_3_4">ccache 3.3.4</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2017-02-17</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Documented the different cache statistics counters.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed a regression in ccache 3.3 related to potentially bad content of
+ dependency files when compiling identical source code but with different
+ source paths. This was only partially fixed in 3.3.2 and reverts the new
+ &#8220;Names of included files are no longer included in the hash of the
+ compiler&#8217;s preprocessed output&#8221; feature in 3.3.
+</p>
+</li>
+<li>
+<p>
+Corrected statistics counter for <code>-optf</code>/<code>--options-file</code> failure.
+</p>
+</li>
+<li>
+<p>
+Fixed undefined behavior warnings in ccache found by <code>-fsanitize=undefined</code>.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_3_3">ccache 3.3.3</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-10-26</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_2">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+ccache now detects usage of <code>.incbin</code> assembler directives in the source code
+ and avoids caching such compilations.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_3_2">ccache 3.3.2</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-09-28</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_3">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed a regression in ccache 3.3 related to potentially bad content of
+ dependency files when compiling identical source code but with different
+ source paths.
+</p>
+</li>
+<li>
+<p>
+Fixed a regression in ccache 3.3.1: ccache could get confused when using the
+ compiler option <code>-Wp,</code> to pass multiple options to the preprocessor,
+ resulting in missing dependency files from direct mode cache hits.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_3_1">ccache 3.3.1</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-09-07</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_4">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed a problem in the &#8220;multiple <code>-arch</code> options&#8221; support introduced in
+ 3.3. When using the direct mode (the default), different combinations of
+ <code>-arch</code> options were not detected properly.
+</p>
+</li>
+<li>
+<p>
+Fixed an issue when compiler option <code>-Wp,-MT,path</code> is used instead of <code>-MT
+ path</code> (and similar for <code>-MF</code>, <code>-MP</code> and <code>-MQ</code>) and <code>run_second_cpp</code>
+ (<code>CCACHE_CPP2</code>) is enabled.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_3">ccache 3.3</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-08-27</p></div>
+<div class="sect2">
+<h3 id="_notes">Notes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+A C99-compatible compiler is now required to build ccache.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_2">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+The configuration option <code>run_second_cpp</code> (<code>CCACHE_CPP2</code>) now defaults to
+ true. This improves ccache&#8217;s out-of-the-box experience for compilers that
+ can&#8217;t compile their own preprocessed output with the same outcome as if they
+ compiled the real source code directly, e.g. newer versions of GCC and Clang.
+</p>
+</li>
+<li>
+<p>
+The configuration option <code>hash_dir</code> (<code>CCACHE_HASHDIR</code>) now defaults to true.
+</p>
+</li>
+<li>
+<p>
+Added a new <code>ignore_headers_in_manifest</code> configuration option, which
+ specifies headers that should be ignored in the direct mode.
+</p>
+</li>
+<li>
+<p>
+Added a new <code>prefix_command_cpp</code> (<code>CCACHE_PREFIX_CPP</code>) configuration option,
+ which specifies one or several prefixes to add to the command line ccache
+ uses when invoking the preprocessor.
+</p>
+</li>
+<li>
+<p>
+Added a new <code>limit_multiple</code> (<code>CCACHE_LIMIT_MULTIPLE</code>) configuration option,
+ which specifies how much of the cache to remove when cleaning.
+</p>
+</li>
+<li>
+<p>
+Added a new <code>keep_comments_cpp</code> (<code>CCACHE_COMMENTS</code>) configuration option,
+ which tells ccache not to discard the comments before hashing preprocessor
+ output. This can be used to check documentation with <strong>-Wdocumentation</strong>.
+</p>
+</li>
+<li>
+<p>
+Added a new sloppiness option <code>no_system_headers</code>, which tells ccache not to
+ include system headers in manifest files.
+</p>
+</li>
+<li>
+<p>
+Added a new statistics counter that tracks the number of performed cleanups
+ due to the cache size being over the limit. The value is shown in the output
+ of &#8220;ccache -s&#8221;.
+</p>
+</li>
+<li>
+<p>
+Added support for relocating debug info directory using <code>-fdebug-prefix-map</code>.
+ This allows for cache hits even when <code>hash_dir</code> is used in combination with
+ <code>base_dir</code>.
+</p>
+</li>
+<li>
+<p>
+Added a new &#8220;cache hit rate&#8221; field to the output of &#8220;ccache -s&#8221;.
+</p>
+</li>
+<li>
+<p>
+Added support for caching compilation of assembler code produced by e.g.
+ &#8220;gcc -S file.c&#8221;.
+</p>
+</li>
+<li>
+<p>
+Added support for cuda including the -optf/--options-file option.
+</p>
+</li>
+<li>
+<p>
+Added support for Fortran 77.
+</p>
+</li>
+<li>
+<p>
+Added support for multiple <code>-arch</code> options to produce "fat binaries".
+</p>
+</li>
+<li>
+<p>
+Multiple identical <code>-arch</code> arguments are now handled without bailing.
+</p>
+</li>
+<li>
+<p>
+The concatenated form of some long compiler options is now recognized, for
+ example when using <code>-isystemPATH</code> instead of <code>-isystem PATH</code>.
+</p>
+</li>
+<li>
+<p>
+If hard-linking is enabled and but fails (e.g. due to cross-device linking),
+ ccache now falls back to copying instead of running the compiler.
+</p>
+</li>
+<li>
+<p>
+Made the <code>hash_dir</code> option only have effect when generating debug info.
+</p>
+</li>
+<li>
+<p>
+ccache now knows how to convert absolute paths to relative paths inside
+ dependency files when using <code>base_dir</code>.
+</p>
+</li>
+<li>
+<p>
+Improved parsing of <code>-g*</code> options.
+</p>
+</li>
+<li>
+<p>
+Made ccache understand <code>-Wp,-D*</code> options.
+</p>
+</li>
+<li>
+<p>
+ccache now understands the undocumented <code>-coverage</code> (only one dash) GCC
+ option.
+</p>
+</li>
+<li>
+<p>
+Names of included files are no longer included in the hash of the compiler&#8217;s
+ preprocessed output. This leads to more potential cache hits when not using
+ the direct mode.
+</p>
+</li>
+<li>
+<p>
+Increased buffer size used when reading file data. This improves performance
+ slightly.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_5">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Bail out on too hard compiler option <code>-P</code>.
+</p>
+</li>
+<li>
+<p>
+Fixed clang test suite when running on Linux.
+</p>
+</li>
+<li>
+<p>
+Fixed build and test for MinGW32 and Windows.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2_9">ccache 3.2.9</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-09-28</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_6">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed a regression in ccache 3.2.8: ccache could get confused when using the
+ compiler option <code>-Wp,</code> to pass multiple options to the preprocessor,
+ resulting in missing dependency files from direct mode cache hits.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2_8">ccache 3.2.8</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-09-07</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_7">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed an issue when compiler option <code>-Wp,-MT,path</code> is used instead of <code>-MT
+ path</code> (and similar for <code>-MF</code>, <code>-MP</code> and <code>-MQ</code>) and <code>run_second_cpp</code>
+ (<code>CCACHE_CPP2</code>) is enabled.
+</p>
+</li>
+<li>
+<p>
+ccache now understands the undocumented <code>-coverage</code> (only one dash) GCC
+ option.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2_7">ccache 3.2.7</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-07-20</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_8">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed a bug which could lead to false cache hits for compiler command lines
+ with a missing argument to an option that takes an argument.
+</p>
+</li>
+<li>
+<p>
+ccache now knows how to work around a glitch in the output of GCC 6&#8217;s
+ preprocessor.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2_6">ccache 3.2.6</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-07-12</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_9">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed build problem on QNX, which lacks &#8220;SA_RESTART&#8221;.
+</p>
+</li>
+<li>
+<p>
+Bail out on compiler option <code>-fstack-usage</code> since it creates a <code>.su</code> file
+ which ccache currently doesn&#8217;t handle.
+</p>
+</li>
+<li>
+<p>
+Fixed a bug where (due to ccache rewriting paths) the compiler could choose
+ incorrect include files if <code>CCACHE_BASEDIR</code> is used and the source file path
+ is absolute and is a symlink.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2_5">ccache 3.2.5</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-04-17</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_3">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Only pass clang-specific <code>-stdlib=</code> to the preprocessor.
+</p>
+</li>
+<li>
+<p>
+Improved handling of stale NFS handles.
+</p>
+</li>
+<li>
+<p>
+Made it harder to misinterpret documentation of boolean environment settings'
+ semantics.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_10">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Include m4 files used by configure.ac in the source dist archives.
+</p>
+</li>
+<li>
+<p>
+Corrected "Performance" section in the manual regarding <code>__DATE_</code>, <code>__TIME__</code>
+ and <code>__FILE__</code> macros.
+</p>
+</li>
+<li>
+<p>
+Fixed build on Solaris 10+ and AIX 7.
+</p>
+</li>
+<li>
+<p>
+Fixed failure to create directories on QNX.
+</p>
+</li>
+<li>
+<p>
+Don&#8217;t (try to) update manifest file in &#8220;read-only&#8221; and &#8220;read-only direct&#8221;
+ modes.
+</p>
+</li>
+<li>
+<p>
+Fixed a bug in caching of <code>stat</code> system calls in &#8220;file_stat_matches
+ sloppiness mode&#8221;.
+</p>
+</li>
+<li>
+<p>
+Fixed bug in hashing of clang plugins, leading to unnecessary cache misses.
+</p>
+</li>
+<li>
+<p>
+Fixed --print-config to show &#8220;pch_defines sloppiness&#8221;.
+</p>
+</li>
+<li>
+<p>
+The man page is now built when running &#8220;make install&#8221; from Git repository
+ sources.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2_4">ccache 3.2.4</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2015-10-08</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_11">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed build error related to zlib on systems with older make versions
+ (regression in ccache 3.2.3).
+</p>
+</li>
+<li>
+<p>
+Made conversion-to-bool explicit to avoid build warnings (and potential
+ runtime errors) on legacy systems.
+</p>
+</li>
+<li>
+<p>
+Improved signal handling: Kill compiler on SIGTERM; wait for compiler to exit
+ before exiting; die appropriately.
+</p>
+</li>
+<li>
+<p>
+Minor fixes related to Windows support.
+</p>
+</li>
+<li>
+<p>
+The correct compression level is now used if compression is requested.
+</p>
+</li>
+<li>
+<p>
+Fixed a bug where cache cleanup could be run too early for caches larger than
+ 64 GiB on 32-bit systems.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2_3">ccache 3.2.3</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2015-08-16</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_4">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Added support for compiler option <code>-gsplit-dwarf</code>.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_12">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Support external zlib in nonstandard directory.
+</p>
+</li>
+<li>
+<p>
+Avoid calling <code>exit()</code> inside an exit handler.
+</p>
+</li>
+<li>
+<p>
+Let exit handler terminate properly.
+</p>
+</li>
+<li>
+<p>
+Bail out on compiler option <code>--save-temps</code> in addition to <code>-save-temps</code>.
+</p>
+</li>
+<li>
+<p>
+Only log "Disabling direct mode" once when failing to read potential include
+ files.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2_2">ccache 3.2.2</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2015-05-10</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_5">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Added support for <code>CCACHE_COMPILERCHECK=string:&lt;value&gt;</code>. This is a faster
+ alternative to <code>CCACHE_COMPILERCHECK=&lt;command&gt;</code> if the command&#8217;s output can
+ be precalculated by the build system.
+</p>
+</li>
+<li>
+<p>
+Add support for caching code coverage results (compiling for gcov).
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_13">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Made hash of cached result created with and without <code>CCACHE_CPP2</code> different.
+ This makes it possible to rebuild with <code>CCACHE_CPP2</code> set without having to
+ clear the cache to get new results.
+</p>
+</li>
+<li>
+<p>
+Don&#8217;t try to reset a non-existing stats file. This avoids &#8220;No such file or
+ directory&#8221; messages in the ccache log when the cache directory doesn&#8217;t
+ exist.
+</p>
+</li>
+<li>
+<p>
+Fixed a bug where ccache deleted clang diagnostics after compiler failures.
+</p>
+</li>
+<li>
+<p>
+Avoid performing an unnecessary copy of the object file on a cache miss.
+</p>
+</li>
+<li>
+<p>
+Bail out on too hard compiler option <code>-fmodules</code>.
+</p>
+</li>
+<li>
+<p>
+Bail out on too hard compiler option <code>-fplugin=libcc1plugin</code> (interaction
+ with GDB).
+</p>
+</li>
+<li>
+<p>
+Fixed build error when compiling ccache with recent clang versions.
+</p>
+</li>
+<li>
+<p>
+Removed signal-unsafe code from signal handler.
+</p>
+</li>
+<li>
+<p>
+Corrected logic for when to output cached stderr.
+</p>
+</li>
+<li>
+<p>
+Wipe the whole cached result on failure retrieving a cached file.
+</p>
+</li>
+<li>
+<p>
+Fixed build error when compiling ccache with recent clang versions.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2_1">ccache 3.2.1</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2014-12-10</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_14">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed regression in temporary file handling, which lead to incorrect
+ permissions for stats, manifest and ccache.conf files in the cache.
+</p>
+</li>
+<li>
+<p>
+<code>CACHEDIR.TAG</code> files are now created in the [0-9a-f] subdirectories so that
+ ccache.conf is not lost in backups.
+</p>
+</li>
+<li>
+<p>
+Made the default cache size suffix <code>G</code>, as previously documented.
+</p>
+</li>
+<li>
+<p>
+<code>-fdiagnostics-color=auto</code> is now passed to the compiler even if stderr is
+ redirected. This fixes a problem when, for instance, a configure test probes
+ if the compiler (wrapped via ccache) supports <code>-fdiagnostics-color=auto</code>.
+</p>
+</li>
+<li>
+<p>
+Added missing documentation for <code>max_files</code> and <code>max_size</code> configuration
+ options.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_2">ccache 3.2</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2014-11-17</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_6">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Added support for configuring ccache via one or several configuration files
+ instead of via environment variables. Environment variables still have
+ priority but are no longer the recommended way of customizing ccache
+ behavior. See the manual for more information.
+</p>
+</li>
+<li>
+<p>
+Added support for compiler error/warning messages with color.
+</p>
+</li>
+<li>
+<p>
+Made creation of temporary directories and cache directories smarter to avoid
+ unnecessary <code>stat</code> calls.
+</p>
+</li>
+<li>
+<p>
+Improved efficiency of the algorithm that scans for <code>__DATE_</code> and <code>__TIME__</code>
+ tokens in the hashed source code.
+</p>
+</li>
+<li>
+<p>
+Added support for several binaries (separated by space) in <code>CCACHE_PREFIX</code>.
+</p>
+</li>
+<li>
+<p>
+The <code>-c</code> option is no longer passed to the preprocessor. This fixes problems
+ with clang and Solaris&#8217;s C++ compiler.
+</p>
+</li>
+<li>
+<p>
+ccache no longer passes preprocessor options like <code>-D</code> and <code>-I</code> to the
+ compiler when compiling preprocessed output. This fixes warnings emitted by
+ clang.
+</p>
+</li>
+<li>
+<p>
+Compiler options <code>-fprofile-generate</code>, <code>-fprofile-arcs</code>, <code>-fprofile-use</code> and
+ <code>-fbranch-probabilities</code> are now handled without bailing.
+</p>
+</li>
+<li>
+<p>
+Added support for clang&#8217;s <code>--serialize-diagnostic</code> option, storing the
+ diagnostic file (<code>.dia</code>) in the cache.
+</p>
+</li>
+<li>
+<p>
+Added support for precompiled headers when using clang.
+</p>
+</li>
+<li>
+<p>
+Added support for clang <code>.pth</code> (pretokenized header) files.
+</p>
+</li>
+<li>
+<p>
+Changed the <code>-x</code> language option to use the new objective C standard for GCC
+ and clang.
+</p>
+</li>
+<li>
+<p>
+On a cache miss, ccache now instructs the compiler to create the object file
+ at the real destination and then copies the file into the cache instead of
+ the other way around. This is needed to support compiler options like
+ <code>-fprofile-arcs</code> and <code>--serialize-diagnostics</code>.
+</p>
+</li>
+<li>
+<p>
+ccache now checks that included files' ctimes aren&#8217;t too new. This check can
+ be turned off by adding <code>include_file_ctime</code> to the &#8220;ccache sloppiness&#8221;
+ setting.
+</p>
+</li>
+<li>
+<p>
+Added possibility to get cache hits based on filename, size, mtime and ctime
+ only. On other words, source code files are not even read, only stat-ed. This
+ operation mode is opt-in by adding <code>file_stat_matches</code> to the &#8220;ccache
+ sloppiness&#8221; setting.
+</p>
+</li>
+<li>
+<p>
+The filename part of options like <code>-Wp,-MDfilename</code> is no longer included in
+ the hash since the filename doesn&#8217;t have any bearing on the result.
+</p>
+</li>
+<li>
+<p>
+Added a &#8220;read-only direct&#8221; configuration setting, which is like the
+ ordinary read-only setting except that ccache will only try to retrieve
+ results from the cache using the direct mode, not the preprocessor mode.
+</p>
+</li>
+<li>
+<p>
+The display and interpretation of cache size has been changed to use SI
+ units.
+</p>
+</li>
+<li>
+<p>
+Default cache size is now 5 GB (was previously 1 GiB).
+</p>
+</li>
+<li>
+<p>
+Added configuration option to set the compression level of compressed object
+ files in the cache.
+</p>
+</li>
+<li>
+<p>
+Added support for <code>@file</code> and <code>-@file</code> arguments (reading options from a
+ file).
+</p>
+</li>
+<li>
+<p>
+<code>-Wl,</code> options are no longer included in the hash since they don&#8217;t affect
+ compilation.
+</p>
+</li>
+<li>
+<p>
+Bail out on too hard compiler option <code>-Wp,-P</code>.
+</p>
+</li>
+<li>
+<p>
+Optimized MD4 calculation code on little-endian systems.
+</p>
+</li>
+<li>
+<p>
+Various improvements and fixes on win32.
+</p>
+</li>
+<li>
+<p>
+Improved logging to the ccache log file.
+</p>
+</li>
+<li>
+<p>
+Added <code>--dump-manifest</code> command-line option for debugging purposes.
+</p>
+</li>
+<li>
+<p>
+Added <code>--with-bundled-zlib</code> configure option.
+</p>
+</li>
+<li>
+<p>
+Upgraded bundled zlib to version 1.2.8.
+</p>
+</li>
+<li>
+<p>
+Improved <code>dev.mk</code> to be more platform independent.
+</p>
+</li>
+<li>
+<p>
+Made the test suite work with clang and gcc-llvm on OS X.
+</p>
+</li>
+<li>
+<p>
+Various other improvements of the test suite.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_15">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Any previous <code>.stderr</code> is now removed from the cache when recaching.
+</p>
+</li>
+<li>
+<p>
+Fixed an issue when handling the <code>-arch</code> compiler option with an argument.
+</p>
+</li>
+<li>
+<p>
+Fixed race condition when creating the initial cache directory.
+</p>
+</li>
+<li>
+<p>
+Fixed test suite failures when <code>CC</code> is a ccache-wrapped compiler.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_12">ccache 3.1.12</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2016-07-12</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_16">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed a bug where (due to ccache rewriting paths) the compiler could choose
+ incorrect include files if <code>CCACHE_BASEDIR</code> is used and the source file path
+ is absolute and is a symlink.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_11">ccache 3.1.11</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2015-03-07</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_17">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed bug which could result in false cache hits when source code contains
+ <code>'"'</code> followed by <code>" /*"</code> or <code>" //"</code> (with variations).
+</p>
+</li>
+<li>
+<p>
+Made hash of cached result created with and without <code>CCACHE_CPP2</code> different.
+ This makes it possible to rebuild with <code>CCACHE_CPP2</code> set without having to
+ clear the cache to get new results.
+</p>
+</li>
+<li>
+<p>
+Don&#8217;t try to reset a non-existing stats file. This avoids &#8220;No such file or
+ directory&#8221; messages in the ccache log when the cache directory doesn&#8217;t
+ exist.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_10">ccache 3.1.10</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2014-10-19</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_7">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Added support for the <code>-Xclang</code> compiler option.
+</p>
+</li>
+<li>
+<p>
+Improved handling of exit code of internally executed processes.
+</p>
+</li>
+<li>
+<p>
+Zero length object files in the cache are now rejected as invalid.
+</p>
+</li>
+<li>
+<p>
+Bail out on option <code>-gsplit-dwarf</code> (since it produces multiple output files).
+</p>
+</li>
+<li>
+<p>
+Compiler option <code>-fdebug-prefix-map</code> is now ignored (not part of the hash).
+ (The <code>-fdebug-prefix-map</code> option may be used in combination with
+ <code>CCACHE_BASEDIR</code> to reuse results across different directories.)
+</p>
+</li>
+<li>
+<p>
+Added note in documentation that <code>--ccache-skip</code> currently does not mean
+ &#8220;don&#8217;t hash the following option&#8221;.
+</p>
+</li>
+<li>
+<p>
+To enable support for precompiled headers (PCH), <code>CCACHE_SLOPPINESS</code> now also
+ needs to include the new <code>pch_defines</code> sloppiness. This is because ccache
+ can&#8217;t detect changes in the source code when only defined macros have been
+ changed.
+</p>
+</li>
+<li>
+<p>
+Stale files in the internal temporary directory (<code>&lt;ccache_dir&gt;/tmp</code>) are now
+ cleaned up if they are older than one hour.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_18">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed path canonicalization in <code>make_relative_path()</code> when path doesn&#8217;t
+ exist.
+</p>
+</li>
+<li>
+<p>
+Fixed bug in <code>common_dir_prefix_length()</code>. This corrects the <code>CCACHE_BASEDIR</code>
+ behavior.
+</p>
+</li>
+<li>
+<p>
+ccache no longer tries to create the cache directory when <code>CCACHE_DISABLE</code> is
+ set.
+</p>
+</li>
+<li>
+<p>
+Fixed bug when reading manifests with a very large number of file info
+ entries.
+</p>
+</li>
+<li>
+<p>
+Fixed problem with logging of current working directory.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_9">ccache 3.1.9</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2013-01-06</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_19">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+The EAGAIN signal is now handled correctly when emitting cached stderr
+ output. This fixes a problem triggered by large error outputs from the
+ compiler.
+</p>
+</li>
+<li>
+<p>
+Subdirectories in the cache are no longer created in read-only mode.
+</p>
+</li>
+<li>
+<p>
+Fixed so that ccache&#8217;s log file descriptor is not made available to the
+ compiler.
+</p>
+</li>
+<li>
+<p>
+Improved error reporting when failing to create temporary stdout/stderr files
+ when executing the compiler.
+</p>
+</li>
+<li>
+<p>
+Disappearing temporary stdout/stderr files are now handled gracefully.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_other">Other</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed test suite to work on ecryptfs.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_8">ccache 3.1.8</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2012-08-11</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_8">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Made paths to dependency files relative in order to increase cache hits.
+</p>
+</li>
+<li>
+<p>
+Added work-around to make ccache work with buggy GCC 4.1 when creating a
+ pre-compiled header.
+</p>
+</li>
+<li>
+<p>
+Clang plugins are now hashed to catch plugin upgrades.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_20">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Fixed crash when the current working directory has been removed.
+</p>
+</li>
+<li>
+<p>
+Fixed crash when stderr is closed.
+</p>
+</li>
+<li>
+<p>
+Corrected a corner case when parsing backslash escapes in string
+ literals.
+</p>
+</li>
+<li>
+<p>
+Paths are now correctly canonicalized when computing paths relative to the
+ base directory.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_other_2">Other</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Made git version macro work when compiling outside of the source directory.
+</p>
+</li>
+<li>
+<p>
+Fixed <code>static_assert</code> macro definition clash with GCC 4.7.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_7">ccache 3.1.7</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2012-01-08</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_21">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Non-writable <code>CCACHE_DIR</code> is now handled gracefully when <code>CCACHE_READONLY</code> is
+ set.
+</p>
+</li>
+<li>
+<p>
+Made failure to create files (typically due to bad directory permissions) in
+ the cache directory fatal. Previously, such failures were silently and
+ erroneously flagged as "compiler produced stdout".
+</p>
+</li>
+<li>
+<p>
+Both the <code>-specs=file</code> and <code>--specs=file</code> forms are now recognized.
+</p>
+</li>
+<li>
+<p>
+Added recognition and hashing of GCC plugins specified with <code>-fplugin=file</code>.
+</p>
+</li>
+<li>
+<p>
+<code>CCACHE_COMPILERCHECK</code> now also determines how to hash explicit specs files
+ (<code>-specs=file</code>).
+</p>
+</li>
+<li>
+<p>
+Added <code>CPATH</code>, <code>C_INCLUDE_PATH</code> and similar environment variables to the hash
+ to avoid false cache hits when such variables have changed.
+</p>
+</li>
+<li>
+<p>
+Corrected log message when unify mode is enabled.
+</p>
+</li>
+<li>
+<p>
+Reverted the GCC bug compatibility introduced in ccache 3.1.5 for <code>-MT</code>/<code>-MQ</code>
+ options with concatenated arguments. (The bug is fixed in recent GCC
+ versions.)
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_other_3">Other</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Corrected license header for <code>mdfour.c</code>.
+</p>
+</li>
+<li>
+<p>
+Improved documentation on how to fix bad object files in the cache.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_6">ccache 3.1.6</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2011-08-21</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_9">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Rewrite argument to <code>--sysroot</code> if <code>CCACHE_BASEDIR</code> is used.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_22">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Don&#8217;t crash if <code>getcwd()</code> fails.
+</p>
+</li>
+<li>
+<p>
+Fixed alignment of &#8220;called for preprocessing&#8221; counter.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_5">ccache 3.1.5</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2011-05-29</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_10">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Added a new statistics counter named &#8220;called for preprocessing&#8221;.
+</p>
+</li>
+<li>
+<p>
+The original command line is now logged to the file specified with
+ <code>CCACHE_LOGFILE</code>.
+</p>
+</li>
+<li>
+<p>
+Improved error logging when system calls fail.
+</p>
+</li>
+<li>
+<p>
+Added support for rewriting absolute paths in <code>-F</code>/<code>-iframework</code> GCC
+ options.
+</p>
+</li>
+<li>
+<p>
+Improved order of statistics counters in <code>ccache -s</code> output.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_23">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+The <code>-MF</code>/<code>-MT</code>/<code>-MQ</code> options with concatenated argument are now handled
+ correctly when they are last on the command line.
+</p>
+</li>
+<li>
+<p>
+ccache is now bug compatible with GCC for the <code>-MT</code>/<code>-MQ</code> options with
+ concatenated arguments.
+</p>
+</li>
+<li>
+<p>
+Fixed a minor memory leak.
+</p>
+</li>
+<li>
+<p>
+Systems that lack (and don&#8217;t need to be linked with) libm are now supported.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_4">ccache 3.1.4</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2011-01-09</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_24">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Made a work-around for a bug in <code>gzputc()</code> in zlib 1.2.5.
+</p>
+</li>
+<li>
+<p>
+Corrupt manifest files are now removed so that they won&#8217;t block direct mode
+ hits.
+</p>
+</li>
+<li>
+<p>
+ccache now copes with file systems that don&#8217;t know about symbolic links.
+</p>
+</li>
+<li>
+<p>
+The file handle in now correctly closed on write error when trying to create
+ a cache dir tag.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_3">ccache 3.1.3</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2010-11-28</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_25">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+The -MFarg, -MTarg and -MQarg compiler options (i.e, without space between
+ option and argument) are now handled correctly.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_other_4">Other</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Portability fixes for HP-UX 11.00 and other esoteric systems.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_2">ccache 3.1.2</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2010-11-21</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_26">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Bail out on too hard compiler options <code>-fdump-*</code>.
+</p>
+</li>
+<li>
+<p>
+NULL return values from malloc/calloc of zero bytes are now handled
+ correctly.
+</p>
+</li>
+<li>
+<p>
+Fixed issue when parsing precompiler output on AIX.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_other_5">Other</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Improved documentation on which information is included in the hash sum.
+</p>
+</li>
+<li>
+<p>
+Made the &#8220;too new header file&#8221; test case work on file systems with
+ unsynchronized clocks.
+</p>
+</li>
+<li>
+<p>
+The test suite now also works on systems that lack a /dev/zero.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1_1">ccache 3.1.1</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2010-11-07</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_27">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+ccache now falls back to preprocessor mode when a non-regular include file
+ (device, socket, etc) has been detected so that potential hanging due to
+ blocking reads is avoided.
+</p>
+</li>
+<li>
+<p>
+CRC errors are now detected when decompressing compressed files in the cache.
+</p>
+</li>
+<li>
+<p>
+Fixed potential object file corruption race on NFS.
+</p>
+</li>
+<li>
+<p>
+Minor documentation corrections.
+</p>
+</li>
+<li>
+<p>
+Fixed configure detection of ar.
+</p>
+</li>
+<li>
+<p>
+ccache development version (set by dev.mk) now works with gits whose
+ <code>describe</code> command doesn&#8217;t understand <code>--dirty</code>.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_other_6">Other</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Minor debug log message improvements.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_1">ccache 3.1</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2010-09-16</p></div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_11">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Added support for hashing the output of a custom command (e.g. <code>%compiler%
+ --version</code>) to identify the compiler instead of stat-ing or hashing the
+ compiler binary. This can improve robustness when the compiler (as seen by
+ ccache) actually isn&#8217;t the real compiler but another compiler wrapper.
+</p>
+</li>
+<li>
+<p>
+Added support for caching compilations that use precompiled headers. (See the
+ manual for important instructions regarding this.)
+</p>
+</li>
+<li>
+<p>
+Locking of the files containing statistics counters is now done using
+ symlinks instead of POSIX locks. This should make ccache behave a lot better
+ on file systems where POSIX locks are slow or broken (e.g. NFS on some
+ systems).
+</p>
+</li>
+<li>
+<p>
+Manifest files are now updated without the need of taking locks.
+</p>
+</li>
+<li>
+<p>
+Updates of statistics counters are now always done in one of the sub-level
+ statistics files. This reduces lock contention, which especially improves
+ performance on slow NFS mounts.
+</p>
+</li>
+<li>
+<p>
+Reading and writing of statistics counters has been made forward-compatible
+ (unknown counters are retained).
+</p>
+</li>
+<li>
+<p>
+Files are now read without using <code>mmap()</code>. This has two benefits: it&#8217;s more
+ robust against file changes during reading and it improves performance on
+ poor systems where <code>mmap()</code> doesn&#8217;t use the disk cache.
+</p>
+</li>
+<li>
+<p>
+Added <code>.cp</code> and <code>.CP</code> as known C++ suffixes.
+</p>
+</li>
+<li>
+<p>
+Improved logging.
+</p>
+</li>
+<li>
+<p>
+Added <code>-install_name</code> as an option known to take an argument. (This improves
+ statistics when using the Darwin linker.)
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_28">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Non-fatal error messages are now never printed to stderr but logged instead.
+</p>
+</li>
+<li>
+<p>
+Fixed a bug affecting failing commands when <code>--ccache-skip</code> is used.
+</p>
+</li>
+<li>
+<p>
+Made <code>--ccache-skip</code> work for all options.
+</p>
+</li>
+<li>
+<p>
+EINTR is now handled correctly.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_other_7">Other</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Work on porting ccache to win32 (native), mostly done by Ramiro Polla. The
+ port is not yet finished, but will hopefully be complete in some subsequent
+ release.
+</p>
+</li>
+<li>
+<p>
+Added a <code>--nostats</code> flag to the performance benchmark program.
+</p>
+</li>
+<li>
+<p>
+Made the performance benchmark program more accurate when measuring cache
+ hits.
+</p>
+</li>
+<li>
+<p>
+Added a new test framework for unit tests written in C.
+</p>
+</li>
+<li>
+<p>
+Got rid of <code>configure-dev</code>; dev mode is now given by <code>dev.mk.in</code> presence.
+</p>
+</li>
+<li>
+<p>
+Improved documentation on how to combine ccache with other compiler wrappers
+ (like <code>distcc</code>).
+</p>
+</li>
+<li>
+<p>
+New <code>LICENSE.txt</code> file with licensing and copyright details about bundled
+ source code.
+</p>
+</li>
+<li>
+<p>
+New <code>AUTHORS.txt</code> file with a list of ccache contributors.
+</p>
+</li>
+<li>
+<p>
+New <code>HACKING.txt</code> file with some notes about ccache code conventions.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_0_1">ccache 3.0.1</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2010-07-15</p></div>
+<div class="sect2">
+<h3 id="_bug_fixes_29">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+The statistics counter &#8220;called for link&#8221; is now correctly updated when
+ linking with a single object file.
+</p>
+</li>
+<li>
+<p>
+Fixed a problem with out-of-source builds.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ccache_3_0">ccache 3.0</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Release date: 2010-06-20</p></div>
+<div class="sect2">
+<h3 id="_general">General</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+ccache is now licensed under the GNU General Public License (GPL) version 3
+ or later.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_upgrade_notes">Upgrade notes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+The way the hashes are calculated has changed, so you won&#8217;t get cache hits
+ for compilation results stored by older ccache versions. Because of this, you
+ might as well clear the old cache directory with <code>ccache --clear</code> if you
+ want, unless you plan to keep using an older ccache version.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_new_features_and_improvements_12">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+ccache now has a &#8220;direct mode&#8221; where it computes a hash of the source code
+ (including all included files) and compiler options without running the
+ preprocessor. By not running the preprocessor, CPU usage is reduced; the
+ speed is somewhere between 1 and 5 times that of ccache running in
+ traditional mode, depending on the circumstances. The speedup will be higher
+ when I/O is fast (e.g., when files are in the disk cache). The direct mode
+ can be disabled by setting <code>CCACHE_NODIRECT</code>.
+</p>
+</li>
+<li>
+<p>
+Support has been added for rewriting absolute paths to relative paths when
+ hashing, in order to increase cache hit rate when building the same source
+ code in different directories even when compiling with <code>-g</code> and when using
+ absolute include directory paths. This is done by setting the
+ <code>CCACHE_BASEDIR</code> environment variable to an absolute path that specifies
+ which paths to rewrite.
+</p>
+</li>
+<li>
+<p>
+Object files are now optionally stored compressed in the cache. The runtime
+ cost is negligible, and more files will fit in the ccache directory and in
+ the disk cache. Set <code>CCACHE_COMPRESS</code> to enable object file compression. Note
+ that you can&#8217;t use compression in combination with the hard link feature.
+</p>
+</li>
+<li>
+<p>
+A <code>CCACHE_COMPILERCHECK</code> option has been added. This option tells ccache what
+ compiler-identifying information to hash to ensure that results retrieved
+ from the cache are accurate. Possible values are: none (don&#8217;t hash anything),
+ mtime (hash the compiler&#8217;s mtime and size) and content (hash the content of
+ the compiler binary). The default is mtime.
+</p>
+</li>
+<li>
+<p>
+It is now possible to specify extra files whose contents should be included
+ in the hash sum by setting the <code>CCACHE_EXTRAFILES</code> option.
+</p>
+</li>
+<li>
+<p>
+Added support for Objective-C and Objective-C++. The statistics counter
+ &#8220;not a C/C++ file&#8221; has been renamed to &#8220;unsupported source language&#8221;.
+</p>
+</li>
+<li>
+<p>
+Added support for the <code>-x</code> compiler option.
+</p>
+</li>
+<li>
+<p>
+Added support for long command-line options.
+</p>
+</li>
+<li>
+<p>
+A <code>CACHEDIR.TAG</code> file is now created in the cache directory. See
+ <a href="http://www.brynosaurus.com/cachedir/">http://www.brynosaurus.com/cachedir/</a>.
+</p>
+</li>
+<li>
+<p>
+Messages printed to the debug log (specified by <code>CCACHE_LOGFILE</code>) have been
+ improved.
+</p>
+</li>
+<li>
+<p>
+You can relax some checks that ccache does in direct mode by setting
+ <code>CCACHE_SLOPPINESS</code>. See the manual for more information.
+</p>
+</li>
+<li>
+<p>
+<code>CCACHE_TEMPDIR</code> no longer needs to be on the same filesystem as
+ <code>CCACHE_DIR</code>.
+</p>
+</li>
+<li>
+<p>
+The default value of <code>CCACHE_TEMPDIR</code> has been changed to <code>$CCACHE_DIR/tmp</code>
+ to avoid cluttering the top directory.
+</p>
+</li>
+<li>
+<p>
+Temporary files that later will be moved into the cache are now created in
+ the cache directory they will end up in. This makes ccache more friendly to
+ Linux&#8217;s directory layout.
+</p>
+</li>
+<li>
+<p>
+Improved the test suite and added tests for most of the new functionality.
+ It&#8217;s now also possible to specify a subset of tests to run.
+</p>
+</li>
+<li>
+<p>
+Standard error output from the compiler is now only stored in the cache if
+ it&#8217;s non-empty.
+</p>
+</li>
+<li>
+<p>
+If the compiler produces no object file or an empty object file, but gives a
+ zero exit status (could be due to a file system problem, a buggy program
+ specified by <code>CCACHE_PREFIX</code>, etc.), ccache copes with it properly.
+</p>
+</li>
+<li>
+<p>
+Added <code>installcheck</code> and <code>distcheck</code> make targets.
+</p>
+</li>
+<li>
+<p>
+Clarified cache size limit options' and cleanup semantics.
+</p>
+</li>
+<li>
+<p>
+Improved display of cache max size values.
+</p>
+</li>
+<li>
+<p>
+The following options are no longer hashed in the preprocessor mode:
+ <code>-imacros</code>, <code>-imultilib</code>, <code>-iprefix</code>, <code>-iquote</code>, <code>-isysroot</code>, <code>-iwithprefix</code>,
+ <code>-iwithprefixbefore</code>, <code>-nostdinc</code>, <code>-nostdinc++</code> and <code>-U</code>.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_30">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Various portability improvements.
+</p>
+</li>
+<li>
+<p>
+Improved detection of home directory.
+</p>
+</li>
+<li>
+<p>
+User-defined <code>CPPFLAGS</code> and <code>LDFLAGS</code> are now respected in the Makefile.
+</p>
+</li>
+<li>
+<p>
+Fixed NFS issues.
+</p>
+</li>
+<li>
+<p>
+Computation of the hash sum has been improved to decrease the risk of hash
+ collisions. For instance, the compiler options <code>-X -Y</code> and <code>-X-Y</code> previously
+ contributed equally to the hash sum.
+</p>
+</li>
+<li>
+<p>
+Bail out on too hard compiler options <code>--coverage</code>, <code>-fprofile-arcs</code>,
+ <code>-fprofile-generate</code>, <code>-fprofile-use</code>, <code>-frepo</code>, <code>-ftest-coverage</code> and
+ <code>-save-temps</code>. Also bail out on <code>@file</code> style options.
+</p>
+</li>
+<li>
+<p>
+Errors when using multiple <code>-arch</code> compiler options are now noted as
+ &#8220;unsupported compiler option&#8221;.
+</p>
+</li>
+<li>
+<p>
+<code>-MD</code>/<code>-MMD</code> options without <code>-MT</code>/<code>-MF</code> are now handled correctly.
+</p>
+</li>
+<li>
+<p>
+The <code>-finput-charset</code> option is now handled correctly.
+</p>
+</li>
+<li>
+<p>
+Added support for <code>-Wp,-MD</code> and <code>-Wp,-MMD</code> options.
+</p>
+</li>
+<li>
+<p>
+The compiler options <code>-Xassembler</code>, <code>-b</code>, <code>-G</code> and <code>-V</code> are now correctly
+ recognized as taking an argument.
+</p>
+</li>
+<li>
+<p>
+Debug information containing line numbers of predefined and command-line
+ macros (enabled with the compiler option <code>-g3</code>) will now be correct.
+</p>
+</li>
+<li>
+<p>
+Corrected LRU cleanup handling of object files.
+</p>
+</li>
+<li>
+<p>
+<code>utimes()</code> is now used instead of <code>utime()</code> when available.
+</p>
+</li>
+<li>
+<p>
+Non-writable cache directories are now handled gracefully.
+</p>
+</li>
+<li>
+<p>
+Corrected documentation about sharing the cache directory.
+</p>
+</li>
+<li>
+<p>
+Fixed compilation warnings from GCC 4.3.
+</p>
+</li>
+<li>
+<p>
+The command specified by <code>CCACHE_PREFIX</code> is no longer part of the hash.
+</p>
+</li>
+<li>
+<p>
+Fixed bad memory access spotted by Valgrind.
+</p>
+</li>
+<li>
+<p>
+Fixed a bug in <code>x_realloc</code>.
+</p>
+</li>
+<li>
+<p>
+Freed memory is no longer referenced when compiling a <code>.i</code>/<code>.ii</code> file and
+ falling back to running the real compiler.
+</p>
+</li>
+<li>
+<p>
+The test suite is now immune to external values of the <code>CCACHE_*</code> environment
+ variables.
+</p>
+</li>
+<li>
+<p>
+Improved detection of recursive invocation.
+</p>
+</li>
+<li>
+<p>
+The ccache binary is now not unconditionally stripped when installing.
+</p>
+</li>
+<li>
+<p>
+Statistics counters are now correctly updated for -E option failures and
+ internal errors.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Version 3.3.4<br />
+Last updated
+ 2017-02-17 22:28:35 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/NEWS.txt b/NEWS.txt
new file mode 100644
index 0000000..e15f18c
--- /dev/null
+++ b/NEWS.txt
@@ -0,0 +1,1092 @@
+ccache news
+===========
+
+ccache 3.3.4
+------------
+Release date: 2017-02-17
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Documented the different cache statistics counters.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed a regression in ccache 3.3 related to potentially bad content of
+ dependency files when compiling identical source code but with different
+ source paths. This was only partially fixed in 3.3.2 and reverts the new
+ ``Names of included files are no longer included in the hash of the
+ compiler's preprocessed output'' feature in 3.3.
+
+- Corrected statistics counter for `-optf`/`--options-file` failure.
+
+- Fixed undefined behavior warnings in ccache found by `-fsanitize=undefined`.
+
+
+ccache 3.3.3
+------------
+Release date: 2016-10-26
+
+Bug fixes
+~~~~~~~~~
+
+- ccache now detects usage of `.incbin` assembler directives in the source code
+ and avoids caching such compilations.
+
+
+ccache 3.3.2
+------------
+Release date: 2016-09-28
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed a regression in ccache 3.3 related to potentially bad content of
+ dependency files when compiling identical source code but with different
+ source paths.
+
+- Fixed a regression in ccache 3.3.1: ccache could get confused when using the
+ compiler option `-Wp,` to pass multiple options to the preprocessor,
+ resulting in missing dependency files from direct mode cache hits.
+
+
+ccache 3.3.1
+------------
+Release date: 2016-09-07
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed a problem in the ``multiple `-arch` options'' support introduced in
+ 3.3. When using the direct mode (the default), different combinations of
+ `-arch` options were not detected properly.
+
+- Fixed an issue when compiler option `-Wp,-MT,path` is used instead of `-MT
+ path` (and similar for `-MF`, `-MP` and `-MQ`) and `run_second_cpp`
+ (`CCACHE_CPP2`) is enabled.
+
+
+ccache 3.3
+----------
+Release date: 2016-08-27
+
+Notes
+~~~~~
+
+- A C99-compatible compiler is now required to build ccache.
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- The configuration option `run_second_cpp` (`CCACHE_CPP2`) now defaults to
+ true. This improves ccache's out-of-the-box experience for compilers that
+ can't compile their own preprocessed output with the same outcome as if they
+ compiled the real source code directly, e.g. newer versions of GCC and Clang.
+
+- The configuration option `hash_dir` (`CCACHE_HASHDIR`) now defaults to true.
+
+- Added a new `ignore_headers_in_manifest` configuration option, which
+ specifies headers that should be ignored in the direct mode.
+
+- Added a new `prefix_command_cpp` (`CCACHE_PREFIX_CPP`) configuration option,
+ which specifies one or several prefixes to add to the command line ccache
+ uses when invoking the preprocessor.
+
+- Added a new `limit_multiple` (`CCACHE_LIMIT_MULTIPLE`) configuration option,
+ which specifies how much of the cache to remove when cleaning.
+
+- Added a new `keep_comments_cpp` (`CCACHE_COMMENTS`) configuration option,
+ which tells ccache not to discard the comments before hashing preprocessor
+ output. This can be used to check documentation with *-Wdocumentation*.
+
+- Added a new sloppiness option `no_system_headers`, which tells ccache not to
+ include system headers in manifest files.
+
+- Added a new statistics counter that tracks the number of performed cleanups
+ due to the cache size being over the limit. The value is shown in the output
+ of ``ccache -s''.
+
+- Added support for relocating debug info directory using `-fdebug-prefix-map`.
+ This allows for cache hits even when `hash_dir` is used in combination with
+ `base_dir`.
+
+- Added a new ``cache hit rate'' field to the output of ``ccache -s''.
+
+- Added support for caching compilation of assembler code produced by e.g.
+ ``gcc -S file.c''.
+
+- Added support for cuda including the -optf/--options-file option.
+
+- Added support for Fortran 77.
+
+- Added support for multiple `-arch` options to produce "fat binaries".
+
+- Multiple identical `-arch` arguments are now handled without bailing.
+
+- The concatenated form of some long compiler options is now recognized, for
+ example when using `-isystemPATH` instead of `-isystem PATH`.
+
+- If hard-linking is enabled and but fails (e.g. due to cross-device linking),
+ ccache now falls back to copying instead of running the compiler.
+
+- Made the `hash_dir` option only have effect when generating debug info.
+
+- ccache now knows how to convert absolute paths to relative paths inside
+ dependency files when using `base_dir`.
+
+- Improved parsing of `-g*` options.
+
+- Made ccache understand `-Wp,-D*` options.
+
+- ccache now understands the undocumented `-coverage` (only one dash) GCC
+ option.
+
+- Names of included files are no longer included in the hash of the compiler's
+ preprocessed output. This leads to more potential cache hits when not using
+ the direct mode.
+
+- Increased buffer size used when reading file data. This improves performance
+ slightly.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Bail out on too hard compiler option `-P`.
+
+- Fixed clang test suite when running on Linux.
+
+- Fixed build and test for MinGW32 and Windows.
+
+
+ccache 3.2.9
+------------
+Release date: 2016-09-28
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed a regression in ccache 3.2.8: ccache could get confused when using the
+ compiler option `-Wp,` to pass multiple options to the preprocessor,
+ resulting in missing dependency files from direct mode cache hits.
+
+
+ccache 3.2.8
+------------
+Release date: 2016-09-07
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed an issue when compiler option `-Wp,-MT,path` is used instead of `-MT
+ path` (and similar for `-MF`, `-MP` and `-MQ`) and `run_second_cpp`
+ (`CCACHE_CPP2`) is enabled.
+
+- ccache now understands the undocumented `-coverage` (only one dash) GCC
+ option.
+
+
+ccache 3.2.7
+------------
+Release date: 2016-07-20
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed a bug which could lead to false cache hits for compiler command lines
+ with a missing argument to an option that takes an argument.
+
+- ccache now knows how to work around a glitch in the output of GCC 6's
+ preprocessor.
+
+
+ccache 3.2.6
+------------
+Release date: 2016-07-12
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed build problem on QNX, which lacks ``SA_RESTART''.
+
+- Bail out on compiler option `-fstack-usage` since it creates a `.su` file
+ which ccache currently doesn't handle.
+
+- Fixed a bug where (due to ccache rewriting paths) the compiler could choose
+ incorrect include files if `CCACHE_BASEDIR` is used and the source file path
+ is absolute and is a symlink.
+
+
+ccache 3.2.5
+------------
+Release date: 2016-04-17
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Only pass clang-specific `-stdlib=` to the preprocessor.
+
+- Improved handling of stale NFS handles.
+
+- Made it harder to misinterpret documentation of boolean environment settings'
+ semantics.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Include m4 files used by configure.ac in the source dist archives.
+
+- Corrected "Performance" section in the manual regarding `__DATE_`, `__TIME__`
+ and `__FILE__` macros.
+
+- Fixed build on Solaris 10+ and AIX 7.
+
+- Fixed failure to create directories on QNX.
+
+- Don't (try to) update manifest file in ``read-only'' and ``read-only direct''
+ modes.
+
+- Fixed a bug in caching of `stat` system calls in ``file_stat_matches
+ sloppiness mode''.
+
+- Fixed bug in hashing of clang plugins, leading to unnecessary cache misses.
+
+- Fixed --print-config to show ``pch_defines sloppiness''.
+
+- The man page is now built when running ``make install'' from Git repository
+ sources.
+
+
+ccache 3.2.4
+------------
+Release date: 2015-10-08
+
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed build error related to zlib on systems with older make versions
+ (regression in ccache 3.2.3).
+
+- Made conversion-to-bool explicit to avoid build warnings (and potential
+ runtime errors) on legacy systems.
+
+- Improved signal handling: Kill compiler on SIGTERM; wait for compiler to exit
+ before exiting; die appropriately.
+
+- Minor fixes related to Windows support.
+
+- The correct compression level is now used if compression is requested.
+
+- Fixed a bug where cache cleanup could be run too early for caches larger than
+ 64 GiB on 32-bit systems.
+
+
+ccache 3.2.3
+------------
+Release date: 2015-08-16
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Added support for compiler option `-gsplit-dwarf`.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Support external zlib in nonstandard directory.
+
+- Avoid calling `exit()` inside an exit handler.
+
+- Let exit handler terminate properly.
+
+- Bail out on compiler option `--save-temps` in addition to `-save-temps`.
+
+- Only log "Disabling direct mode" once when failing to read potential include
+ files.
+
+
+ccache 3.2.2
+------------
+Release date: 2015-05-10
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Added support for `CCACHE_COMPILERCHECK=string:<value>`. This is a faster
+ alternative to `CCACHE_COMPILERCHECK=<command>` if the command's output can
+ be precalculated by the build system.
+
+- Add support for caching code coverage results (compiling for gcov).
+
+
+Bug fixes
+~~~~~~~~~
+
+- Made hash of cached result created with and without `CCACHE_CPP2` different.
+ This makes it possible to rebuild with `CCACHE_CPP2` set without having to
+ clear the cache to get new results.
+
+- Don't try to reset a non-existing stats file. This avoids ``No such file or
+ directory'' messages in the ccache log when the cache directory doesn't
+ exist.
+
+- Fixed a bug where ccache deleted clang diagnostics after compiler failures.
+
+- Avoid performing an unnecessary copy of the object file on a cache miss.
+
+- Bail out on too hard compiler option `-fmodules`.
+
+- Bail out on too hard compiler option `-fplugin=libcc1plugin` (interaction
+ with GDB).
+
+- Fixed build error when compiling ccache with recent clang versions.
+
+- Removed signal-unsafe code from signal handler.
+
+- Corrected logic for when to output cached stderr.
+
+- Wipe the whole cached result on failure retrieving a cached file.
+
+- Fixed build error when compiling ccache with recent clang versions.
+
+
+ccache 3.2.1
+------------
+Release date: 2014-12-10
+
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed regression in temporary file handling, which lead to incorrect
+ permissions for stats, manifest and ccache.conf files in the cache.
+
+- `CACHEDIR.TAG` files are now created in the [0-9a-f] subdirectories so that
+ ccache.conf is not lost in backups.
+
+- Made the default cache size suffix `G`, as previously documented.
+
+- `-fdiagnostics-color=auto` is now passed to the compiler even if stderr is
+ redirected. This fixes a problem when, for instance, a configure test probes
+ if the compiler (wrapped via ccache) supports `-fdiagnostics-color=auto`.
+
+- Added missing documentation for `max_files` and `max_size` configuration
+ options.
+
+
+ccache 3.2
+----------
+Release date: 2014-11-17
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Added support for configuring ccache via one or several configuration files
+ instead of via environment variables. Environment variables still have
+ priority but are no longer the recommended way of customizing ccache
+ behavior. See the manual for more information.
+
+- Added support for compiler error/warning messages with color.
+
+- Made creation of temporary directories and cache directories smarter to avoid
+ unnecessary `stat` calls.
+
+- Improved efficiency of the algorithm that scans for `__DATE_` and `__TIME__`
+ tokens in the hashed source code.
+
+- Added support for several binaries (separated by space) in `CCACHE_PREFIX`.
+
+- The `-c` option is no longer passed to the preprocessor. This fixes problems
+ with clang and Solaris's C++ compiler.
+
+- ccache no longer passes preprocessor options like `-D` and `-I` to the
+ compiler when compiling preprocessed output. This fixes warnings emitted by
+ clang.
+
+- Compiler options `-fprofile-generate`, `-fprofile-arcs`, `-fprofile-use` and
+ `-fbranch-probabilities` are now handled without bailing.
+
+- Added support for clang's `--serialize-diagnostic` option, storing the
+ diagnostic file (`.dia`) in the cache.
+
+- Added support for precompiled headers when using clang.
+
+- Added support for clang `.pth` (pretokenized header) files.
+
+- Changed the `-x` language option to use the new objective C standard for GCC
+ and clang.
+
+- On a cache miss, ccache now instructs the compiler to create the object file
+ at the real destination and then copies the file into the cache instead of
+ the other way around. This is needed to support compiler options like
+ `-fprofile-arcs` and `--serialize-diagnostics`.
+
+- ccache now checks that included files' ctimes aren't too new. This check can
+ be turned off by adding `include_file_ctime` to the ``ccache sloppiness''
+ setting.
+
+- Added possibility to get cache hits based on filename, size, mtime and ctime
+ only. On other words, source code files are not even read, only stat-ed. This
+ operation mode is opt-in by adding `file_stat_matches` to the ``ccache
+ sloppiness'' setting.
+
+- The filename part of options like `-Wp,-MDfilename` is no longer included in
+ the hash since the filename doesn't have any bearing on the result.
+
+- Added a ``read-only direct'' configuration setting, which is like the
+ ordinary read-only setting except that ccache will only try to retrieve
+ results from the cache using the direct mode, not the preprocessor mode.
+
+- The display and interpretation of cache size has been changed to use SI
+ units.
+
+- Default cache size is now 5 GB (was previously 1 GiB).
+
+- Added configuration option to set the compression level of compressed object
+ files in the cache.
+
+- Added support for `@file` and `-@file` arguments (reading options from a
+ file).
+
+- `-Wl,` options are no longer included in the hash since they don't affect
+ compilation.
+
+- Bail out on too hard compiler option `-Wp,-P`.
+
+- Optimized MD4 calculation code on little-endian systems.
+
+- Various improvements and fixes on win32.
+
+- Improved logging to the ccache log file.
+
+- Added `--dump-manifest` command-line option for debugging purposes.
+
+- Added `--with-bundled-zlib` configure option.
+
+- Upgraded bundled zlib to version 1.2.8.
+
+- Improved `dev.mk` to be more platform independent.
+
+- Made the test suite work with clang and gcc-llvm on OS X.
+
+- Various other improvements of the test suite.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Any previous `.stderr` is now removed from the cache when recaching.
+
+- Fixed an issue when handling the `-arch` compiler option with an argument.
+
+- Fixed race condition when creating the initial cache directory.
+
+- Fixed test suite failures when `CC` is a ccache-wrapped compiler.
+
+
+ccache 3.1.12
+-------------
+Release date: 2016-07-12
+
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed a bug where (due to ccache rewriting paths) the compiler could choose
+ incorrect include files if `CCACHE_BASEDIR` is used and the source file path
+ is absolute and is a symlink.
+
+
+ccache 3.1.11
+-------------
+Release date: 2015-03-07
+
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed bug which could result in false cache hits when source code contains
+ `'"'` followed by `" /*"` or `" //"` (with variations).
+
+- Made hash of cached result created with and without `CCACHE_CPP2` different.
+ This makes it possible to rebuild with `CCACHE_CPP2` set without having to
+ clear the cache to get new results.
+
+- Don't try to reset a non-existing stats file. This avoids ``No such file or
+ directory'' messages in the ccache log when the cache directory doesn't
+ exist.
+
+
+ccache 3.1.10
+-------------
+Release date: 2014-10-19
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Added support for the `-Xclang` compiler option.
+
+- Improved handling of exit code of internally executed processes.
+
+- Zero length object files in the cache are now rejected as invalid.
+
+- Bail out on option `-gsplit-dwarf` (since it produces multiple output files).
+
+- Compiler option `-fdebug-prefix-map` is now ignored (not part of the hash).
+ (The `-fdebug-prefix-map` option may be used in combination with
+ `CCACHE_BASEDIR` to reuse results across different directories.)
+
+- Added note in documentation that `--ccache-skip` currently does not mean
+ ``don't hash the following option''.
+
+- To enable support for precompiled headers (PCH), `CCACHE_SLOPPINESS` now also
+ needs to include the new `pch_defines` sloppiness. This is because ccache
+ can't detect changes in the source code when only defined macros have been
+ changed.
+
+- Stale files in the internal temporary directory (`<ccache_dir>/tmp`) are now
+ cleaned up if they are older than one hour.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed path canonicalization in `make_relative_path()` when path doesn't
+ exist.
+
+- Fixed bug in `common_dir_prefix_length()`. This corrects the `CCACHE_BASEDIR`
+ behavior.
+
+- ccache no longer tries to create the cache directory when `CCACHE_DISABLE` is
+ set.
+
+- Fixed bug when reading manifests with a very large number of file info
+ entries.
+
+- Fixed problem with logging of current working directory.
+
+
+ccache 3.1.9
+------------
+Release date: 2013-01-06
+
+
+Bug fixes
+~~~~~~~~~
+
+- The EAGAIN signal is now handled correctly when emitting cached stderr
+ output. This fixes a problem triggered by large error outputs from the
+ compiler.
+
+- Subdirectories in the cache are no longer created in read-only mode.
+
+- Fixed so that ccache's log file descriptor is not made available to the
+ compiler.
+
+- Improved error reporting when failing to create temporary stdout/stderr files
+ when executing the compiler.
+
+- Disappearing temporary stdout/stderr files are now handled gracefully.
+
+
+Other
+~~~~~
+
+- Fixed test suite to work on ecryptfs.
+
+
+ccache 3.1.8
+------------
+Release date: 2012-08-11
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Made paths to dependency files relative in order to increase cache hits.
+
+- Added work-around to make ccache work with buggy GCC 4.1 when creating a
+ pre-compiled header.
+
+- Clang plugins are now hashed to catch plugin upgrades.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Fixed crash when the current working directory has been removed.
+
+- Fixed crash when stderr is closed.
+
+- Corrected a corner case when parsing backslash escapes in string
+ literals.
+
+- Paths are now correctly canonicalized when computing paths relative to the
+ base directory.
+
+
+Other
+~~~~~
+
+- Made git version macro work when compiling outside of the source directory.
+
+- Fixed `static_assert` macro definition clash with GCC 4.7.
+
+
+ccache 3.1.7
+------------
+Release date: 2012-01-08
+
+
+Bug fixes
+~~~~~~~~~
+
+- Non-writable `CCACHE_DIR` is now handled gracefully when `CCACHE_READONLY` is
+ set.
+
+- Made failure to create files (typically due to bad directory permissions) in
+ the cache directory fatal. Previously, such failures were silently and
+ erroneously flagged as "compiler produced stdout".
+
+- Both the `-specs=file` and `--specs=file` forms are now recognized.
+
+- Added recognition and hashing of GCC plugins specified with `-fplugin=file`.
+
+- `CCACHE_COMPILERCHECK` now also determines how to hash explicit specs files
+ (`-specs=file`).
+
+- Added `CPATH`, `C_INCLUDE_PATH` and similar environment variables to the hash
+ to avoid false cache hits when such variables have changed.
+
+- Corrected log message when unify mode is enabled.
+
+- Reverted the GCC bug compatibility introduced in ccache 3.1.5 for `-MT`/`-MQ`
+ options with concatenated arguments. (The bug is fixed in recent GCC
+ versions.)
+
+
+Other
+~~~~~
+
+- Corrected license header for `mdfour.c`.
+
+- Improved documentation on how to fix bad object files in the cache.
+
+
+
+ccache 3.1.6
+------------
+Release date: 2011-08-21
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Rewrite argument to `--sysroot` if `CCACHE_BASEDIR` is used.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Don't crash if `getcwd()` fails.
+
+- Fixed alignment of ``called for preprocessing'' counter.
+
+
+ccache 3.1.5
+------------
+Release date: 2011-05-29
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Added a new statistics counter named ``called for preprocessing''.
+
+- The original command line is now logged to the file specified with
+ `CCACHE_LOGFILE`.
+
+- Improved error logging when system calls fail.
+
+- Added support for rewriting absolute paths in `-F`/`-iframework` GCC
+ options.
+
+- Improved order of statistics counters in `ccache -s` output.
+
+
+Bug fixes
+~~~~~~~~~
+
+- The `-MF`/`-MT`/`-MQ` options with concatenated argument are now handled
+ correctly when they are last on the command line.
+
+- ccache is now bug compatible with GCC for the `-MT`/`-MQ` options with
+ concatenated arguments.
+
+- Fixed a minor memory leak.
+
+- Systems that lack (and don't need to be linked with) libm are now supported.
+
+
+ccache 3.1.4
+------------
+Release date: 2011-01-09
+
+
+Bug fixes
+~~~~~~~~~
+
+- Made a work-around for a bug in `gzputc()` in zlib 1.2.5.
+
+- Corrupt manifest files are now removed so that they won't block direct mode
+ hits.
+
+- ccache now copes with file systems that don't know about symbolic links.
+
+- The file handle in now correctly closed on write error when trying to create
+ a cache dir tag.
+
+
+ccache 3.1.3
+------------
+Release date: 2010-11-28
+
+
+Bug fixes
+~~~~~~~~~
+
+- The -MFarg, -MTarg and -MQarg compiler options (i.e, without space between
+ option and argument) are now handled correctly.
+
+
+Other
+~~~~~
+
+- Portability fixes for HP-UX 11.00 and other esoteric systems.
+
+
+ccache 3.1.2
+------------
+Release date: 2010-11-21
+
+
+Bug fixes
+~~~~~~~~~
+
+- Bail out on too hard compiler options `-fdump-*`.
+
+- NULL return values from malloc/calloc of zero bytes are now handled
+ correctly.
+
+- Fixed issue when parsing precompiler output on AIX.
+
+
+Other
+~~~~~
+
+- Improved documentation on which information is included in the hash sum.
+
+- Made the ``too new header file'' test case work on file systems with
+ unsynchronized clocks.
+
+- The test suite now also works on systems that lack a /dev/zero.
+
+
+ccache 3.1.1
+------------
+Release date: 2010-11-07
+
+
+Bug fixes
+~~~~~~~~~
+
+- ccache now falls back to preprocessor mode when a non-regular include file
+ (device, socket, etc) has been detected so that potential hanging due to
+ blocking reads is avoided.
+
+- CRC errors are now detected when decompressing compressed files in the cache.
+
+- Fixed potential object file corruption race on NFS.
+
+- Minor documentation corrections.
+
+- Fixed configure detection of ar.
+
+- ccache development version (set by dev.mk) now works with gits whose
+ `describe` command doesn't understand `--dirty`.
+
+
+Other
+~~~~~
+
+- Minor debug log message improvements.
+
+
+ccache 3.1
+----------
+Release date: 2010-09-16
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Added support for hashing the output of a custom command (e.g. `%compiler%
+ --version`) to identify the compiler instead of stat-ing or hashing the
+ compiler binary. This can improve robustness when the compiler (as seen by
+ ccache) actually isn't the real compiler but another compiler wrapper.
+
+- Added support for caching compilations that use precompiled headers. (See the
+ manual for important instructions regarding this.)
+
+- Locking of the files containing statistics counters is now done using
+ symlinks instead of POSIX locks. This should make ccache behave a lot better
+ on file systems where POSIX locks are slow or broken (e.g. NFS on some
+ systems).
+
+- Manifest files are now updated without the need of taking locks.
+
+- Updates of statistics counters are now always done in one of the sub-level
+ statistics files. This reduces lock contention, which especially improves
+ performance on slow NFS mounts.
+
+- Reading and writing of statistics counters has been made forward-compatible
+ (unknown counters are retained).
+
+- Files are now read without using `mmap()`. This has two benefits: it's more
+ robust against file changes during reading and it improves performance on
+ poor systems where `mmap()` doesn't use the disk cache.
+
+- Added `.cp` and `.CP` as known C++ suffixes.
+
+- Improved logging.
+
+- Added `-install_name` as an option known to take an argument. (This improves
+ statistics when using the Darwin linker.)
+
+
+Bug fixes
+~~~~~~~~~
+
+- Non-fatal error messages are now never printed to stderr but logged instead.
+
+- Fixed a bug affecting failing commands when `--ccache-skip` is used.
+
+- Made `--ccache-skip` work for all options.
+
+- EINTR is now handled correctly.
+
+
+Other
+~~~~~
+
+- Work on porting ccache to win32 (native), mostly done by Ramiro Polla. The
+ port is not yet finished, but will hopefully be complete in some subsequent
+ release.
+
+- Added a `--nostats` flag to the performance benchmark program.
+
+- Made the performance benchmark program more accurate when measuring cache
+ hits.
+
+- Added a new test framework for unit tests written in C.
+
+- Got rid of `configure-dev`; dev mode is now given by `dev.mk.in` presence.
+
+- Improved documentation on how to combine ccache with other compiler wrappers
+ (like `distcc`).
+
+- New `LICENSE.txt` file with licensing and copyright details about bundled
+ source code.
+
+- New `AUTHORS.txt` file with a list of ccache contributors.
+
+- New `HACKING.txt` file with some notes about ccache code conventions.
+
+
+ccache 3.0.1
+------------
+Release date: 2010-07-15
+
+
+Bug fixes
+~~~~~~~~~
+
+- The statistics counter ``called for link'' is now correctly updated when
+ linking with a single object file.
+
+- Fixed a problem with out-of-source builds.
+
+
+ccache 3.0
+----------
+Release date: 2010-06-20
+
+
+General
+~~~~~~~
+
+- ccache is now licensed under the GNU General Public License (GPL) version 3
+ or later.
+
+
+Upgrade notes
+~~~~~~~~~~~~~
+
+- The way the hashes are calculated has changed, so you won't get cache hits
+ for compilation results stored by older ccache versions. Because of this, you
+ might as well clear the old cache directory with `ccache --clear` if you
+ want, unless you plan to keep using an older ccache version.
+
+
+New features and improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ccache now has a ``direct mode'' where it computes a hash of the source code
+ (including all included files) and compiler options without running the
+ preprocessor. By not running the preprocessor, CPU usage is reduced; the
+ speed is somewhere between 1 and 5 times that of ccache running in
+ traditional mode, depending on the circumstances. The speedup will be higher
+ when I/O is fast (e.g., when files are in the disk cache). The direct mode
+ can be disabled by setting +CCACHE_NODIRECT+.
+
+- Support has been added for rewriting absolute paths to relative paths when
+ hashing, in order to increase cache hit rate when building the same source
+ code in different directories even when compiling with `-g` and when using
+ absolute include directory paths. This is done by setting the
+ `CCACHE_BASEDIR` environment variable to an absolute path that specifies
+ which paths to rewrite.
+
+- Object files are now optionally stored compressed in the cache. The runtime
+ cost is negligible, and more files will fit in the ccache directory and in
+ the disk cache. Set `CCACHE_COMPRESS` to enable object file compression. Note
+ that you can't use compression in combination with the hard link feature.
+
+- A `CCACHE_COMPILERCHECK` option has been added. This option tells ccache what
+ compiler-identifying information to hash to ensure that results retrieved
+ from the cache are accurate. Possible values are: none (don't hash anything),
+ mtime (hash the compiler's mtime and size) and content (hash the content of
+ the compiler binary). The default is mtime.
+
+- It is now possible to specify extra files whose contents should be included
+ in the hash sum by setting the `CCACHE_EXTRAFILES` option.
+
+- Added support for Objective-C and Objective-C\+\+. The statistics counter
+ ``not a C/C++ file'' has been renamed to ``unsupported source language''.
+
+- Added support for the `-x` compiler option.
+
+- Added support for long command-line options.
+
+- A `CACHEDIR.TAG` file is now created in the cache directory. See
+ <http://www.brynosaurus.com/cachedir/>.
+
+- Messages printed to the debug log (specified by `CCACHE_LOGFILE`) have been
+ improved.
+
+- You can relax some checks that ccache does in direct mode by setting
+ `CCACHE_SLOPPINESS`. See the manual for more information.
+
+- `CCACHE_TEMPDIR` no longer needs to be on the same filesystem as
+ `CCACHE_DIR`.
+
+- The default value of `CCACHE_TEMPDIR` has been changed to `$CCACHE_DIR/tmp`
+ to avoid cluttering the top directory.
+
+- Temporary files that later will be moved into the cache are now created in
+ the cache directory they will end up in. This makes ccache more friendly to
+ Linux's directory layout.
+
+- Improved the test suite and added tests for most of the new functionality.
+ It's now also possible to specify a subset of tests to run.
+
+- Standard error output from the compiler is now only stored in the cache if
+ it's non-empty.
+
+- If the compiler produces no object file or an empty object file, but gives a
+ zero exit status (could be due to a file system problem, a buggy program
+ specified by `CCACHE_PREFIX`, etc.), ccache copes with it properly.
+
+- Added `installcheck` and `distcheck` make targets.
+
+- Clarified cache size limit options' and cleanup semantics.
+
+- Improved display of cache max size values.
+
+- The following options are no longer hashed in the preprocessor mode:
+ `-imacros`, `-imultilib`, `-iprefix`, `-iquote`, `-isysroot`, `-iwithprefix`,
+ `-iwithprefixbefore`, `-nostdinc`, `-nostdinc++` and `-U`.
+
+
+Bug fixes
+~~~~~~~~~
+
+- Various portability improvements.
+
+- Improved detection of home directory.
+
+- User-defined `CPPFLAGS` and `LDFLAGS` are now respected in the Makefile.
+
+- Fixed NFS issues.
+
+- Computation of the hash sum has been improved to decrease the risk of hash
+ collisions. For instance, the compiler options `-X -Y` and `-X-Y` previously
+ contributed equally to the hash sum.
+
+- Bail out on too hard compiler options `--coverage`, `-fprofile-arcs`,
+ `-fprofile-generate`, `-fprofile-use`, `-frepo`, `-ftest-coverage` and
+ `-save-temps`. Also bail out on `@file` style options.
+
+- Errors when using multiple `-arch` compiler options are now noted as
+ ``unsupported compiler option''.
+
+- `-MD`/`-MMD` options without `-MT`/`-MF` are now handled correctly.
+
+- The `-finput-charset` option is now handled correctly.
+
+- Added support for `-Wp,-MD` and `-Wp,-MMD` options.
+
+- The compiler options `-Xassembler`, `-b`, `-G` and `-V` are now correctly
+ recognized as taking an argument.
+
+- Debug information containing line numbers of predefined and command-line
+ macros (enabled with the compiler option `-g3`) will now be correct.
+
+- Corrected LRU cleanup handling of object files.
+
+- `utimes()` is now used instead of `utime()` when available.
+
+- Non-writable cache directories are now handled gracefully.
+
+- Corrected documentation about sharing the cache directory.
+
+- Fixed compilation warnings from GCC 4.3.
+
+- The command specified by `CCACHE_PREFIX` is no longer part of the hash.
+
+- Fixed bad memory access spotted by Valgrind.
+
+- Fixed a bug in `x_realloc`.
+
+- Freed memory is no longer referenced when compiling a `.i`/`.ii` file and
+ falling back to running the real compiler.
+
+- The test suite is now immune to external values of the `CCACHE_*` environment
+ variables.
+
+- Improved detection of recursive invocation.
+
+- The ccache binary is now not unconditionally stripped when installing.
+
+- Statistics counters are now correctly updated for -E option failures and
+ internal errors.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cbb985a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,66 @@
+ccache
+======
+
+[![Build Status](https://travis-ci.org/ccache/ccache.svg?branch=master)](https://travis-ci.org/ccache/ccache)
+
+About
+-----
+
+ccache is a compiler cache. It speeds up recompilation by caching the result of
+previous compilations and detecting when the same compilation is being done
+again. Supported languages are C, C++, Objective-C and Objective-C++.
+
+
+Documentation
+-------------
+
+See the https://ccache.samba.org.
+
+
+Installation
+------------
+
+See [INSTALL.md](INSTALL.md).
+
+
+Web site
+--------
+
+The main ccache web site is here:
+
+https://ccache.samba.org
+
+
+Mailing list
+------------
+
+There is a mailing list for discussing usage and development of ccache:
+
+https://lists.samba.org/mailman/listinfo/ccache/
+
+Anyone is welcome to join.
+
+
+Bug reports
+-----------
+
+To submit a bug report or to search for existing reports, please visit this web
+page:
+
+https://ccache.samba.org/bugs.html
+
+
+History
+-------
+
+ccache was originally written by Andrew Tridgell and is currently developed and
+maintained by Joel Rosdahl. ccache started out as a reimplementation of Erik
+Thiele's "compilercache" (see http://www.erikyyy.de/compilercache/) in C.
+
+See also https://ccache.samba.org/news.html.
+
+
+License and copyright
+---------------------
+
+See https://ccache.samba.org/license.html.
diff --git a/args.c b/args.c
new file mode 100644
index 0000000..66cc680
--- /dev/null
+++ b/args.c
@@ -0,0 +1,314 @@
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2009-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+
+struct args *
+args_init(int init_argc, char **init_args)
+{
+ struct args *args = (struct args *)x_malloc(sizeof(struct args));
+ args->argc = 0;
+ args->argv = (char **)x_malloc(sizeof(char *));
+ args->argv[0] = NULL;
+ for (int i = 0; i < init_argc; i++) {
+ args_add(args, init_args[i]);
+ }
+ return args;
+}
+
+struct args *
+args_init_from_string(const char *command)
+{
+ char *p = x_strdup(command);
+ char *q = p;
+ char *word, *saveptr = NULL;
+ struct args *args = args_init(0, NULL);
+ while ((word = strtok_r(q, " \t\r\n", &saveptr))) {
+ args_add(args, word);
+ q = NULL;
+ }
+
+ free(p);
+ return args;
+}
+
+struct args *
+args_init_from_gcc_atfile(const char *filename)
+{
+ char *argtext;
+ if (!(argtext = read_text_file(filename, 0))) {
+ return NULL;
+ }
+
+ struct args *args = args_init(0, NULL);
+ char *pos = argtext;
+ char *argbuf = x_malloc(strlen(argtext) + 1);
+ char *argpos = argbuf;
+
+ // Used to track quoting state; if \0, we are not inside quotes. Otherwise
+ // stores the quoting character that started it, for matching the end quote.
+ char quoting = '\0';
+
+ while (1) {
+ switch (*pos) {
+ case '\\':
+ pos++;
+ if (*pos == '\0') {
+ continue;
+ }
+ break;
+
+ case '\"':
+ case '\'':
+ if (quoting != '\0') {
+ if (quoting == *pos) {
+ quoting = '\0';
+ pos++;
+ continue;
+ } else {
+ break;
+ }
+ } else {
+ quoting = *pos;
+ pos++;
+ continue;
+ }
+
+ case '\n':
+ case '\r':
+ case '\t':
+ case ' ':
+ if (quoting) {
+ break;
+ }
+ // Fall through.
+
+ case '\0':
+ // End of token
+ *argpos = '\0';
+ if (argbuf[0] != '\0') {
+ args_add(args, argbuf);
+ }
+ argpos = argbuf;
+ if (*pos == '\0') {
+ goto out;
+ } else {
+ pos++;
+ continue;
+ }
+ }
+
+ *argpos = *pos;
+ pos++;
+ argpos++;
+ }
+
+out:
+ free(argbuf);
+ free(argtext);
+ return args;
+}
+
+struct args *
+args_copy(struct args *args)
+{
+ return args_init(args->argc, args->argv);
+}
+
+// Insert all arguments in src into dest at position index. If replace is true,
+// the element at dest->argv[index] is replaced with the contents of src and
+// everything past it is shifted. Otherwise, dest->argv[index] is also shifted.
+//
+// src is consumed by this operation and should not be freed or used again by
+// the caller.
+void
+args_insert(struct args *dest, int index, struct args *src, bool replace)
+{
+ // Adjustments made if we are replacing or shifting the element currently at
+ // dest->argv[index].
+ int offset = replace ? 1 : 0;
+
+ if (replace) {
+ free(dest->argv[index]);
+ }
+
+ if (src->argc == 0) {
+ if (replace) {
+ // Have to shift everything down by 1 since we replaced with an empty
+ // list.
+ for (int i = index; i < dest->argc; i++) {
+ dest->argv[i] = dest->argv[i + 1];
+ }
+ dest->argc--;
+ }
+ args_free(src);
+ return;
+ }
+
+ if (src->argc == 1 && replace) {
+ // Trivial case; replace with 1 element.
+ dest->argv[index] = src->argv[0];
+ src->argc = 0;
+ args_free(src);
+ return;
+ }
+
+ dest->argv = (char **)x_realloc(
+ dest->argv,
+ (src->argc + dest->argc + 1 - offset) *
+ sizeof(char *));
+
+ // Shift arguments over.
+ for (int i = dest->argc; i >= index + offset; i--) {
+ dest->argv[i + src->argc - offset] = dest->argv[i];
+ }
+
+ // Copy the new arguments into place.
+ for (int i = 0; i < src->argc; i++) {
+ dest->argv[i + index] = src->argv[i];
+ }
+
+ dest->argc += src->argc - offset;
+ src->argc = 0;
+ args_free(src);
+}
+
+void
+args_free(struct args *args)
+{
+ if (!args) {
+ return;
+ }
+ for (int i = 0; i < args->argc; ++i) {
+ if (args->argv[i]) {
+ free(args->argv[i]);
+ }
+ }
+ free(args->argv);
+ free(args);
+}
+
+void
+args_add(struct args *args, const char *s)
+{
+ args->argv = (char **)x_realloc(args->argv,
+ (args->argc + 2) * sizeof(char *));
+ args->argv[args->argc] = x_strdup(s);
+ args->argc++;
+ args->argv[args->argc] = NULL;
+}
+
+// Add all arguments in to_append to args.
+void
+args_extend(struct args *args, struct args *to_append)
+{
+ for (int i = 0; i < to_append->argc; i++) {
+ args_add(args, to_append->argv[i]);
+ }
+}
+
+// Pop the last element off the args list.
+void
+args_pop(struct args *args, int n)
+{
+ while (n--) {
+ args->argc--;
+ free(args->argv[args->argc]);
+ args->argv[args->argc] = NULL;
+ }
+}
+
+// Set argument at given index.
+void
+args_set(struct args *args, int index, const char *value)
+{
+ assert(index < args->argc);
+ free(args->argv[index]);
+ args->argv[index] = x_strdup(value);
+}
+
+// Remove the first element of the argument list.
+void
+args_remove_first(struct args *args)
+{
+ free(args->argv[0]);
+ memmove(&args->argv[0], &args->argv[1], args->argc * sizeof(args->argv[0]));
+ args->argc--;
+}
+
+// Add an argument into the front of the argument list.
+void
+args_add_prefix(struct args *args, const char *s)
+{
+ args->argv = (char **)x_realloc(args->argv,
+ (args->argc + 2) * sizeof(char *));
+ memmove(&args->argv[1], &args->argv[0],
+ (args->argc+1) * sizeof(args->argv[0]));
+ args->argv[0] = x_strdup(s);
+ args->argc++;
+}
+
+// Strip any arguments beginning with the specified prefix.
+void
+args_strip(struct args *args, const char *prefix)
+{
+ for (int i = 0; i < args->argc; ) {
+ if (str_startswith(args->argv[i], prefix)) {
+ free(args->argv[i]);
+ memmove(&args->argv[i],
+ &args->argv[i+1],
+ (args->argc - i) * sizeof(args->argv[i]));
+ args->argc--;
+ } else {
+ i++;
+ }
+ }
+}
+
+// Format args to a space-separated string. Does not quote spaces. Caller
+// frees.
+char *
+args_to_string(struct args *args)
+{
+ unsigned size = 0;
+ for (char **p = args->argv; *p; p++) {
+ size += strlen(*p) + 1;
+ }
+
+ char *result = x_malloc(size + 1);
+ int pos = 0;
+ for (char **p = args->argv; *p; p++) {
+ pos += sprintf(&result[pos], "%s ", *p);
+ }
+ result[pos - 1] = '\0';
+ return result;
+}
+
+// Returns true if args1 equals args2, else false.
+bool
+args_equal(struct args *args1, struct args *args2)
+{
+ if (args1->argc != args2->argc) {
+ return false;
+ }
+ for (int i = 0; i < args1->argc; i++) {
+ if (!str_eq(args1->argv[i], args2->argv[i])) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..eb3d9ba
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+set -e
+
+rm -f dev_mode_disabled
+autoheader
+autoconf
+echo "Now run ./configure and make"
diff --git a/ccache.1 b/ccache.1
new file mode 100644
index 0000000..f0de31b
--- /dev/null
+++ b/ccache.1
@@ -0,0 +1,1809 @@
+'\" t
+.\" Title: ccache
+.\" Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 02/17/2017
+.\" Manual: ccache Manual
+.\" Source: ccache 3.3.4
+.\" Language: English
+.\"
+.TH "CCACHE" "1" "02/17/2017" "ccache 3\&.3\&.4" "ccache Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+ccache \- a fast C/C++ compiler cache
+.SH "SYNOPSIS"
+.sp
+.nf
+\fBccache\fR [\fIoptions\fR]
+\fBccache\fR \fIcompiler\fR [\fIcompiler options\fR]
+\fIcompiler\fR [\fIcompiler options\fR] (via symbolic link)
+.fi
+.SH "DESCRIPTION"
+.sp
+ccache is a compiler cache\&. It speeds up recompilation by caching the result of previous compilations and detecting when the same compilation is being done again\&. Supported languages are C, C++, Objective\-C and Objective\-C++\&.
+.sp
+ccache has been carefully written to always produce exactly the same compiler output that you would get without the cache\&. The only way you should be able to tell that you are using ccache is the speed\&. Currently known exceptions to this goal are listed under CAVEATS\&. If you ever discover an undocumented case where ccache changes the output of your compiler, please let us know\&.
+.SS "Features"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Keeps statistics on hits/misses\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Automatic cache size management\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Can cache compilations that generate warnings\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Easy installation\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Low overhead\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Optionally uses hard links where possible to avoid copies\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Optionally compresses files in the cache to reduce disk space\&.
+.RE
+.SS "Limitations"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Only knows how to cache the compilation of a single C/C++/Objective\-C/Objective\-C++ file\&. Other types of compilations (multi\-file compilation, linking, etc) will silently fall back to running the real compiler\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Only works with GCC and compilers that behave similar enough\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Some compiler flags are not supported\&. If such a flag is detected, ccache will silently fall back to running the real compiler\&.
+.RE
+.SH "RUN MODES"
+.sp
+There are two ways to use ccache\&. You can either prefix your compilation commands with \fBccache\fR or you can let ccache masquerade as the compiler by creating a symbolic link (named as the compiler) to ccache\&. The first method is most convenient if you just want to try out ccache or wish to use it for some specific projects\&. The second method is most useful for when you wish to use ccache for all your compilations\&.
+.sp
+To use the first method, just make sure that \fBccache\fR is in your \fBPATH\fR\&.
+.sp
+To use the symlinks method, do something like this:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+cp ccache /usr/local/bin/
+ln \-s ccache /usr/local/bin/gcc
+ln \-s ccache /usr/local/bin/g++
+ln \-s ccache /usr/local/bin/cc
+ln \-s ccache /usr/local/bin/c++
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+And so forth\&. This will work as long as the directory with symlinks comes before the path to the compiler (which is usually in /usr/bin)\&. After installing you may wish to run \(lqwhich gcc\(rq to make sure that the correct link is being used\&.
+.if n \{\
+.sp
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBWarning\fR
+.ps -1
+.br
+.sp
+The technique of letting ccache masquerade as the compiler works well, but currently doesn\(cqt interact well with other tools that do the same thing\&. See USING CCACHE WITH OTHER COMPILER WRAPPERS\&.
+.sp .5v
+.RE
+.if n \{\
+.sp
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBWarning\fR
+.ps -1
+.br
+.sp
+Do not use a hard link, use a symbolic link\&. A hard link will cause \(lqinteresting\(rq problems\&.
+.sp .5v
+.RE
+.SH "OPTIONS"
+.sp
+These options only apply when you invoke ccache as \(lqccache\(rq\&. When invoked as a compiler (via a symlink as described in the previous section), the normal compiler options apply and you should refer to the compiler\(cqs documentation\&.
+.PP
+\fB\-c, \-\-cleanup\fR
+.RS 4
+Clean up the cache by removing old cached files until the specified file number and cache size limits are not exceeded\&. This also recalculates the cache file count and size totals\&. Normally, there is no need to initiate cleanup manually as ccache keeps the cache below the specified limits at runtime and keeps statistics up to date on each compilation\&. Forcing a cleanup is mostly useful if you manually modify the cache contents or believe that the cache size statistics may be inaccurate\&.
+.RE
+.PP
+\fB\-C, \-\-clear\fR
+.RS 4
+Clear the entire cache, removing all cached files, but keeping the configuration file\&.
+.RE
+.PP
+\fB\-F, \-\-max\-files\fR=\fIN\fR
+.RS 4
+Set the maximum number of files allowed in the cache\&. Use 0 for no limit\&. The value is stored in a configuration file in the cache directory and applies to all future compilations\&.
+.RE
+.PP
+\fB\-h, \-\-help\fR
+.RS 4
+Print an options summary page\&.
+.RE
+.PP
+\fB\-M, \-\-max\-size\fR=\fISIZE\fR
+.RS 4
+Set the maximum size of the files stored in the cache\&.
+\fISIZE\fR
+should be a number followed by an optional suffix: k, M, G, T (decimal), Ki, Mi, Gi or Ti (binary)\&. The default suffix is G\&. Use 0 for no limit\&. The value is stored in a configuration file in the cache directory and applies to all future compilations\&.
+.RE
+.PP
+\fB\-o, \-\-set\-config\fR=\fIKEY=VALUE\fR
+.RS 4
+Set configuration
+\fIKEY\fR
+to
+\fIVALUE\fR\&. See
+CONFIGURATION
+for more information\&.
+.RE
+.PP
+\fB\-p, \-\-print\-config\fR
+.RS 4
+Print current configuration options and from where they originate (environment variable, configuration file or compile\-time default)\&.
+.RE
+.PP
+\fB\-s, \-\-show\-stats\fR
+.RS 4
+Print the current statistics summary for the cache\&.
+.RE
+.PP
+\fB\-V, \-\-version\fR
+.RS 4
+Print version and copyright information\&.
+.RE
+.PP
+\fB\-z, \-\-zero\-stats\fR
+.RS 4
+Zero the cache statistics (but not the configuration options)\&.
+.RE
+.SH "EXTRA OPTIONS"
+.sp
+When run as a compiler, ccache usually just takes the same command line options as the compiler you are using\&. The only exception to this is the option \fB\-\-ccache\-skip\fR\&. That option can be used to tell ccache to avoid interpreting the next option in any way and to pass it along to the compiler as\-is\&.
+.if n \{\
+.sp
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBNote\fR
+.ps -1
+.br
+.sp
+\fB\-\-ccache\-skip\fR currently only tells ccache not to interpret the next option as a special compiler option \(em the option will still be included in the direct mode hash\&.
+.sp .5v
+.RE
+.sp
+The reason this can be important is that ccache does need to parse the command line and determine what is an input filename and what is a compiler option, as it needs the input filename to determine the name of the resulting object file (among other things)\&. The heuristic ccache uses when parsing the command line is that any argument that exists as a file is treated as an input file name\&. By using \fB\-\-ccache\-skip\fR you can force an option to not be treated as an input file name and instead be passed along to the compiler as a command line option\&.
+.sp
+Another case where \fB\-\-ccache\-skip\fR can be useful is if ccache interprets an option specially but shouldn\(cqt, since the option has another meaning for your compiler than what ccache thinks\&.
+.SH "CONFIGURATION"
+.sp
+ccache\(cqs default behavior can be overridden by configuration file settings, which in turn can be overridden by environment variables with names starting with \fBCCACHE_\fR\&. ccache normally reads configuration from two files: first a system\-level configuration file and secondly a cache\-specific configuration file\&. The priority of configuration settings is as follows (where 1 is highest):
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+Environment variables\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+The cache\-specific configuration file
+\fB<ccachedir>/ccache\&.conf\fR
+(typically
+\fB$HOME/\&.ccache/ccache\&.conf\fR)\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+The system\-wide configuration file
+\fB<sysconfdir>/ccache\&.conf\fR
+(typically
+\fB/etc/ccache\&.conf\fR
+or
+\fB/usr/local/etc/ccache\&.conf\fR)\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+Compile\-time defaults\&.
+.RE
+.sp
+As a special case, if the environment variable \fBCCACHE_CONFIGPATH\fR is set, ccache reads configuration from the specified path instead of the default paths\&.
+.SS "Configuration file syntax"
+.sp
+Configuration files are in a simple \(lqkey = value\(rq format, one setting per line\&. Lines starting with a hash sign are comments\&. Blank lines are ignored, as is whitespace surrounding keys and values\&. Example:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# Set maximum cache size to 10 GB:
+max_size = 10G
+.fi
+.if n \{\
+.RE
+.\}
+.SS "Boolean values"
+.sp
+Some settings are boolean values (i\&.e\&. truth values)\&. In a configuration file, such values must be set to the string \fBtrue\fR or \fBfalse\fR\&. For the corresponding environment variables, the semantics are a bit different: a set environment variable means \(lqtrue\(rq regardless of the value (even if set to the empty string), and an unset environment variable means \(lqfalse\(rq\&. Each boolean environment variable also has a negated form starting with \fBCCACHE_NO\fR\&. For example, \fBCCACHE_COMPRESS\fR can be set to force compression and \fBCCACHE_NOCOMPRESS\fR can be set to force no compression\&.
+.SS "Configuration settings"
+.sp
+Below is a list of available configuration settings\&. The corresponding environment variable name is indicated in parentheses after each configuration setting key\&.
+.PP
+\fBbase_dir\fR (\fBCCACHE_BASEDIR\fR)
+.RS 4
+This setting should be an absolute path to a directory\&. ccache then rewrites absolute paths into relative paths before computing the hash that identifies the compilation, but only for paths under the specified directory\&. If set to the empty string (which is the default), no rewriting is done\&. See also the discussion under
+COMPILING IN DIFFERENT DIRECTORIES\&. If using GCC or newer versions of Clang, you might want to look into the
+\fB\-fdebug\-prefix\-map=old=new\fR
+option for relocating debug info to a common prefix (mapping prefix with old=new)\&.
+.RE
+.PP
+\fBcache_dir\fR (\fBCCACHE_DIR\fR)
+.RS 4
+This setting specifies where ccache will keep its cached compiler outputs\&. It will only take effect if set in the system\-wide configuration file or as an environment variable\&. The default is
+\fB$HOME/\&.ccache\fR\&.
+.RE
+.PP
+\fBcache_dir_levels\fR (\fBCCACHE_NLEVELS\fR)
+.RS 4
+This setting allows you to choose the number of directory levels in the cache directory\&. The default is 2\&. The minimum is 1 and the maximum is 8\&.
+.RE
+.PP
+\fBcompiler\fR (\fBCCACHE_CC\fR)
+.RS 4
+This setting can be used to force the name of the compiler to use\&. If set to the empty string (which is the default), ccache works it out from the command line\&.
+.RE
+.PP
+\fBcompiler_check\fR (\fBCCACHE_COMPILERCHECK\fR)
+.RS 4
+By default, ccache includes the modification time (\(lqmtime\(rq) and size of the compiler in the hash to ensure that results retrieved from the cache are accurate\&. This setting can be used to select another strategy\&. Possible values are:
+.PP
+\fBcontent\fR
+.RS 4
+Hash the content of the compiler binary\&. This makes ccache very slightly slower compared to the
+\fBmtime\fR
+setting, but makes it cope better with compiler upgrades during a build bootstrapping process\&.
+.RE
+.PP
+\fBmtime\fR
+.RS 4
+Hash the compiler\(cqs mtime and size, which is fast\&. This is the default\&.
+.RE
+.PP
+\fBnone\fR
+.RS 4
+Don\(cqt hash anything\&. This may be good for situations where you can safely use the cached results even though the compiler\(cqs mtime or size has changed (e\&.g\&. if the compiler is built as part of your build system and the compiler\(cqs source has not changed, or if the compiler only has changes that don\(cqt affect code generation)\&. You should only use the
+\fBnone\fR
+setting if you know what you are doing\&.
+.RE
+.PP
+\fBstring:value\fR
+.RS 4
+Use
+\fBvalue\fR
+as the string to calculate hash from\&. This can be the compiler revision number you retrieved earlier and set here via environment variable\&.
+.RE
+.PP
+\fIa command string\fR
+.RS 4
+Hash the standard output and standard error output of the specified command\&. The string will be split on whitespace to find out the command and arguments to run\&. No other interpretation of the command string will be done, except that the special word
+\fB%compiler%\fR
+will be replaced with the path to the compiler\&. Several commands can be specified with semicolon as separator\&. Examples:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+%compiler% \-v
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+%compiler% \-dumpmachine; %compiler% \-dumpversion
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+You should make sure that the specified command is as fast as possible since it will be run once for each ccache invocation\&.
+.sp
+Identifying the compiler using a command is useful if you want to avoid cache misses when the compiler has been rebuilt but not changed\&.
+.sp
+Another case is when the compiler (as seen by ccache) actually isn\(cqt the real compiler but another compiler wrapper \(em in that case, the default
+\fBmtime\fR
+method will hash the mtime and size of the other compiler wrapper, which means that ccache won\(cqt be able to detect a compiler upgrade\&. Using a suitable command to identify the compiler is thus safer, but it\(cqs also slower, so you should consider continue using the
+\fBmtime\fR
+method in combination with the
+\fBprefix_command\fR
+setting if possible\&. See
+USING CCACHE WITH OTHER COMPILER WRAPPERS\&.
+.RE
+.RE
+.PP
+\fBcompression\fR (\fBCCACHE_COMPRESS\fR or \fBCCACHE_NOCOMPRESS\fR, see Boolean values above)
+.RS 4
+If true, ccache will compress object files and other compiler output it puts in the cache\&. However, this setting has no effect on how files are retrieved from the cache; compressed and uncompressed results will still be usable regardless of this setting\&. The default is false\&.
+.RE
+.PP
+\fBcompression_level\fR (\fBCCACHE_COMPRESSLEVEL\fR)
+.RS 4
+This setting determines the level at which ccache will compress object files\&. It only has effect if
+\fBcompression\fR
+is enabled\&. The value defaults to 6, and must be no lower than 1 (fastest, worst compression) and no higher than 9 (slowest, best compression)\&.
+.RE
+.PP
+\fBcpp_extension\fR (\fBCCACHE_EXTENSION\fR)
+.RS 4
+This setting can be used to force a certain extension for the intermediate preprocessed file\&. The default is to automatically determine the extension to use for intermediate preprocessor files based on the type of file being compiled, but that sometimes doesn\(cqt work\&. For example, when using the \(lqaCC\(rq compiler on HP\-UX, set the cpp extension to
+\fBi\fR\&.
+.RE
+.PP
+\fBdirect_mode\fR (\fBCCACHE_DIRECT\fR or \fBCCACHE_NODIRECT\fR, see Boolean values above)
+.RS 4
+If true, the direct mode will be used\&. The default is true\&. See
+THE DIRECT MODE\&.
+.RE
+.PP
+\fBdisable\fR (\fBCCACHE_DISABLE\fR or \fBCCACHE_NODISABLE\fR, see Boolean values above)
+.RS 4
+When true, ccache will just call the real compiler, bypassing the cache completely\&. The default is false\&.
+.RE
+.PP
+\fBextra_files_to_hash\fR (\fBCCACHE_EXTRAFILES\fR)
+.RS 4
+This setting is a list of paths to files that ccache will include in the the hash sum that identifies the build\&. The list separator is semicolon on Windows systems and colon on other systems\&.
+.RE
+.PP
+\fBhard_link\fR (\fBCCACHE_HARDLINK\fR or \fBCCACHE_NOHARDLINK\fR, see Boolean values above)
+.RS 4
+If true, ccache will attempt to use hard links from the cache directory when creating the compiler output rather than using a file copy\&. Using hard links may be slightly faster in some situations, but can confuse programs like \(lqmake\(rq that rely on modification times\&. Another thing to keep in mind is that if the resulting object file is modified in any way, this corrupts the cached object file as well\&. Hard links are never made for compressed cache files\&. This means that you should not enable compression if you want to use hard links\&. The default is false\&.
+.RE
+.PP
+\fBhash_dir\fR (\fBCCACHE_HASHDIR\fR or \fBCCACHE_NOHASHDIR\fR, see Boolean values above)
+.RS 4
+If true (which is the default), ccache will include the current working directory (CWD) in the hash that is used to distinguish two compilations when generating debug info (compiler option
+\fB\-g\fR
+with variations)\&. Exception: The CWD will not be included in the hash if
+\fBbase_dir\fR
+is set (and matches the CWD) and the compiler option
+\fB\-fdebug\-prefix\-map\fR
+is used\&.
+.sp
+The reason for including the CWD in the hash by default is to prevent a problem with the storage of the current working directory in the debug info of an object file, which can lead ccache to return a cached object file that has the working directory in the debug info set incorrectly\&.
+.sp
+You can disable this setting to get cache hits when compiling the same source code in different directories if you don\(cqt mind that CWD in the debug info might be incorrect\&.
+.RE
+.PP
+\fBignore_headers_in_manifest\fR (\fBCCACHE_IGNOREHEADERS\fR)
+.RS 4
+This setting is a list of paths to files (or directories with headers) that ccache will
+\fBnot\fR
+include in the manifest list that makes up the direct mode\&. Note that this can cause stale cache hits if those headers do indeed change\&. The list separator is semicolon on Windows systems and colon on other systems\&.
+.RE
+.PP
+\fBkeep_comments_cpp\fR (\fBCCACHE_COMMENTS\fR or \fBCCACHE_NOCOMMENTS\fR, see Boolean values above)
+.RS 4
+If true, ccache will not discard the comments before hashing preprocessor output\&. This can be used to check documentation with
+\fB\-Wdocumentation\fR\&.
+.RE
+.PP
+\fBlimit_multiple\fR (\fBCCACHE_LIMIT_MULTIPLE\fR)
+.RS 4
+Sets the limit when cleaning up\&. Files are deleted (in LRU order) until the levels are below the limit\&. The default is 0\&.8 (= 80%)\&.
+.RE
+.PP
+\fBlog_file\fR (\fBCCACHE_LOGFILE\fR)
+.RS 4
+If set to a file path, ccache will write information on what it is doing to the specified file\&. This is useful for tracking down problems\&.
+.RE
+.PP
+\fBmax_files\fR (\fBCCACHE_MAXFILES\fR)
+.RS 4
+This option specifies the maximum number of files to keep in the cache\&. Use 0 for no limit (which is the default)\&.
+.RE
+.PP
+\fBmax_size\fR (\fBCCACHE_MAXSIZE\fR)
+.RS 4
+This option specifies the maximum size of the cache\&. Use 0 for no limit\&. The default value is 5G\&. Available suffixes: k, M, G, T (decimal) and Ki, Mi, Gi, Ti (binary)\&. The default suffix is "G"\&.
+.RE
+.PP
+\fBpath\fR (\fBCCACHE_PATH\fR)
+.RS 4
+If set, ccache will search directories in this list when looking for the real compiler\&. The list separator is semicolon on Windows systems and colon on other systems\&. If not set, ccache will look for the first executable matching the compiler name in the normal
+\fBPATH\fR
+that isn\(cqt a symbolic link to ccache itself\&.
+.RE
+.PP
+\fBprefix_command\fR (\fBCCACHE_PREFIX\fR)
+.RS 4
+This option adds a list of prefixes (separated by space) to the command line that ccache uses when invoking the compiler\&. See also
+USING CCACHE WITH OTHER COMPILER WRAPPERS\&.
+.RE
+.PP
+\fBprefix_command_cpp\fR (\fBCCACHE_PREFIX_CPP\fR)
+.RS 4
+This option adds a list of prefixes (separated by space) to the command line that ccache uses when invoking the preprocessor\&.
+.RE
+.PP
+\fBread_only\fR (\fBCCACHE_READONLY\fR or \fBCCACHE_NOREADONLY\fR, see Boolean values above)
+.RS 4
+If true, ccache will attempt to use existing cached object files, but it will not to try to add anything new to the cache\&. If you are using this because your ccache directory is read\-only, then you need to set
+\fBtemporary_dir\fR
+as otherwise ccache will fail to create temporary files\&.
+.RE
+.PP
+\fBread_only_direct\fR (\fBCCACHE_READONLY_DIRECT\fR or \fBCCACHE_NOREADONLY_DIRECT\fR, see Boolean values above)
+.RS 4
+Just like
+\fBread_only\fR
+except that ccache will only try to retrieve results from the cache using the direct mode, not the preprocessor mode\&. See documentation for
+\fBread_only\fR
+regarding using a read\-only ccache directory\&.
+.RE
+.PP
+\fBrecache\fR (\fBCCACHE_RECACHE\fR or \fBCCACHE_NORECACHE\fR, see Boolean values above)
+.RS 4
+If true, ccache will not use any previously stored result\&. New results will still be cached, possibly overwriting any pre\-existing results\&.
+.RE
+.PP
+\fBrun_second_cpp\fR (\fBCCACHE_CPP2\fR or \fBCCACHE_NOCPP2\fR, see Boolean values above)
+.RS 4
+If true, ccache will first run the preprocessor to preprocess the source code (see
+THE PREPROCESSOR MODE) and then on a cache miss run the compiler on the source code to get hold of the object file\&. This is the default\&.
+.sp
+If false, ccache will first run preprocessor to preprocess the source code and then on a cache miss run the compiler on the
+\fIpreprocessed source code\fR
+instead of the original source code\&. This makes cache misses slightly faster since the source code only has to be preprocessed once\&. The downside is that some compilers won\(cqt produce the same result (for instance diagnostics warnings) when compiling preprocessed source code\&.
+.RE
+.PP
+\fBsloppiness\fR (\fBCCACHE_SLOPPINESS\fR)
+.RS 4
+By default, ccache tries to give as few false cache hits as possible\&. However, in certain situations it\(cqs possible that you know things that ccache can\(cqt take for granted\&. This setting makes it possible to tell ccache to relax some checks in order to increase the hit rate\&. The value should be a comma\-separated string with options\&. Available options are:
+.PP
+\fBfile_macro\fR
+.RS 4
+Ignore
+\fB__FILE__\fR
+being present in the source\&.
+.RE
+.PP
+\fBfile_stat_matches\fR
+.RS 4
+ccache normally examines a file\(cqs contents to determine whether it matches the cached version\&. With this option set, ccache will consider a file as matching its cached version if the sizes, mtimes and ctimes match\&.
+.RE
+.PP
+\fBinclude_file_ctime\fR
+.RS 4
+By default, ccache also will not cache a file if it includes a header whose ctime is too new\&. This option disables that check\&.
+.RE
+.PP
+\fBinclude_file_mtime\fR
+.RS 4
+By default, ccache will not cache a file if it includes a header whose mtime is too new\&. This option disables that check\&.
+.RE
+.PP
+\fBno_system_headers\fR
+.RS 4
+By default, ccache will also include all system headers in the manifest\&. With this option set, ccache will only include system headers in the hash but not add the system header files to the list of include files\&.
+.RE
+.PP
+\fBpch_defines\fR
+.RS 4
+Be sloppy about #defines when precompiling a header file\&. See
+PRECOMPILED HEADERS
+for more information\&.
+.RE
+.PP
+\fBtime_macros\fR
+.RS 4
+Ignore
+\fB__DATE__\fR
+and
+\fB__TIME__\fR
+being present in the source code\&.
+.RE
+.sp
+See the discussion under
+TROUBLESHOOTING
+for more information\&.
+.RE
+.PP
+\fBstats\fR (\fBCCACHE_STATS\fR or \fBCCACHE_NOSTATS\fR, see Boolean values above)
+.RS 4
+If true, ccache will update the statistics counters on each compilation\&. The default is true\&.
+.RE
+.PP
+\fBtemporary_dir\fR (\fBCCACHE_TEMPDIR\fR)
+.RS 4
+This setting specifies where ccache will put temporary files\&. The default is
+\fB<cache_dir>/tmp\fR\&.
+.if n \{\
+.sp
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBNote\fR
+.ps -1
+.br
+In previous versions of ccache,
+\fBCCACHE_TEMPDIR\fR
+had to be on the same filesystem as the
+\fBCCACHE_DIR\fR
+path, but this requirement has been relaxed\&.)
+.sp .5v
+.RE
+.RE
+.PP
+\fBumask\fR (\fBCCACHE_UMASK\fR)
+.RS 4
+This setting specifies the umask for ccache and all child processes (such as the compiler)\&. This is mostly useful when you wish to share your cache with other users\&. Note that this also affects the file permissions set on the object files created from your compilations\&.
+.RE
+.PP
+\fBunify\fR (\fBCCACHE_UNIFY\fR or \fBCCACHE_NOUNIFY\fR, see Boolean values above)
+.RS 4
+If true, ccache will use a C/C++ unifier when hashing the preprocessor output if the
+\fB\-g\fR
+option is not used\&. The unifier is slower than a normal hash, so setting this environment variable loses a little bit of speed, but it means that ccache can take advantage of not recompiling when the changes to the source code consist of reformatting only\&. Note that enabling the unifier changes the hash, so cached compilations produced when the unifier is enabled cannot be reused when the unifier is disabled, and vice versa\&. Enabling the unifier may result in incorrect line number information in compiler warning messages and expansions of the
+\fB__LINE__\fR
+macro\&. Also note that enabling the unifier implies turning off the direct mode\&.
+.RE
+.SH "CACHE SIZE MANAGEMENT"
+.sp
+By default, ccache has a five gigabyte limit on the total size of files in the cache and no maximum number of files\&. You can set different limits using the \fB\-M\fR/\fB\-\-max\-size\fR and \fB\-F\fR/\fB\-\-max\-files\fR options\&. Use \fBccache \-s/\-\-show\-stats\fR to see the cache size and the currently configured limits (in addition to other various statistics)\&.
+.SH "CACHE COMPRESSION"
+.sp
+ccache can optionally compress all files it puts into the cache using the compression library zlib\&. While this may involve a tiny performance slowdown, it increases the number of files that fit in the cache\&. You can turn on compression with the \fBcompression\fR configuration setting and you can also tweak the compression level with \fBcompression_level\fR\&.
+.SH "CACHE STATISTICS"
+.sp
+\fBccache \-s/\-\-show\-stats\fR can show the following statistics:
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Name
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+autoconf compile/link
+T}:T{
+.sp
+Uncachable compilation or linking by an autoconf test\&.
+T}
+T{
+.sp
+bad compiler arguments
+T}:T{
+.sp
+Malformed compiler argument, e\&.g\&. missing a value for an option that requires an argument or failure to read a file specified by an option argument\&.
+T}
+T{
+.sp
+cache file missing
+T}:T{
+.sp
+A file was unexpectedly missing from the cache\&. This only happens in rare situations, e\&.g\&. if one ccache instance is about to get a file from the cache while another instance removed the file as part of cache cleanup\&.
+T}
+T{
+.sp
+cache hit (direct)
+T}:T{
+.sp
+A result was successfully found using the direct mode\&.
+T}
+T{
+.sp
+cache hit (preprocessed)
+T}:T{
+.sp
+A result was successfully found using the preprocessor mode\&.
+T}
+T{
+.sp
+cache miss
+T}:T{
+.sp
+No result was found\&.
+T}
+T{
+.sp
+cache size
+T}:T{
+.sp
+Current size of the cache\&.
+T}
+T{
+.sp
+called for link
+T}:T{
+.sp
+The compiler was called for linking, not compiling\&.
+T}
+T{
+.sp
+called for preprocessing
+T}:T{
+.sp
+The compiler was called for preprocessing, not compiling\&.
+T}
+T{
+.sp
+can\(cqt use precompiled header
+T}:T{
+.sp
+Preconditions for using precompiled headers were not fulfilled\&.
+T}
+T{
+.sp
+ccache internal error
+T}:T{
+.sp
+Unexpected failure, e\&.g\&. due to problems reading/writing the cache\&.
+T}
+T{
+.sp
+cleanups performed
+T}:T{
+.sp
+Number of cleanups performed, either implicitly due to the cache size limit being reached or due to explicit \fBccache \-c/\-\-cleanup\fR calls\&.
+T}
+T{
+.sp
+compile failed
+T}:T{
+.sp
+The compilation failed\&. No result stored in the cache\&.
+T}
+T{
+.sp
+compiler check failed
+T}:T{
+.sp
+A compiler check program specified by \fBcompiler_check\fR (\fBCCACHE_COMPILERCHECK\fR) failed\&.
+T}
+T{
+.sp
+compiler produced empty output
+T}:T{
+.sp
+The compiler\(cqs output file (typically an object file) was empty after compilation\&.
+T}
+T{
+.sp
+compiler produced no output
+T}:T{
+.sp
+The compiler\(cqs output file (typically an object file) was missing after compilation\&.
+T}
+T{
+.sp
+compiler produced stdout
+T}:T{
+.sp
+The compiler wrote data to standard output\&. This is something that compilers normally never do, so ccache is not designed to store such output in the cache\&.
+T}
+T{
+.sp
+couldn\(cqt find the compiler
+T}:T{
+.sp
+The compiler to execute could not be found\&.
+T}
+T{
+.sp
+error hashing extra file
+T}:T{
+.sp
+Failure reading a file specified by \fBextra_files_to_hash\fR (\fBCCACHE_EXTRAFILES\fR)\&.
+T}
+T{
+.sp
+files in cache
+T}:T{
+.sp
+Current number of files in the cache\&.
+T}
+T{
+.sp
+multiple source files
+T}:T{
+.sp
+The compiler was called to compile multiple source files in one go\&. This is not supported by ccache\&.
+T}
+T{
+.sp
+no input file
+T}:T{
+.sp
+No input file was specified to the compiler\&.
+T}
+T{
+.sp
+output to a non\-regular file
+T}:T{
+.sp
+The output path specified with \fB\-o\fR is not a file (e\&.g\&. a directory or a device node)\&.
+T}
+T{
+.sp
+output to stdout
+T}:T{
+.sp
+The compiler was instructed to write its output to standard output using \fB\-o \-\fR\&. This is not supported by ccache\&.
+T}
+T{
+.sp
+preprocessor error
+T}:T{
+.sp
+Preprocessing the source code using the compiler\(cqs \fB\-E\fR option failed\&.
+T}
+T{
+.sp
+unsupported code directive
+T}:T{
+.sp
+Code like the assembler \(lq\&.incbin\(rq directive was found\&. This is not supported by ccache\&.
+T}
+T{
+.sp
+unsupported compiler option
+T}:T{
+.sp
+A compiler option not supported by ccache was found\&.
+T}
+T{
+.sp
+unsupported source language
+T}:T{
+.sp
+A source language e\&.g\&. specified with \fB\-x\fR was unsupported by ccache\&.
+T}
+.TE
+.sp 1
+.SH "HOW CCACHE WORKS"
+.sp
+The basic idea is to detect when you are compiling exactly the same code a second time and reuse the previously produced output\&. The detection is done by hashing different kinds of information that should be unique for the compilation and then using the hash sum to identify the cached output\&. ccache uses MD4, a very fast cryptographic hash algorithm, for the hashing\&. (MD4 is nowadays too weak to be useful in cryptographic contexts, but it should be safe enough to be used to identify recompilations\&.) On a cache hit, ccache is able to supply all of the correct compiler outputs (including all warnings, dependency file, etc) from the cache\&.
+.sp
+ccache has two ways of doing the detection:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the
+\fBdirect mode\fR, where ccache hashes the source code and include files directly
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the
+\fBpreprocessor mode\fR, where ccache runs the preprocessor on the source code and hashes the result
+.RE
+.sp
+The direct mode is generally faster since running the preprocessor has some overhead\&.
+.SS "Common hashed information"
+.sp
+For both modes, the following information is included in the hash:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the extension used by the compiler for a file with preprocessor output (normally
+\fB\&.i\fR
+for C code and
+\fB\&.ii\fR
+for C++ code)
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the compiler\(cqs size and modification time (or other compiler\-specific information specified by the
+\fBcompiler_check\fR
+setting)
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the name of the compiler
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the current directory (if the
+\fBhash_dir\fR
+setting is enabled)
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+contents of files specified by the
+\fBextra_files_to_hash\fR
+setting (if any)
+.RE
+.SS "The direct mode"
+.sp
+In the direct mode, the hash is formed of the common information and:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the input source file
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the command line options
+.RE
+.sp
+Based on the hash, a data structure called \(lqmanifest\(rq is looked up in the cache\&. The manifest contains:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+references to cached compilation results (object file, dependency file, etc) that were produced by previous compilations that matched the hash
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+paths to the include files that were read at the time the compilation results were stored in the cache
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+hash sums of the include files at the time the compilation results were stored in the cache
+.RE
+.sp
+The current contents of the include files are then hashed and compared to the information in the manifest\&. If there is a match, ccache knows the result of the compilation\&. If there is no match, ccache falls back to running the preprocessor\&. The output from the preprocessor is parsed to find the include files that were read\&. The paths and hash sums of those include files are then stored in the manifest along with information about the produced compilation result\&.
+.sp
+There is a catch with the direct mode: header files that were used by the compiler are recorded, but header files that were \fBnot\fR used, but would have been used if they existed, are not\&. So, when ccache checks if a result can be taken from the cache, it currently can\(cqt check if the existence of a new header file should invalidate the result\&. In practice, the direct mode is safe to use in the absolute majority of cases\&.
+.sp
+The direct mode will be disabled if any of the following holds:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the configuration setting
+\fBdirect_mode\fR
+is false
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+a modification time of one of the include files is too new (needed to avoid a race condition)
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the unifier is enabled (the configuration setting
+\fBunify\fR
+is true)
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+a compiler option not supported by the direct mode is used:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+a
+\fB\-Wp,\fR\fB\fIX\fR\fR
+compiler option other than
+\fB\-Wp,\-MD,\fR\fB\fIpath\fR\fR,
+\fB\-Wp,\-MMD,\fR\fB\fIpath\fR\fR
+and
+\fB\-Wp,\-D_define_\fR
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fB\-Xpreprocessor\fR
+.RE
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the string \(lq__TIME__\(rq is present in the source code
+.RE
+.SS "The preprocessor mode"
+.sp
+In the preprocessor mode, the hash is formed of the common information and:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the preprocessor output from running the compiler with
+\fB\-E\fR
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+the command line options except options that affect include files (\fB\-I\fR,
+\fB\-include\fR,
+\fB\-D\fR, etc; the theory is that these options will change the preprocessor output if they have any effect at all)
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+any standard error output generated by the preprocessor
+.RE
+.sp
+Based on the hash, the cached compilation result can be looked up directly in the cache\&.
+.SH "COMPILING IN DIFFERENT DIRECTORIES"
+.sp
+Some information included in the hash that identifies a unique compilation may contain absolute paths:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The preprocessed source code may contain absolute paths to include files if the compiler option
+\fB\-g\fR
+is used or if absolute paths are given to
+\fB\-I\fR
+and similar compiler options\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Paths specified by compiler options (such as
+\fB\-I\fR,
+\fB\-MF\fR, etc) may be absolute\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The source code file path may be absolute, and that path may substituted for
+\fB__FILE__\fR
+macros in the source code or included in warnings emitted to standard error by the preprocessor\&.
+.RE
+.sp
+This means that if you compile the same code in different locations, you can\(cqt share compilation results between the different build directories since you get cache misses because of the absolute build directory paths that are part of the hash\&. To mitigate this problem, you can specify a \(lqbase directory\(rq in the configuration setting \fBbase_dir\fR to an absolute path to the directory\&. ccache will then rewrite absolute paths that are under the base directory (i\&.e\&., paths that have the base directory as a prefix) to relative paths when constructing the hash\&. A typical path to use as the base directory is your home directory or another directory that is a parent of your build directories\&. (Don\(cqt use / as the base directory since that will make ccache also rewrite paths to system header files, which doesn\(cqt gain anything\&.)
+.sp
+The drawbacks of using a base directory are:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If you specify an absolute path to the source code file,
+\fB__FILE__\fR
+macros will be expanded to a relative path instead\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If you specify an absolute path to the source code file and compile with
+\fB\-g\fR, the source code path stored in the object file may point to the wrong directory, which may prevent debuggers like GDB from finding the source code\&. Sometimes, a work\-around is to change the directory explicitly with the \(lqcd\(rq command in GDB\&.
+.RE
+.SH "PRECOMPILED HEADERS"
+.sp
+ccache has support for GCC\(cqs precompiled headers\&. However, you have to do some things to make it work properly:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+You must set
+\fBsloppiness\fR
+to
+\fBpch_defines,time_macros\fR\&. The reason is that ccache can\(cqt tell whether
+\fB__TIME__\fR
+or
+\fB__DATE__\fR
+is used when using a precompiled header\&. Further, it can\(cqt detect changes in #defines in the source code because of how preprocessing works in combination with precompiled headers\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+You must either:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+use the
+\fB\-include\fR
+compiler option to include the precompiled header (i\&.e\&., don\(cqt use
+\fB#include\fR
+in the source code to include the header); or
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+(for the Clang compiler) use the
+\fB\-include\-pch\fR
+compiler option to include the PCH file generated from the precompiled header; or
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+add the
+\fB\-fpch\-preprocess\fR
+compiler option when compiling\&.
+.RE
+.sp
+If you don\(cqt do this, either the non\-precompiled version of the header file will be used (if available) or ccache will fall back to running the real compiler and increase the statistics counter \(lqpreprocessor error\(rq (if the non\-precompiled header file is not available)\&.
+.RE
+.SH "SHARING A CACHE"
+.sp
+A group of developers can increase the cache hit rate by sharing a cache directory\&. To share a cache without unpleasant side effects, the following conditions should to be met:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Use the same cache directory\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Make sure that the configuration setting
+\fBhard_link\fR
+is false (which is the default)\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Make sure that all users are in the same group\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Set the configuration setting
+\fBumask\fR
+to 002\&. This ensures that cached files are accessible to everyone in the group\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Make sure that all users have write permission in the entire cache directory (and that you trust all users of the shared cache)\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Make sure that the setgid bit is set on all directories in the cache\&. This tells the filesystem to inherit group ownership for new directories\&. The following command might be useful for this:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+find $CCACHE_DIR \-type d | xargs chmod g+s
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+The reason to avoid the hard link mode is that the hard links cause unwanted side effects, as all links to a cached file share the file\(cqs modification timestamp\&. This results in false dependencies to be triggered by timestamp\-based build systems whenever another user links to an existing file\&. Typically, users will see that their libraries and binaries are relinked without reason\&.
+.sp
+You may also want to make sure that a base directory is set appropriately, as discussed in a previous section\&.
+.SH "SHARING A CACHE ON NFS"
+.sp
+It is possible to put the cache directory on an NFS filesystem (or similar filesystems), but keep in mind that:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Having the cache on NFS may slow down compilation\&. Make sure to do some benchmarking to see if it\(cqs worth it\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+ccache hasn\(cqt been tested very thoroughly on NFS\&.
+.RE
+.sp
+A tip is to set \fBtemporary_dir\fR to a directory on the local host to avoid NFS traffic for temporary files\&.
+.SH "USING CCACHE WITH OTHER COMPILER WRAPPERS"
+.sp
+The recommended way of combining ccache with another compiler wrapper (such as \(lqdistcc\(rq) is by letting ccache execute the compiler wrapper\&. This is accomplished by defining the configuration setting \fBprefix_command\fR, for example by setting the environment variable \fBCCACHE_PREFIX\fR to the name of the wrapper (e\&.g\&. \fBdistcc\fR)\&. ccache will then prefix the command line with the specified command when running the compiler\&. To specify several prefix commands, set \fBprefix_command\fR to a colon\-separated list of commands\&.
+.sp
+Unless you set \fBcompiler_check\fR to a suitable command (see the description of that configuration option), it is not recommended to use the form \fBccache anotherwrapper compiler args\fR as the compilation command\&. It\(cqs also not recommended to use the masquerading technique for the other compiler wrapper\&. The reason is that by default, ccache will in both cases hash the mtime and size of the other wrapper instead of the real compiler, which means that:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Compiler upgrades will not be detected properly\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The cached results will not be shared between compilations with and without the other wrapper\&.
+.RE
+.sp
+Another minor thing is that if \fBprefix_command\fR is used, ccache will not invoke the other wrapper when running the preprocessor, which increases performance\&. You can use the \fBprefix_command_cpp\fR configuration setting if you also want to invoke the other wrapper when doing preprocessing (normally by adding \fB\-E\fR)\&.
+.SH "CAVEATS"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The direct mode fails to pick up new header files in some rare scenarios\&. See
+THE DIRECT MODE
+above\&.
+.RE
+.SH "TROUBLESHOOTING"
+.SS "General"
+.sp
+A general tip for getting information about what ccache is doing is to enable debug logging by setting \fBlog_file\fR\&. The log contains executed commands, important decisions that ccache makes, read and written files, etc\&. Another way of keeping track of what is happening is to check the output of \fBccache \-s\fR\&.
+.SS "Performance"
+.sp
+ccache has been written to perform well out of the box, but sometimes you may have to do some adjustments of how you use the compiler and ccache in order to improve performance\&.
+.sp
+Since ccache works best when I/O is fast, put the cache directory on a fast storage device if possible\&. Having lots of free memory so that files in the cache directory stay in the disk cache is also preferable\&.
+.sp
+A good way of monitoring how well ccache works is to run \fBccache \-s\fR before and after your build and then compare the statistics counters\&. Here are some common problems and what may be done to increase the hit rate:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If \(lqcache hit (preprocessed)\(rq has been incremented instead of \(lqcache hit (direct)\(rq, ccache has fallen back to preprocessor mode, which is generally slower\&. Some possible reasons are:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The source code has been modified in such a way that the preprocessor output is not affected\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Compiler arguments that are hashed in the direct mode but not in the preprocessor mode have changed (\fB\-I\fR,
+\fB\-include\fR,
+\fB\-D\fR, etc) and they didn\(cqt affect the preprocessor output\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The compiler option
+\fB\-Xpreprocessor\fR
+or
+\fB\-Wp,\fR\fB\fIX\fR\fR
+(except
+\fB\-Wp,\-MD,\fR\fB\fIpath\fR\fR,
+\fB\-Wp,\-MMD,\fR\fB\fIpath\fR\fR, and
+\fB\-Wp,\-D_define_\fR) is used\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+This was the first compilation with a new value of the base directory setting\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+A modification time of one of the include files is too new (created the same second as the compilation is being done)\&. This check is made to avoid a race condition\&. To fix this, create the include file earlier in the build process, if possible, or set
+\fBsloppiness\fR
+to
+\fBinclude_file_mtime\fR
+if you are willing to take the risk\&. (The race condition consists of these events: the preprocessor is run; an include file is modified by someone; the new include file is hashed by ccache; the real compiler is run on the preprocessor\(cqs output, which contains data from the old header file; the wrong object file is stored in the cache\&.)
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The
+\fB__TIME__\fR
+preprocessor macro is (potentially) being used\&. ccache turns off direct mode if \(lq__TIME__\(rq is present in the source code\&. This is done as a safety measure since the string indicates that a
+\fB__TIME__\fR
+macro
+\fImay\fR
+affect the output\&. (To be sure, ccache would have to run the preprocessor, but the sole point of the direct mode is to avoid that\&.) If you know that
+\fB__TIME__\fR
+isn\(cqt used in practise, or don\(cqt care if ccache produces objects where
+\fB__TIME__\fR
+is expanded to something in the past, you can set
+\fBsloppiness\fR
+to
+\fBtime_macros\fR\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The
+\fB__DATE__\fR
+preprocessor macro is (potentially) being used and the date has changed\&. This is similar to how
+\fB__TIME__\fR
+is handled\&. If \(lq__DATE__\(rq is present in the source code, ccache hashes the current date in order to be able to produce the correct object file if the
+\fB__DATE__\fR
+macro affects the output\&. If you know that
+\fB__DATE__\fR
+isn\(cqt used in practise, or don\(cqt care if ccache produces objects where
+\fB__DATE__\fR
+is expanded to something in the past, you can set
+\fBsloppiness\fR
+to
+\fBtime_macros\fR\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The
+\fB__FILE__\fR
+preprocessor macro is (potentially) being used and the file path has changed\&. If \(lq__FILE__\(rq is present in the source code, ccache hashes the current input file path in order to be able to produce the correct object file if the
+\fB__FILE__\fR
+macro affects the output\&. If you know that
+\fB__FILE__\fR
+isn\(cqt used in practise, or don\(cqt care if ccache produces objects where
+\fB__FILE__\fR
+is expanded to the wrong path, you can set
+\fBsloppiness\fR
+to
+\fBfile_macro\fR\&.
+.RE
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If \(lqcache miss\(rq has been incremented even though the same code has been compiled and cached before, ccache has either detected that something has changed anyway or a cleanup has been performed (either explicitly or implicitly when a cache limit has been reached)\&. Some perhaps unobvious things that may result in a cache miss are usage of
+\fB__TIME__\fR
+or
+\fB__DATE__\fR
+macros, or use of automatically generated code that contains a timestamp, build counter or other volatile information\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If \(lqmultiple source files\(rq has been incremented, it\(cqs an indication that the compiler has been invoked on several source code files at once\&. ccache doesn\(cqt support that\&. Compile the source code files separately if possible\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If \(lqunsupported compiler option\(rq has been incremented, enable debug logging and check which option was rejected\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If \(lqpreprocessor error\(rq has been incremented, one possible reason is that precompiled headers are being used\&. See
+PRECOMPILED HEADERS
+for how to remedy this\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If \(lqcan\(cqt use precompiled header\(rq has been incremented, see
+PRECOMPILED HEADERS\&.
+.RE
+.SS "Corrupt object files"
+.sp
+It should be noted that ccache is susceptible to general storage problems\&. If a bad object file sneaks into the cache for some reason, it will of course stay bad\&. Some possible reasons for erroneous object files are bad hardware (disk drive, disk controller, memory, etc), buggy drivers or file systems, a bad \fBprefix_command\fR or compiler wrapper\&. If this happens, the easiest way of fixing it is this:
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+Build so that the bad object file ends up in the build tree\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+Remove the bad object file from the build tree\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+Rebuild with
+\fBCCACHE_RECACHE\fR
+set\&.
+.RE
+.sp
+An alternative is to clear the whole cache with \fBccache \-C\fR if you don\(cqt mind losing other cached results\&.
+.sp
+There are no reported issues about ccache producing broken object files reproducibly\&. That doesn\(cqt mean it can\(cqt happen, so if you find a repeatable case, please report it\&.
+.SH "MORE INFORMATION"
+.sp
+Credits, mailing list information, bug reporting instructions, source code, etc, can be found on ccache\(cqs web site: https://ccache\&.samba\&.org\&.
+.SH "AUTHOR"
+.sp
+ccache was originally written by Andrew Tridgell and is currently developed and maintained by Joel Rosdahl\&. See AUTHORS\&.txt or AUTHORS\&.html and https://ccache\&.samba\&.org/credits\&.html for a list of contributors\&.
diff --git a/ccache.c b/ccache.c
new file mode 100644
index 0000000..de2b1e3
--- /dev/null
+++ b/ccache.c
@@ -0,0 +1,3476 @@
+// ccache -- a fast C/C++ compiler cache
+//
+// Copyright (C) 2002-2007 Andrew Tridgell
+// Copyright (C) 2009-2017 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+#include "compopt.h"
+#ifdef HAVE_GETOPT_LONG
+#include <getopt.h>
+#else
+#include "getopt_long.h"
+#endif
+#include "hashtable.h"
+#include "hashtable_itr.h"
+#include "hashutil.h"
+#include "language.h"
+#include "manifest.h"
+
+#define STRINGIFY(x) #x
+#define TO_STRING(x) STRINGIFY(x)
+
+static const char VERSION_TEXT[] =
+ MYNAME " version %s\n"
+ "\n"
+ "Copyright (C) 2002-2007 Andrew Tridgell\n"
+ "Copyright (C) 2009-2017 Joel Rosdahl\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or modify it under\n"
+ "the terms of the GNU General Public License as published by the Free Software\n"
+ "Foundation; either version 3 of the License, or (at your option) any later\n"
+ "version.\n";
+
+static const char USAGE_TEXT[] =
+ "Usage:\n"
+ " " MYNAME " [options]\n"
+ " " MYNAME " compiler [compiler options]\n"
+ " compiler [compiler options] (via symbolic link)\n"
+ "\n"
+ "Options:\n"
+ " -c, --cleanup delete old files and recalculate size counters\n"
+ " (normally not needed as this is done automatically)\n"
+ " -C, --clear clear the cache completely (except configuration)\n"
+ " -F, --max-files=N set maximum number of files in cache to N (use 0 for\n"
+ " no limit)\n"
+ " -M, --max-size=SIZE set maximum size of cache to SIZE (use 0 for no\n"
+ " limit); available suffixes: k, M, G, T (decimal) and\n"
+ " Ki, Mi, Gi, Ti (binary); default suffix: G\n"
+ " -o, --set-config=K=V set configuration key K to value V\n"
+ " -p, --print-config print current configuration options\n"
+ " -s, --show-stats show statistics summary\n"
+ " -z, --zero-stats zero statistics counters\n"
+ "\n"
+ " -h, --help print this help text\n"
+ " -V, --version print version and copyright information\n"
+ "\n"
+ "See also <https://ccache.samba.org>.\n";
+
+// Global configuration data.
+struct conf *conf = NULL;
+
+// Where to write configuration changes.
+char *primary_config_path = NULL;
+
+// Secondary, read-only configuration file (if any).
+char *secondary_config_path = NULL;
+
+// Current working directory taken from $PWD, or getcwd() if $PWD is bad.
+char *current_working_dir = NULL;
+
+// The original argument list.
+static struct args *orig_args;
+
+// The source file.
+static char *input_file;
+
+// The output file being compiled to.
+static char *output_obj;
+
+// The path to the dependency file (implicit or specified with -MF).
+static char *output_dep;
+
+// The path to the coverage file (implicit when using -ftest-coverage).
+static char *output_cov;
+
+// Diagnostic generation information (clang). Contains pathname if not NULL.
+static char *output_dia = NULL;
+
+// Split dwarf information (GCC 4.8 andup). Contains pathname if not NULL.
+static char *output_dwo = NULL;
+
+// Array for storing -arch options.
+#define MAX_ARCH_ARGS 10
+static size_t arch_args_size = 0;
+static char *arch_args[MAX_ARCH_ARGS] = {NULL};
+
+// Name (represented as a struct file_hash) of the file containing the cached
+// object code.
+static struct file_hash *cached_obj_hash;
+
+// Full path to the file containing the cached object code
+// (cachedir/a/b/cdef[...]-size.o).
+static char *cached_obj;
+
+// Full path to the file containing the standard error output
+// (cachedir/a/b/cdef[...]-size.stderr).
+static char *cached_stderr;
+
+// Full path to the file containing the dependency information
+// (cachedir/a/b/cdef[...]-size.d).
+static char *cached_dep;
+
+// Full path to the file containing the coverage information
+// (cachedir/a/b/cdef[...]-size.gcno).
+static char *cached_cov;
+
+// Full path to the file containing the diagnostic information (for clang)
+// (cachedir/a/b/cdef[...]-size.dia).
+static char *cached_dia;
+
+// Full path to the file containing the split dwarf (for GCC 4.8 and above)
+// (cachedir/a/b/cdef[...]-size.dwo).
+//
+// Contains NULL if -gsplit-dwarf is not given.
+static char *cached_dwo;
+
+// using_split_dwarf is true if "-gsplit-dwarf" is given to the compiler (GCC
+// 4.8 and up).
+bool using_split_dwarf = false;
+
+// Full path to the file containing the manifest
+// (cachedir/a/b/cdef[...]-size.manifest).
+static char *manifest_path;
+
+// Time of compilation. Used to see if include files have changed after
+// compilation.
+time_t time_of_compilation;
+
+// Files included by the preprocessor and their hashes/sizes. Key: file path.
+// Value: struct file_hash.
+static struct hashtable *included_files = NULL;
+
+// Uses absolute path for some include files.
+static bool has_absolute_include_headers = false;
+
+// List of headers to ignore.
+static char **ignore_headers;
+
+// Size of headers to ignore list.
+static size_t ignore_headers_len;
+
+// Is the compiler being asked to output debug info?
+static bool generating_debuginfo;
+
+// Is the compiler being asked to output dependencies?
+static bool generating_dependencies;
+
+// Is the compiler being asked to output coverage?
+static bool generating_coverage;
+
+// Relocating debuginfo in the format old=new.
+static char *debug_prefix_map = NULL;
+
+// Is the compiler being asked to output coverage data (.gcda) at runtime?
+static bool profile_arcs;
+
+// Name of the custom profile directory (default: object dirname).
+static char *profile_dir;
+
+// The name of the temporary preprocessed file.
+static char *i_tmpfile;
+
+// Are we compiling a .i or .ii file directly?
+static bool direct_i_file;
+
+// The name of the cpp stderr file.
+static char *cpp_stderr;
+
+// Full path to the statistics file in the subdirectory where the cached result
+// belongs (<cache_dir>/<x>/stats).
+char *stats_file = NULL;
+
+// Whether the output is a precompiled header.
+static bool output_is_precompiled_header = false;
+
+// Profile generation / usage information.
+static char *profile_dir = NULL;
+static bool profile_use = false;
+static bool profile_generate = false;
+
+// Whether we are using a precompiled header (either via -include, #include or
+// clang's -include-pch or -include-pth).
+static bool using_precompiled_header = false;
+
+// The .gch/.pch/.pth file used for compilation.
+static char *included_pch_file = NULL;
+
+// How long (in microseconds) to wait before breaking a stale lock.
+unsigned lock_staleness_limit = 2000000;
+
+enum fromcache_call_mode {
+ FROMCACHE_DIRECT_MODE,
+ FROMCACHE_CPP_MODE
+};
+
+struct pending_tmp_file {
+ char *path;
+ struct pending_tmp_file *next;
+};
+
+// Temporary files to remove at program exit.
+static struct pending_tmp_file *pending_tmp_files = NULL;
+
+#ifndef _WIN32
+static sigset_t fatal_signal_set;
+
+// PID of currently executing compiler that we have started, if any. 0 means no
+// ongoing compilation.
+static pid_t compiler_pid = 0;
+#endif
+
+// This is a string that identifies the current "version" of the hash sum
+// computed by ccache. If, for any reason, we want to force the hash sum to be
+// different for the same input in a new ccache version, we can just change
+// this string. A typical example would be if the format of one of the files
+// stored in the cache changes in a backwards-incompatible way.
+static const char HASH_PREFIX[] = "3";
+
+static void
+add_prefix(struct args *args, char *prefix_command)
+{
+ if (str_eq(prefix_command, "")) {
+ return;
+ }
+
+ struct args *prefix = args_init(0, NULL);
+ char *e = x_strdup(prefix_command);
+ char *saveptr = NULL;
+ for (char *tok = strtok_r(e, " ", &saveptr);
+ tok;
+ tok = strtok_r(NULL, " ", &saveptr)) {
+ char *p;
+
+ p = find_executable(tok, MYNAME);
+ if (!p) {
+ fatal("%s: %s", tok, strerror(errno));
+ }
+
+ args_add(prefix, p);
+ free(p);
+ }
+ free(e);
+
+ cc_log("Using command-line prefix %s", prefix_command);
+ for (int i = prefix->argc; i != 0; i--) {
+ args_add_prefix(args, prefix->argv[i-1]);
+ }
+ args_free(prefix);
+}
+
+// Something went badly wrong - just execute the real compiler.
+static void
+failed(void)
+{
+ assert(orig_args);
+
+ args_strip(orig_args, "--ccache-");
+ add_prefix(orig_args, conf->prefix_command);
+
+ cc_log("Failed; falling back to running the real compiler");
+ cc_log_argv("Executing ", orig_args->argv);
+ exitfn_call();
+ execv(orig_args->argv[0], orig_args->argv);
+ fatal("execv of %s failed: %s", orig_args->argv[0], strerror(errno));
+}
+
+static const char *
+temp_dir()
+{
+ static char *path = NULL;
+ if (path) {
+ return path; // Memoize
+ }
+ path = conf->temporary_dir;
+ if (str_eq(path, "")) {
+ path = format("%s/tmp", conf->cache_dir);
+ }
+ return path;
+}
+
+void
+block_signals(void)
+{
+#ifndef _WIN32
+ sigprocmask(SIG_BLOCK, &fatal_signal_set, NULL);
+#endif
+}
+
+void
+unblock_signals(void)
+{
+#ifndef _WIN32
+ sigset_t empty;
+ sigemptyset(&empty);
+ sigprocmask(SIG_SETMASK, &empty, NULL);
+#endif
+}
+
+static void
+add_pending_tmp_file(const char *path)
+{
+ block_signals();
+ struct pending_tmp_file *e = x_malloc(sizeof(*e));
+ e->path = x_strdup(path);
+ e->next = pending_tmp_files;
+ pending_tmp_files = e;
+ unblock_signals();
+}
+
+static void
+do_clean_up_pending_tmp_files(void)
+{
+ struct pending_tmp_file *p = pending_tmp_files;
+ while (p) {
+ // Can't call tmp_unlink here since its cc_log calls aren't signal safe.
+ unlink(p->path);
+ p = p->next;
+ // Leak p->path and p here because clean_up_pending_tmp_files needs to be
+ // signal safe.
+ }
+}
+
+static void
+clean_up_pending_tmp_files(void)
+{
+ block_signals();
+ do_clean_up_pending_tmp_files();
+ unblock_signals();
+}
+
+#ifndef _WIN32
+static void
+signal_handler(int signum)
+{
+ // Unregister handler for this signal so that we can send the signal to
+ // ourselves at the end of the handler.
+ signal(signum, SIG_DFL);
+
+ // If ccache was killed explicitly, then bring the compiler subprocess (if
+ // any) with us as well.
+ if (signum == SIGTERM
+ && compiler_pid != 0
+ && waitpid(compiler_pid, NULL, WNOHANG) == 0) {
+ kill(compiler_pid, signum);
+ }
+
+ do_clean_up_pending_tmp_files();
+
+ if (compiler_pid != 0) {
+ // Wait for compiler subprocess to exit before we snuff it.
+ waitpid(compiler_pid, NULL, 0);
+ }
+
+ // Resend signal to ourselves to exit properly after returning from the
+ // handler.
+ kill(getpid(), signum);
+}
+
+static void
+register_signal_handler(int signum)
+{
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = signal_handler;
+ act.sa_mask = fatal_signal_set;
+#ifdef SA_RESTART
+ act.sa_flags = SA_RESTART;
+#endif
+ sigaction(signum, &act, NULL);
+}
+
+static void
+set_up_signal_handlers(void)
+{
+ sigemptyset(&fatal_signal_set);
+ sigaddset(&fatal_signal_set, SIGINT);
+ sigaddset(&fatal_signal_set, SIGTERM);
+#ifdef SIGHUP
+ sigaddset(&fatal_signal_set, SIGHUP);
+#endif
+#ifdef SIGQUIT
+ sigaddset(&fatal_signal_set, SIGQUIT);
+#endif
+
+ register_signal_handler(SIGINT);
+ register_signal_handler(SIGTERM);
+#ifdef SIGHUP
+ register_signal_handler(SIGHUP);
+#endif
+#ifdef SIGQUIT
+ register_signal_handler(SIGQUIT);
+#endif
+}
+#endif // _WIN32
+
+static void
+clean_up_internal_tempdir(void)
+{
+ time_t now = time(NULL);
+ struct stat st;
+ if (x_stat(conf->cache_dir, &st) != 0 || st.st_mtime + 3600 >= now) {
+ // No cleanup needed.
+ return;
+ }
+
+ update_mtime(conf->cache_dir);
+
+ DIR *dir = opendir(temp_dir());
+ if (!dir) {
+ return;
+ }
+
+ struct dirent *entry;
+ while ((entry = readdir(dir))) {
+ if (str_eq(entry->d_name, ".") || str_eq(entry->d_name, "..")) {
+ continue;
+ }
+
+ char *path = format("%s/%s", temp_dir(), entry->d_name);
+ if (x_lstat(path, &st) == 0 && st.st_mtime + 3600 < now) {
+ tmp_unlink(path);
+ }
+ free(path);
+ }
+
+ closedir(dir);
+}
+
+static char *
+get_current_working_dir(void)
+{
+ if (!current_working_dir) {
+ char *cwd = get_cwd();
+ if (cwd) {
+ current_working_dir = x_realpath(cwd);
+ free(cwd);
+ }
+ if (!current_working_dir) {
+ cc_log("Unable to determine current working directory: %s",
+ strerror(errno));
+ failed();
+ }
+ }
+ return current_working_dir;
+}
+
+// Transform a name to a full path into the cache directory, creating needed
+// sublevels if needed. Caller frees.
+static char *
+get_path_in_cache(const char *name, const char *suffix)
+{
+ char *path = x_strdup(conf->cache_dir);
+ for (unsigned i = 0; i < conf->cache_dir_levels; ++i) {
+ char *p = format("%s/%c", path, name[i]);
+ free(path);
+ path = p;
+ }
+
+ char *result =
+ format("%s/%s%s", path, name + conf->cache_dir_levels, suffix);
+ free(path);
+ return result;
+}
+
+// This function hashes an include file and stores the path and hash in the
+// global included_files variable. If the include file is a PCH, cpp_hash is
+// also updated. Takes over ownership of path.
+static void
+remember_include_file(char *path, struct mdfour *cpp_hash, bool system)
+{
+ size_t path_len = strlen(path);
+ if (path_len >= 2 && (path[0] == '<' && path[path_len - 1] == '>')) {
+ // Typically <built-in> or <command-line>.
+ goto ignore;
+ }
+
+ if (str_eq(path, input_file)) {
+ // Don't remember the input file.
+ goto ignore;
+ }
+
+ if (system && (conf->sloppiness & SLOPPY_NO_SYSTEM_HEADERS)) {
+ // Don't remember this system header.
+ goto ignore;
+ }
+
+ if (hashtable_search(included_files, path)) {
+ // Already known include file.
+ goto ignore;
+ }
+
+#ifdef _WIN32
+ // stat fails on directories on win32.
+ DWORD attributes = GetFileAttributes(path);
+ if (attributes != INVALID_FILE_ATTRIBUTES &&
+ attributes & FILE_ATTRIBUTE_DIRECTORY) {
+ goto ignore;
+ }
+#endif
+
+ struct stat st;
+ if (x_stat(path, &st) != 0) {
+ goto failure;
+ }
+ if (S_ISDIR(st.st_mode)) {
+ // Ignore directory, typically $PWD.
+ goto ignore;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ // Device, pipe, socket or other strange creature.
+ cc_log("Non-regular include file %s", path);
+ goto failure;
+ }
+
+ // Canonicalize path for comparison; clang uses ./header.h.
+ char *canonical = path;
+ size_t canonical_len = path_len;
+ if (canonical[0] == '.' && canonical[1] == '/') {
+ canonical += 2;
+ canonical_len -= 2;
+ }
+
+ for (size_t i = 0; i < ignore_headers_len; i++) {
+ char *ignore = ignore_headers[i];
+ size_t ignore_len = strlen(ignore);
+ if (ignore_len > canonical_len) {
+ continue;
+ }
+ if (strncmp(canonical, ignore, ignore_len) == 0
+ && (ignore[ignore_len-1] == DIR_DELIM_CH
+ || canonical[ignore_len] == DIR_DELIM_CH
+ || canonical[ignore_len] == '\0')) {
+ goto ignore;
+ }
+ }
+
+ if (!(conf->sloppiness & SLOPPY_INCLUDE_FILE_MTIME)
+ && st.st_mtime >= time_of_compilation) {
+ cc_log("Include file %s too new", path);
+ goto failure;
+ }
+
+ if (!(conf->sloppiness & SLOPPY_INCLUDE_FILE_CTIME)
+ && st.st_ctime >= time_of_compilation) {
+ cc_log("Include file %s ctime too new", path);
+ goto failure;
+ }
+
+ // Let's hash the include file content.
+ struct mdfour fhash;
+ hash_start(&fhash);
+
+ bool is_pch = is_precompiled_header(path);
+ if (is_pch) {
+ if (!hash_file(&fhash, path)) {
+ goto failure;
+ }
+ struct file_hash pch_hash;
+ hash_result_as_bytes(&fhash, pch_hash.hash);
+ pch_hash.size = fhash.totalN;
+ hash_delimiter(cpp_hash, "pch_hash");
+ hash_buffer(cpp_hash, pch_hash.hash, sizeof(pch_hash.hash));
+ }
+
+ if (conf->direct_mode) {
+ if (!is_pch) { // else: the file has already been hashed.
+ char *source = NULL;
+ size_t size;
+ if (st.st_size > 0) {
+ if (!read_file(path, st.st_size, &source, &size)) {
+ goto failure;
+ }
+ } else {
+ source = x_strdup("");
+ size = 0;
+ }
+
+ int result = hash_source_code_string(conf, &fhash, source, size, path);
+ free(source);
+ if (result & HASH_SOURCE_CODE_ERROR
+ || result & HASH_SOURCE_CODE_FOUND_TIME) {
+ goto failure;
+ }
+ }
+
+ struct file_hash *h = x_malloc(sizeof(*h));
+ hash_result_as_bytes(&fhash, h->hash);
+ h->size = fhash.totalN;
+ hashtable_insert(included_files, path, h);
+ } else {
+ free(path);
+ }
+
+ return;
+
+failure:
+ if (conf->direct_mode) {
+ cc_log("Disabling direct mode");
+ conf->direct_mode = false;
+ }
+ // Fall through.
+ignore:
+ free(path);
+}
+
+// Make a relative path from current working directory to path if path is under
+// the base directory. Takes over ownership of path. Caller frees.
+static char *
+make_relative_path(char *path)
+{
+ if (str_eq(conf->base_dir, "") || !str_startswith(path, conf->base_dir)) {
+ return path;
+ }
+
+#ifdef _WIN32
+ if (path[0] == '/') {
+ path++; // Skip leading slash.
+ }
+#endif
+
+ // x_realpath only works for existing paths, so if path doesn't exist, try
+ // dirname(path) and assemble the path afterwards. We only bother to try
+ // canonicalizing one of these two paths since a compiler path argument
+ // typically only makes sense if path or dirname(path) exists.
+ char *path_suffix = NULL;
+ struct stat st;
+ if (stat(path, &st) != 0) {
+ // path doesn't exist.
+ char *dir = dirname(path);
+ if (stat(dir, &st) != 0) {
+ // And neither does its parent directory, so no action to take.
+ free(dir);
+ return path;
+ }
+ free(dir);
+ path_suffix = basename(path);
+ char *p = path;
+ path = dirname(path);
+ free(p);
+ }
+
+ char *canon_path = x_realpath(path);
+ if (canon_path) {
+ free(path);
+ char *relpath = get_relative_path(get_current_working_dir(), canon_path);
+ free(canon_path);
+ if (path_suffix) {
+ path = format("%s/%s", relpath, path_suffix);
+ free(relpath);
+ free(path_suffix);
+ return path;
+ } else {
+ return relpath;
+ }
+ } else {
+ // path doesn't exist, so leave it as it is.
+ free(path_suffix);
+ return path;
+ }
+}
+
+// This function reads and hashes a file. While doing this, it also does these
+// things:
+//
+// - Makes include file paths for which the base directory is a prefix relative
+// when computing the hash sum.
+// - Stores the paths and hashes of included files in the global variable
+// included_files.
+static bool
+process_preprocessed_file(struct mdfour *hash, const char *path)
+{
+ char *data;
+ size_t size;
+ if (!read_file(path, 0, &data, &size)) {
+ return false;
+ }
+
+ ignore_headers = NULL;
+ ignore_headers_len = 0;
+ if (!str_eq(conf->ignore_headers_in_manifest, "")) {
+ char *header, *p, *q, *saveptr = NULL;
+ p = x_strdup(conf->ignore_headers_in_manifest);
+ q = p;
+ while ((header = strtok_r(q, PATH_DELIM, &saveptr))) {
+ ignore_headers = x_realloc(ignore_headers,
+ (ignore_headers_len+1) * sizeof(char *));
+ ignore_headers[ignore_headers_len++] = x_strdup(header);
+ q = NULL;
+ }
+ free(p);
+ }
+
+ if (!included_files) {
+ included_files = create_hashtable(1000, hash_from_string, strings_equal);
+ }
+
+ // Bytes between p and q are pending to be hashed.
+ char *p = data;
+ char *q = data;
+ char *end = data + size;
+
+ // There must be at least 7 characters (# 1 "x") left to potentially find an
+ // include file path.
+ while (q < end - 7) {
+ // Check if we look at a line containing the file name of an included file.
+ // At least the following formats exist (where N is a positive integer):
+ //
+ // GCC:
+ //
+ // # N "file"
+ // # N "file" N
+ // #pragma GCC pch_preprocess "file"
+ //
+ // HP's compiler:
+ //
+ // #line N "file"
+ //
+ // AIX's compiler:
+ //
+ // #line N "file"
+ // #line N
+ //
+ // Note that there may be other lines starting with '#' left after
+ // preprocessing as well, for instance "# pragma".
+ if (q[0] == '#'
+ // GCC:
+ && ((q[1] == ' ' && q[2] >= '0' && q[2] <= '9')
+ // GCC precompiled header:
+ || (q[1] == 'p'
+ && str_startswith(&q[2], "ragma GCC pch_preprocess "))
+ // HP/AIX:
+ || (q[1] == 'l' && q[2] == 'i' && q[3] == 'n' && q[4] == 'e'
+ && q[5] == ' '))
+ && (q == data || q[-1] == '\n')) {
+ // Workarounds for preprocessor linemarker bugs in GCC version 6.
+ if (q[2] == '3') {
+ if (str_startswith(q, "# 31 \"<command-line>\"\n")) {
+ // Bogus extra line with #31, after the regular #1: Ignore the whole
+ // line, and continue parsing.
+ hash_buffer(hash, p, q - p);
+ while (q < end && *q != '\n') {
+ q++;
+ }
+ q++;
+ p = q;
+ continue;
+ } else if (str_startswith(q, "# 32 \"<command-line>\" 2\n")) {
+ // Bogus wrong line with #32, instead of regular #1: Replace the line
+ // number with the usual one.
+ hash_buffer(hash, p, q - p);
+ q += 1;
+ q[0] = '#';
+ q[1] = ' ';
+ q[2] = '1';
+ p = q;
+ }
+ }
+
+ while (q < end && *q != '"' && *q != '\n') {
+ q++;
+ }
+ if (q < end && *q == '\n') {
+ // A newline before the quotation mark -> no match.
+ continue;
+ }
+ q++;
+ if (q >= end) {
+ cc_log("Failed to parse included file path");
+ free(data);
+ return false;
+ }
+ // q points to the beginning of an include file path
+ hash_buffer(hash, p, q - p);
+ p = q;
+ while (q < end && *q != '"') {
+ q++;
+ }
+ // Look for preprocessor flags, after the "filename".
+ bool system = false;
+ char *r = q + 1;
+ while (r < end && *r != '\n') {
+ if (*r == '3') { // System header.
+ system = true;
+ }
+ r++;
+ }
+ // p and q span the include file path.
+ char *inc_path = x_strndup(p, q - p);
+ if (!has_absolute_include_headers) {
+ has_absolute_include_headers = is_absolute_path(inc_path);
+ }
+ inc_path = make_relative_path(inc_path);
+
+ bool should_hash_inc_path = true;
+ if (!conf->hash_dir) {
+ char *cwd = gnu_getcwd();
+ if (str_startswith(inc_path, cwd) && str_endswith(inc_path, "//")) {
+ // When compiling with -g or similar, GCC adds the absolute path to
+ // CWD like this:
+ //
+ // # 1 "CWD//"
+ //
+ // If the user has opted out of including the CWD in the hash, don't
+ // hash it. See also how debug_prefix_map is handled.
+ should_hash_inc_path = false;
+ }
+ free(cwd);
+ }
+ if (should_hash_inc_path) {
+ hash_string(hash, inc_path);
+ }
+
+ remember_include_file(inc_path, hash, system);
+ p = q; // Everything of interest between p and q has been hashed now.
+ } else if (q[0] == '.' && q[1] == 'i' && q[2] == 'n' && q[3] == 'c'
+ && q[4] == 'b' && q[5] == 'i' && q[6] == 'n') {
+ // An assembler .incbin statement (which could be part of inline
+ // assembly) refers to an external file. If the file changes, the hash
+ // should change as well, but finding out what file to hash is too hard
+ // for ccache, so just bail out.
+ cc_log("Found unsupported .incbin directive in source code");
+ stats_update(STATS_UNSUPPORTED_DIRECTIVE);
+ failed();
+ } else {
+ q++;
+ }
+ }
+
+ hash_buffer(hash, p, (end - p));
+ free(data);
+
+ // Explicitly check the .gch/.pch/.pth file, Clang does not include any
+ // mention of it in the preprocessed output.
+ if (included_pch_file) {
+ char *path = x_strdup(included_pch_file);
+ path = make_relative_path(path);
+ hash_string(hash, path);
+ remember_include_file(path, hash, false);
+ }
+
+ return true;
+}
+
+// Replace absolute paths with relative paths in the provided dependency file.
+static void
+use_relative_paths_in_depfile(const char *depfile)
+{
+ if (str_eq(conf->base_dir, "")) {
+ cc_log("Base dir not set, skip using relative paths");
+ return; // nothing to do
+ }
+ if (!has_absolute_include_headers) {
+ cc_log("No absolute path for included files found, skip using relative"
+ " paths");
+ return; // nothing to do
+ }
+
+ FILE *f;
+ f = fopen(depfile, "r");
+ if (!f) {
+ cc_log("Cannot open dependency file: %s (%s)", depfile, strerror(errno));
+ return;
+ }
+
+ char *tmp_file = format("%s.tmp", depfile);
+ FILE *tmpf = create_tmp_file(&tmp_file, "w");
+
+ bool result = false;
+ char buf[10000];
+ while (fgets(buf, sizeof(buf), f) && !ferror(tmpf)) {
+ char *saveptr;
+ char *token = strtok_r(buf, " \t", &saveptr);
+ while (token) {
+ char *relpath;
+ if (is_absolute_path(token) && str_startswith(token, conf->base_dir)) {
+ relpath = make_relative_path(x_strdup(token));
+ result = true;
+ } else {
+ relpath = token;
+ }
+ if (token != buf) { // This is a dependency file.
+ fputc(' ', tmpf);
+ }
+ fputs(relpath, tmpf);
+ if (relpath != token) {
+ free(relpath);
+ }
+ token = strtok_r(NULL, " \t", &saveptr);
+ }
+ }
+
+ if (ferror(f)) {
+ cc_log("Error reading dependency file: %s, skip relative path usage",
+ depfile);
+ result = false;
+ goto out;
+ }
+ if (ferror(tmpf)) {
+ cc_log("Error writing temporary dependency file: %s, skip relative path"
+ " usage", tmp_file);
+ result = false;
+ goto out;
+ }
+
+out:
+ fclose(tmpf);
+ fclose(f);
+ if (result) {
+ if (x_rename(tmp_file, depfile) != 0) {
+ cc_log("Error renaming dependency file: %s -> %s (%s), skip relative"
+ " path usage", tmp_file, depfile, strerror(errno));
+ result = false;
+ } else {
+ cc_log("Renamed dependency file: %s -> %s", tmp_file, depfile);
+ }
+ }
+ if (!result) {
+ cc_log("Removing temporary dependency file: %s", tmp_file);
+ x_unlink(tmp_file);
+ }
+ free(tmp_file);
+}
+
+// Copy or link a file to the cache.
+static void
+put_file_in_cache(const char *source, const char *dest)
+{
+ assert(!conf->read_only);
+ assert(!conf->read_only_direct);
+
+ bool do_link = conf->hard_link && !conf->compression;
+ if (do_link) {
+ x_unlink(dest);
+ int ret = link(source, dest);
+ if (ret != 0) {
+ cc_log("Failed to link %s to %s: %s", source, dest, strerror(errno));
+ cc_log("Falling back to copying");
+ do_link = false;
+ }
+ }
+ if (!do_link) {
+ int ret = copy_file(
+ source, dest, conf->compression ? conf->compression_level : 0);
+ if (ret != 0) {
+ cc_log("Failed to copy %s to %s: %s", source, dest, strerror(errno));
+ stats_update(STATS_ERROR);
+ failed();
+ }
+ }
+
+ cc_log("Stored in cache: %s -> %s", source, dest);
+
+ struct stat st;
+ if (x_stat(dest, &st) != 0) {
+ stats_update(STATS_ERROR);
+ failed();
+ }
+ stats_update_size(file_size(&st), 1);
+}
+
+// Copy or link a file from the cache.
+static void
+get_file_from_cache(const char *source, const char *dest)
+{
+ int ret;
+ bool do_link = conf->hard_link && !file_is_compressed(source);
+ if (do_link) {
+ x_unlink(dest);
+ ret = link(source, dest);
+ } else {
+ ret = copy_file(source, dest, 0);
+ }
+
+ if (ret == -1) {
+ if (errno == ENOENT || errno == ESTALE) {
+ // Someone removed the file just before we began copying?
+ cc_log("Cache file %s just disappeared from cache", source);
+ stats_update(STATS_MISSING);
+ } else {
+ cc_log("Failed to %s %s to %s: %s",
+ do_link ? "link" : "copy",
+ source,
+ dest,
+ strerror(errno));
+ stats_update(STATS_ERROR);
+ }
+
+ // If there was trouble getting a file from the cached result, wipe the
+ // whole cached result for consistency.
+ x_unlink(cached_stderr);
+ x_unlink(cached_obj);
+ x_unlink(cached_dep);
+ x_unlink(cached_dia);
+
+ failed();
+ }
+
+ cc_log("Created from cache: %s -> %s", source, dest);
+}
+
+// Send cached stderr, if any, to stderr.
+static void
+send_cached_stderr(void)
+{
+ int fd_stderr = open(cached_stderr, O_RDONLY | O_BINARY);
+ if (fd_stderr != -1) {
+ copy_fd(fd_stderr, 2);
+ close(fd_stderr);
+ }
+}
+
+// Create or update the manifest file.
+void update_manifest_file(void)
+{
+ if (!conf->direct_mode
+ || !included_files
+ || conf->read_only
+ || conf->read_only_direct) {
+ return;
+ }
+
+ struct stat st;
+ size_t old_size = 0; // in bytes
+ if (stat(manifest_path, &st) == 0) {
+ old_size = file_size(&st);
+ }
+ if (manifest_put(manifest_path, cached_obj_hash, included_files)) {
+ cc_log("Added object file hash to %s", manifest_path);
+ update_mtime(manifest_path);
+ if (x_stat(manifest_path, &st) == 0) {
+ stats_update_size(file_size(&st) - old_size, old_size == 0 ? 1 : 0);
+ }
+ } else {
+ cc_log("Failed to add object file hash to %s", manifest_path);
+ }
+}
+
+// Run the real compiler and put the result in cache.
+static void
+to_cache(struct args *args)
+{
+ char *tmp_stdout = format("%s.tmp.stdout", cached_obj);
+ int tmp_stdout_fd = create_tmp_fd(&tmp_stdout);
+ char *tmp_stderr = format("%s.tmp.stderr", cached_obj);
+ int tmp_stderr_fd = create_tmp_fd(&tmp_stderr);
+
+ char *tmp_cov;
+ if (generating_coverage) {
+ char *tmp_aux;
+ // GCC has some funny rule about max extension length.
+ if (strlen(get_extension(output_obj)) < 6) {
+ tmp_aux = remove_extension(output_obj);
+ } else {
+ tmp_aux = x_strdup(output_obj);
+ }
+ tmp_cov = format("%s.gcno", tmp_aux);
+ free(tmp_aux);
+ } else {
+ tmp_cov = NULL;
+ }
+
+ // GCC (at least 4.8 and 4.9) forms the .dwo file name by removing everything
+ // after (and including) the last "." from the object file name and then
+ // appending ".dwo".
+ char *tmp_dwo = NULL;
+ if (using_split_dwarf) {
+ char *base_name = remove_extension(output_obj);
+ tmp_dwo = format("%s.dwo", base_name);
+ free(base_name);
+ }
+
+ args_add(args, "-o");
+ args_add(args, output_obj);
+
+ if (output_dia) {
+ args_add(args, "--serialize-diagnostics");
+ args_add(args, output_dia);
+ }
+
+ // Turn off DEPENDENCIES_OUTPUT when running cc1, because otherwise it will
+ // emit a line like this:
+ //
+ // tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i
+ x_unsetenv("DEPENDENCIES_OUTPUT");
+
+ if (conf->run_second_cpp) {
+ args_add(args, input_file);
+ } else {
+ args_add(args, i_tmpfile);
+ }
+
+ cc_log("Running real compiler");
+ int status =
+ execute(args->argv, tmp_stdout_fd, tmp_stderr_fd, &compiler_pid);
+ args_pop(args, 3);
+
+ struct stat st;
+ if (x_stat(tmp_stdout, &st) != 0) {
+ // The stdout file was removed - cleanup in progress? Better bail out.
+ stats_update(STATS_MISSING);
+ tmp_unlink(tmp_stdout);
+ tmp_unlink(tmp_stderr);
+ if (tmp_cov) {
+ tmp_unlink(tmp_cov);
+ }
+ if (tmp_dwo) {
+ tmp_unlink(tmp_dwo);
+ }
+ failed();
+ }
+ if (st.st_size != 0) {
+ cc_log("Compiler produced stdout");
+ stats_update(STATS_STDOUT);
+ tmp_unlink(tmp_stdout);
+ tmp_unlink(tmp_stderr);
+ if (tmp_cov) {
+ tmp_unlink(tmp_cov);
+ }
+ if (tmp_dwo) {
+ tmp_unlink(tmp_dwo);
+ }
+ failed();
+ }
+ tmp_unlink(tmp_stdout);
+
+ // Merge stderr from the preprocessor (if any) and stderr from the real
+ // compiler into tmp_stderr.
+ if (cpp_stderr) {
+ char *tmp_stderr2 = format("%s.2", tmp_stderr);
+ if (x_rename(tmp_stderr, tmp_stderr2)) {
+ cc_log("Failed to rename %s to %s: %s", tmp_stderr, tmp_stderr2,
+ strerror(errno));
+ failed();
+ }
+
+ int fd_cpp_stderr = open(cpp_stderr, O_RDONLY | O_BINARY);
+ if (fd_cpp_stderr == -1) {
+ cc_log("Failed opening %s: %s", cpp_stderr, strerror(errno));
+ failed();
+ }
+
+ int fd_real_stderr = open(tmp_stderr2, O_RDONLY | O_BINARY);
+ if (fd_real_stderr == -1) {
+ cc_log("Failed opening %s: %s", tmp_stderr2, strerror(errno));
+ failed();
+ }
+
+ int fd_result =
+ open(tmp_stderr, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ if (fd_result == -1) {
+ cc_log("Failed opening %s: %s", tmp_stderr, strerror(errno));
+ failed();
+ }
+
+ copy_fd(fd_cpp_stderr, fd_result);
+ copy_fd(fd_real_stderr, fd_result);
+ close(fd_cpp_stderr);
+ close(fd_real_stderr);
+ close(fd_result);
+ tmp_unlink(tmp_stderr2);
+ free(tmp_stderr2);
+ }
+
+ if (status != 0) {
+ cc_log("Compiler gave exit status %d", status);
+ stats_update(STATS_STATUS);
+
+ int fd = open(tmp_stderr, O_RDONLY | O_BINARY);
+ if (fd != -1) {
+ // We can output stderr immediately instead of rerunning the compiler.
+ copy_fd(fd, 2);
+ close(fd);
+ tmp_unlink(tmp_stderr);
+
+ x_exit(status);
+ }
+
+ tmp_unlink(tmp_stderr);
+ if (tmp_cov) {
+ tmp_unlink(tmp_cov);
+ }
+ if (tmp_dwo) {
+ tmp_unlink(tmp_dwo);
+ }
+
+ failed();
+ }
+
+ if (stat(output_obj, &st) != 0) {
+ cc_log("Compiler didn't produce an object file");
+ stats_update(STATS_NOOUTPUT);
+ failed();
+ }
+ if (st.st_size == 0) {
+ cc_log("Compiler produced an empty object file");
+ stats_update(STATS_EMPTYOUTPUT);
+ failed();
+ }
+
+ if (using_split_dwarf) {
+ if (stat(tmp_dwo, &st) != 0) {
+ cc_log("Compiler didn't produce a split dwarf file");
+ stats_update(STATS_NOOUTPUT);
+ failed();
+ }
+ if (st.st_size == 0) {
+ cc_log("Compiler produced an empty split dwarf file");
+ stats_update(STATS_EMPTYOUTPUT);
+ failed();
+ }
+ }
+
+ if (x_stat(tmp_stderr, &st) != 0) {
+ stats_update(STATS_ERROR);
+ failed();
+ }
+ if (st.st_size > 0) {
+ if (move_uncompressed_file(
+ tmp_stderr, cached_stderr,
+ conf->compression ? conf->compression_level : 0) != 0) {
+ cc_log("Failed to move %s to %s: %s", tmp_stderr, cached_stderr,
+ strerror(errno));
+ stats_update(STATS_ERROR);
+ failed();
+ }
+ cc_log("Stored in cache: %s", cached_stderr);
+ if (!conf->compression
+ // If the file was compressed, obtain the size again:
+ || x_stat(cached_stderr, &st) == 0) {
+ stats_update_size(file_size(&st), 1);
+ }
+ } else {
+ tmp_unlink(tmp_stderr);
+ if (conf->recache) {
+ // If recaching, we need to remove any previous .stderr.
+ x_unlink(cached_stderr);
+ }
+ }
+
+ if (generating_coverage) {
+ // GCC won't generate notes if there is no code.
+ if (stat(tmp_cov, &st) != 0 && errno == ENOENT) {
+ FILE *f = fopen(cached_cov, "wb");
+ cc_log("Creating placeholder: %s", cached_cov);
+ if (!f) {
+ cc_log("Failed to create %s: %s", cached_cov, strerror(errno));
+ stats_update(STATS_ERROR);
+ failed();
+ }
+ fclose(f);
+ stats_update_size(0, 1);
+ } else {
+ put_file_in_cache(tmp_cov, cached_cov);
+ }
+ }
+
+ if (output_dia) {
+ if (x_stat(output_dia, &st) != 0) {
+ stats_update(STATS_ERROR);
+ failed();
+ }
+ if (st.st_size > 0) {
+ put_file_in_cache(output_dia, cached_dia);
+ }
+ }
+
+ put_file_in_cache(output_obj, cached_obj);
+
+ if (using_split_dwarf) {
+ assert(tmp_dwo);
+ assert(cached_dwo);
+ put_file_in_cache(tmp_dwo, cached_dwo);
+ }
+
+ if (generating_dependencies) {
+ use_relative_paths_in_depfile(output_dep);
+ put_file_in_cache(output_dep, cached_dep);
+ }
+ stats_update(STATS_TOCACHE);
+
+ // Make sure we have a CACHEDIR.TAG in the cache part of cache_dir. This can
+ // be done almost anywhere, but we might as well do it near the end as we
+ // save the stat call if we exit early.
+ {
+ char *first_level_dir = dirname(stats_file);
+ if (create_cachedirtag(first_level_dir) != 0) {
+ cc_log("Failed to create %s/CACHEDIR.TAG (%s)\n",
+ first_level_dir, strerror(errno));
+ stats_update(STATS_ERROR);
+ failed();
+ }
+ free(first_level_dir);
+
+ // Remove any CACHEDIR.TAG on the cache_dir level where it was located in
+ // previous ccache versions.
+ if (getpid() % 1000 == 0) {
+ char *path = format("%s/CACHEDIR.TAG", conf->cache_dir);
+ x_unlink(path);
+ free(path);
+ }
+ }
+
+ // Everything OK.
+ send_cached_stderr();
+ update_manifest_file();
+
+ free(tmp_stderr);
+ free(tmp_stdout);
+ free(tmp_cov);
+ free(tmp_dwo);
+}
+
+// Find the object file name by running the compiler in preprocessor mode.
+// Returns the hash as a heap-allocated hex string.
+static struct file_hash *
+get_object_name_from_cpp(struct args *args, struct mdfour *hash)
+{
+ time_of_compilation = time(NULL);
+
+ char *path_stderr = format("%s/tmp.cpp_stderr", temp_dir());
+ int path_stderr_fd = create_tmp_fd(&path_stderr);
+ add_pending_tmp_file(path_stderr);
+
+ char *path_stdout;
+ int status;
+ if (direct_i_file) {
+ // We are compiling a .i or .ii file - that means we can skip the cpp stage
+ // and directly form the correct i_tmpfile.
+ path_stdout = input_file;
+ status = 0;
+ } else {
+ // Run cpp on the input file to obtain the .i.
+
+ // Limit the basename to 10 characters in order to cope with filesystem with
+ // small maximum filename length limits.
+ char *input_base = basename(input_file);
+ char *tmp = strchr(input_base, '.');
+ if (tmp) {
+ *tmp = 0;
+ }
+ if (strlen(input_base) > 10) {
+ input_base[10] = 0;
+ }
+
+ path_stdout = format("%s/%s.stdout", temp_dir(), input_base);
+ int path_stdout_fd = create_tmp_fd(&path_stdout);
+ add_pending_tmp_file(path_stdout);
+
+ int args_added = 2;
+ args_add(args, "-E");
+ if (conf->keep_comments_cpp) {
+ args_add(args, "-C");
+ args_added = 3;
+ }
+ args_add(args, input_file);
+ add_prefix(args, conf->prefix_command_cpp);
+ cc_log("Running preprocessor");
+ status = execute(args->argv, path_stdout_fd, path_stderr_fd, &compiler_pid);
+ args_pop(args, args_added);
+ }
+
+ if (status != 0) {
+ cc_log("Preprocessor gave exit status %d", status);
+ stats_update(STATS_PREPROCESSOR);
+ failed();
+ }
+
+ if (conf->unify) {
+ // When we are doing the unifying tricks we need to include the input file
+ // name in the hash to get the warnings right.
+ hash_delimiter(hash, "unifyfilename");
+ hash_string(hash, input_file);
+
+ hash_delimiter(hash, "unifycpp");
+ if (unify_hash(hash, path_stdout) != 0) {
+ stats_update(STATS_ERROR);
+ cc_log("Failed to unify %s", path_stdout);
+ failed();
+ }
+ } else {
+ hash_delimiter(hash, "cpp");
+ if (!process_preprocessed_file(hash, path_stdout)) {
+ stats_update(STATS_ERROR);
+ failed();
+ }
+ }
+
+ hash_delimiter(hash, "cppstderr");
+ if (!hash_file(hash, path_stderr)) {
+ fatal("Failed to open %s: %s", path_stderr, strerror(errno));
+ }
+
+ if (direct_i_file) {
+ i_tmpfile = input_file;
+ } else {
+ // i_tmpfile needs the proper cpp_extension for the compiler to do its
+ // thing correctly
+ i_tmpfile = format("%s.%s", path_stdout, conf->cpp_extension);
+ x_rename(path_stdout, i_tmpfile);
+ add_pending_tmp_file(i_tmpfile);
+ }
+
+ if (conf->run_second_cpp) {
+ free(path_stderr);
+ } else {
+ // If we are using the CPP trick, we need to remember this stderr data and
+ // output it just before the main stderr from the compiler pass.
+ cpp_stderr = path_stderr;
+ hash_delimiter(hash, "runsecondcpp");
+ hash_string(hash, "false");
+ }
+
+ struct file_hash *result = x_malloc(sizeof(*result));
+ hash_result_as_bytes(hash, result->hash);
+ result->size = hash->totalN;
+ return result;
+}
+
+static void
+update_cached_result_globals(struct file_hash *hash)
+{
+ char *object_name = format_hash_as_string(hash->hash, hash->size);
+ cached_obj_hash = hash;
+ cached_obj = get_path_in_cache(object_name, ".o");
+ cached_stderr = get_path_in_cache(object_name, ".stderr");
+ cached_dep = get_path_in_cache(object_name, ".d");
+ cached_cov = get_path_in_cache(object_name, ".gcno");
+ cached_dia = get_path_in_cache(object_name, ".dia");
+
+ if (using_split_dwarf) {
+ cached_dwo = get_path_in_cache(object_name, ".dwo");
+ } else {
+ cached_dwo = NULL;
+ }
+
+ stats_file = format("%s/%c/stats", conf->cache_dir, object_name[0]);
+ free(object_name);
+}
+
+// Hash mtime or content of a file, or the output of a command, according to
+// the CCACHE_COMPILERCHECK setting.
+static void
+hash_compiler(struct mdfour *hash, struct stat *st, const char *path,
+ bool allow_command)
+{
+ if (str_eq(conf->compiler_check, "none")) {
+ // Do nothing.
+ } else if (str_eq(conf->compiler_check, "mtime")) {
+ hash_delimiter(hash, "cc_mtime");
+ hash_int(hash, st->st_size);
+ hash_int(hash, st->st_mtime);
+ } else if (str_startswith(conf->compiler_check, "string:")) {
+ hash_delimiter(hash, "cc_hash");
+ hash_string(hash, conf->compiler_check + strlen("string:"));
+ } else if (str_eq(conf->compiler_check, "content") || !allow_command) {
+ hash_delimiter(hash, "cc_content");
+ hash_file(hash, path);
+ } else { // command string
+ if (!hash_multicommand_output(
+ hash, conf->compiler_check, orig_args->argv[0])) {
+ fatal("Failure running compiler check command: %s", conf->compiler_check);
+ }
+ }
+}
+
+// Note that these compiler checks are unreliable, so nothing should
+// hard-depend on them.
+
+static bool
+compiler_is_clang(struct args *args)
+{
+ char *name = basename(args->argv[0]);
+ bool result = strstr(name, "clang") != NULL;
+ free(name);
+ return result;
+}
+
+static bool
+compiler_is_gcc(struct args *args)
+{
+ char *name = basename(args->argv[0]);
+ bool result = strstr(name, "gcc") || strstr(name, "g++");
+ free(name);
+ return result;
+}
+
+// Update a hash sum with information common for the direct and preprocessor
+// modes.
+static void
+calculate_common_hash(struct args *args, struct mdfour *hash)
+{
+ hash_string(hash, HASH_PREFIX);
+
+ // We have to hash the extension, as a .i file isn't treated the same by the
+ // compiler as a .ii file.
+ hash_delimiter(hash, "ext");
+ hash_string(hash, conf->cpp_extension);
+
+#ifdef _WIN32
+ const char *ext = strrchr(args->argv[0], '.');
+ char full_path_win_ext[MAX_PATH + 1] = {0};
+ add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext,
+ args->argv[0]);
+ const char *full_path = full_path_win_ext;
+#else
+ const char *full_path = args->argv[0];
+#endif
+
+ struct stat st;
+ if (x_stat(full_path, &st) != 0) {
+ stats_update(STATS_COMPILER);
+ failed();
+ }
+
+ // Hash information about the compiler.
+ hash_compiler(hash, &st, args->argv[0], true);
+
+ // Also hash the compiler name as some compilers use hard links and behave
+ // differently depending on the real name.
+ hash_delimiter(hash, "cc_name");
+ char *p = basename(args->argv[0]);
+ hash_string(hash, p);
+ free(p);
+
+ // Possibly hash the current working directory.
+ if (generating_debuginfo && conf->hash_dir) {
+ char *cwd = gnu_getcwd();
+ if (debug_prefix_map) {
+ char *map = debug_prefix_map;
+ char *sep = strchr(map, '=');
+ if (sep) {
+ char *old = x_strndup(map, sep - map);
+ char *new = x_strdup(sep + 1);
+ cc_log("Relocating debuginfo cwd %s, from %s to %s", cwd, old, new);
+ if (str_startswith(cwd, old)) {
+ char *dir = format("%s%s", new, cwd + strlen(old));
+ free(cwd);
+ cwd = dir;
+ }
+ free(old);
+ free(new);
+ }
+ }
+ if (cwd) {
+ hash_delimiter(hash, "cwd");
+ hash_string(hash, cwd);
+ free(cwd);
+ }
+ }
+
+ // Possibly hash the coverage data file path.
+ if (generating_coverage && profile_arcs) {
+ char *dir = dirname(output_obj);
+ if (profile_dir) {
+ dir = x_strdup(profile_dir);
+ } else {
+ char *real_dir = x_realpath(dir);
+ free(dir);
+ dir = real_dir;
+ }
+ if (dir) {
+ char *base_name = basename(output_obj);
+ p = remove_extension(base_name);
+ free(base_name);
+ char *gcda_path = format("%s/%s.gcda", dir, p);
+ cc_log("Hashing coverage path %s", gcda_path);
+ free(p);
+ hash_delimiter(hash, "gcda");
+ hash_string(hash, gcda_path);
+ free(dir);
+ }
+ }
+
+ if (!str_eq(conf->extra_files_to_hash, "")) {
+ char *p = x_strdup(conf->extra_files_to_hash);
+ char *q = p;
+ char *path;
+ char *saveptr = NULL;
+ while ((path = strtok_r(q, PATH_DELIM, &saveptr))) {
+ cc_log("Hashing extra file %s", path);
+ hash_delimiter(hash, "extrafile");
+ if (!hash_file(hash, path)) {
+ stats_update(STATS_BADEXTRAFILE);
+ failed();
+ }
+ q = NULL;
+ }
+ free(p);
+ }
+
+ // Possibly hash GCC_COLORS (for color diagnostics).
+ if (compiler_is_gcc(args)) {
+ const char *gcc_colors = getenv("GCC_COLORS");
+ if (gcc_colors) {
+ hash_delimiter(hash, "gcccolors");
+ hash_string(hash, gcc_colors);
+ }
+ }
+}
+
+// Update a hash sum with information specific to the direct and preprocessor
+// modes and calculate the object hash. Returns the object hash on success,
+// otherwise NULL. Caller frees.
+static struct file_hash *
+calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
+{
+ if (direct_mode) {
+ hash_delimiter(hash, "manifest version");
+ hash_int(hash, MANIFEST_VERSION);
+ }
+
+ // First the arguments.
+ for (int i = 1; i < args->argc; i++) {
+ // -L doesn't affect compilation.
+ if (i < args->argc-1 && str_eq(args->argv[i], "-L")) {
+ i++;
+ continue;
+ }
+ if (str_startswith(args->argv[i], "-L")) {
+ continue;
+ }
+
+ // -Wl,... doesn't affect compilation.
+ if (str_startswith(args->argv[i], "-Wl,")) {
+ continue;
+ }
+
+ // The -fdebug-prefix-map option may be used in combination with
+ // CCACHE_BASEDIR to reuse results across different directories. Skip it
+ // from hashing.
+ if (str_startswith(args->argv[i], "-fdebug-prefix-map=")) {
+ continue;
+ }
+
+ // When using the preprocessor, some arguments don't contribute to the
+ // hash. The theory is that these arguments will change the output of -E if
+ // they are going to have any effect at all. For precompiled headers this
+ // might not be the case.
+ if (!direct_mode && !output_is_precompiled_header
+ && !using_precompiled_header) {
+ if (compopt_affects_cpp(args->argv[i])) {
+ i++;
+ continue;
+ }
+ if (compopt_short(compopt_affects_cpp, args->argv[i])) {
+ continue;
+ }
+ }
+
+ // If we're generating dependencies, we make sure to skip the filename of
+ // the dependency file, since it doesn't impact the output.
+ if (generating_dependencies) {
+ if (str_startswith(args->argv[i], "-Wp,")) {
+ if (str_startswith(args->argv[i], "-Wp,-MD,")
+ && !strchr(args->argv[i] + 8, ',')) {
+ hash_string_length(hash, args->argv[i], 8);
+ continue;
+ } else if (str_startswith(args->argv[i], "-Wp,-MMD,")
+ && !strchr(args->argv[i] + 9, ',')) {
+ hash_string_length(hash, args->argv[i], 9);
+ continue;
+ }
+ } else if (str_startswith(args->argv[i], "-MF")) {
+ // In either case, hash the "-MF" part.
+ hash_string_length(hash, args->argv[i], 3);
+
+ bool separate_argument = (strlen(args->argv[i]) == 3);
+ if (separate_argument) {
+ // Next argument is dependency name, so skip it.
+ i++;
+ }
+ continue;
+ }
+ }
+
+ char *p = NULL;
+ if (str_startswith(args->argv[i], "-specs=")) {
+ p = args->argv[i] + 7;
+ } else if (str_startswith(args->argv[i], "--specs=")) {
+ p = args->argv[i] + 8;
+ }
+
+ struct stat st;
+ if (p && x_stat(p, &st) == 0) {
+ // If given an explicit specs file, then hash that file, but don't
+ // include the path to it in the hash.
+ hash_delimiter(hash, "specs");
+ hash_compiler(hash, &st, p, false);
+ continue;
+ }
+
+ if (str_startswith(args->argv[i], "-fplugin=")
+ && x_stat(args->argv[i] + 9, &st) == 0) {
+ hash_delimiter(hash, "plugin");
+ hash_compiler(hash, &st, args->argv[i] + 9, false);
+ continue;
+ }
+
+ if (str_eq(args->argv[i], "-Xclang")
+ && i + 3 < args->argc
+ && str_eq(args->argv[i+1], "-load")
+ && str_eq(args->argv[i+2], "-Xclang")
+ && x_stat(args->argv[i+3], &st) == 0) {
+ hash_delimiter(hash, "plugin");
+ hash_compiler(hash, &st, args->argv[i+3], false);
+ i += 3;
+ continue;
+ }
+
+ // All other arguments are included in the hash.
+ hash_delimiter(hash, "arg");
+ hash_string(hash, args->argv[i]);
+ if (i + 1 < args->argc && compopt_takes_arg(args->argv[i])) {
+ i++;
+ hash_delimiter(hash, "arg");
+ hash_string(hash, args->argv[i]);
+ }
+ }
+
+ // For profile generation (-fprofile-arcs, -fprofile-generate):
+ // - hash profile directory
+ //
+ // For profile usage (-fprofile-use):
+ // - hash profile data
+ //
+ // -fbranch-probabilities and -fvpt usage is covered by
+ // -fprofile-generate/-fprofile-use.
+ //
+ // The profile directory can be specified as an argument to
+ // -fprofile-generate=, -fprofile-use= or -fprofile-dir=.
+ if (profile_generate) {
+ if (!profile_dir) {
+ profile_dir = get_cwd();
+ }
+ cc_log("Adding profile directory %s to our hash", profile_dir);
+ hash_delimiter(hash, "-fprofile-dir");
+ hash_string(hash, profile_dir);
+ }
+
+ if (profile_use) {
+ // Calculate gcda name.
+ if (!profile_dir) {
+ profile_dir = get_cwd();
+ }
+ char *base_name = remove_extension(output_obj);
+ char *gcda_name = format("%s/%s.gcda", profile_dir, base_name);
+ cc_log("Adding profile data %s to our hash", gcda_name);
+ // Add the gcda to our hash.
+ hash_delimiter(hash, "-fprofile-use");
+ hash_file(hash, gcda_name);
+ free(base_name);
+ free(gcda_name);
+ }
+
+ // Adding -arch to hash since cpp output is affected.
+ for (size_t i = 0; i < arch_args_size; ++i) {
+ hash_delimiter(hash, "-arch");
+ hash_string(hash, arch_args[i]);
+ }
+
+ struct file_hash *object_hash = NULL;
+ if (direct_mode) {
+ // Hash environment variables that affect the preprocessor output.
+ const char *envvars[] = {
+ "CPATH",
+ "C_INCLUDE_PATH",
+ "CPLUS_INCLUDE_PATH",
+ "OBJC_INCLUDE_PATH",
+ "OBJCPLUS_INCLUDE_PATH", // clang
+ NULL
+ };
+ for (const char **p = envvars; *p; ++p) {
+ char *v = getenv(*p);
+ if (v) {
+ hash_delimiter(hash, *p);
+ hash_string(hash, v);
+ }
+ }
+
+ if (!(conf->sloppiness & SLOPPY_FILE_MACRO)) {
+ // The source code file or an include file may contain __FILE__, so make
+ // sure that the hash is unique for the file name.
+ hash_delimiter(hash, "inputfile");
+ hash_string(hash, input_file);
+ }
+
+ hash_delimiter(hash, "sourcecode");
+ int result = hash_source_code_file(conf, hash, input_file);
+ if (result & HASH_SOURCE_CODE_ERROR) {
+ failed();
+ }
+ if (result & HASH_SOURCE_CODE_FOUND_TIME) {
+ cc_log("Disabling direct mode");
+ conf->direct_mode = false;
+ return NULL;
+ }
+ char *manifest_name = hash_result(hash);
+ manifest_path = get_path_in_cache(manifest_name, ".manifest");
+ free(manifest_name);
+ cc_log("Looking for object file hash in %s", manifest_path);
+ object_hash = manifest_get(conf, manifest_path);
+ if (object_hash) {
+ cc_log("Got object file hash from manifest");
+ } else {
+ cc_log("Did not find object file hash in manifest");
+ }
+ } else {
+ if (arch_args_size == 0) {
+ object_hash = get_object_name_from_cpp(args, hash);
+ cc_log("Got object file hash from preprocessor");
+ } else {
+ args_add(args, "-arch");
+ for (size_t i = 0; i < arch_args_size; ++i) {
+ args_add(args, arch_args[i]);
+ object_hash = get_object_name_from_cpp(args, hash);
+ cc_log("Got object file hash from preprocessor with -arch %s",
+ arch_args[i]);
+ if (i != arch_args_size - 1) {
+ free(object_hash);
+ }
+ args_pop(args, 1);
+ }
+ args_pop(args, 1);
+ }
+ if (generating_dependencies) {
+ cc_log("Preprocessor created %s", output_dep);
+ }
+ }
+
+ return object_hash;
+}
+
+// Try to return the compile result from cache. If we can return from cache
+// then this function exits with the correct status code, otherwise it returns.
+static void
+from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest)
+{
+ // The user might be disabling cache hits.
+ if (conf->recache) {
+ return;
+ }
+
+ struct stat st;
+ if (stat(cached_obj, &st) != 0) {
+ cc_log("Object file %s not in cache", cached_obj);
+ return;
+ }
+
+ // Check if the diagnostic file is there.
+ if (output_dia && stat(cached_dia, &st) != 0) {
+ cc_log("Diagnostic file %s not in cache", cached_dia);
+ return;
+ }
+
+ // Occasionally, e.g. on hard reset, our cache ends up as just filesystem
+ // meta-data with no content. Catch an easy case of this.
+ if (st.st_size == 0) {
+ cc_log("Invalid (empty) object file %s in cache", cached_obj);
+ x_unlink(cached_obj);
+ return;
+ }
+
+ if (using_split_dwarf && !generating_dependencies) {
+ assert(output_dwo);
+ }
+ if (output_dwo) {
+ assert(cached_dwo);
+ if (stat(cached_dwo, &st) != 0) {
+ cc_log("Split dwarf file %s not in cache", cached_dwo);
+ return;
+ }
+ if (st.st_size == 0) {
+ cc_log("Invalid (empty) dwo file %s in cache", cached_dwo);
+ x_unlink(cached_dwo);
+ x_unlink(cached_obj); // To really invalidate.
+ return;
+ }
+ }
+
+ // (If mode != FROMCACHE_DIRECT_MODE, the dependency file is created by gcc.)
+ bool produce_dep_file =
+ generating_dependencies && mode == FROMCACHE_DIRECT_MODE;
+
+ // If the dependency file should be in the cache, check that it is.
+ if (produce_dep_file && stat(cached_dep, &st) != 0) {
+ cc_log("Dependency file %s missing in cache", cached_dep);
+ return;
+ }
+
+ // Copy object file from cache. Do so also for FissionDwarf file, cached_dwo,
+ // when -gsplit-dwarf is specified.
+ if (!str_eq(output_obj, "/dev/null")) {
+ get_file_from_cache(cached_obj, output_obj);
+ if (using_split_dwarf) {
+ assert(output_dwo);
+ get_file_from_cache(cached_dwo, output_dwo);
+ }
+ }
+ if (produce_dep_file) {
+ get_file_from_cache(cached_dep, output_dep);
+ }
+ if (generating_coverage && stat(cached_cov, &st) == 0 && st.st_size > 0) {
+ // The compiler won't generate notes if there is no code
+ get_file_from_cache(cached_cov, output_cov);
+ }
+ if (output_dia) {
+ get_file_from_cache(cached_dia, output_dia);
+ }
+
+ // Update modification timestamps to save files from LRU cleanup. Also gives
+ // files a sensible mtime when hard-linking.
+ update_mtime(cached_obj);
+ update_mtime(cached_stderr);
+ if (produce_dep_file) {
+ update_mtime(cached_dep);
+ }
+ if (generating_coverage) {
+ update_mtime(cached_cov);
+ }
+ if (output_dia) {
+ update_mtime(cached_dia);
+ }
+ if (cached_dwo) {
+ update_mtime(cached_dwo);
+ }
+
+ if (generating_dependencies && mode == FROMCACHE_CPP_MODE
+ && !conf->read_only && !conf->read_only_direct) {
+ put_file_in_cache(output_dep, cached_dep);
+ }
+
+ send_cached_stderr();
+
+ if (put_object_in_manifest) {
+ update_manifest_file();
+ }
+
+ // Log the cache hit.
+ switch (mode) {
+ case FROMCACHE_DIRECT_MODE:
+ cc_log("Succeeded getting cached result");
+ stats_update(STATS_CACHEHIT_DIR);
+ break;
+
+ case FROMCACHE_CPP_MODE:
+ cc_log("Succeeded getting cached result");
+ stats_update(STATS_CACHEHIT_CPP);
+ break;
+ }
+
+ // And exit with the right status code.
+ x_exit(0);
+}
+
+// Find the real compiler. We just search the PATH to find an executable of the
+// same name that isn't a link to ourselves.
+static void
+find_compiler(char **argv)
+{
+ // We might be being invoked like "ccache gcc -c foo.c".
+ char *base = basename(argv[0]);
+ if (same_executable_name(base, MYNAME)) {
+ args_remove_first(orig_args);
+ free(base);
+ if (is_full_path(orig_args->argv[0])) {
+ // A full path was given.
+ return;
+ }
+ base = basename(orig_args->argv[0]);
+ }
+
+ // Support user override of the compiler.
+ if (!str_eq(conf->compiler, "")) {
+ base = conf->compiler;
+ }
+
+ char *compiler = find_executable(base, MYNAME);
+ if (!compiler) {
+ stats_update(STATS_COMPILER);
+ fatal("Could not find compiler \"%s\" in PATH", base);
+ }
+ if (str_eq(compiler, argv[0])) {
+ fatal("Recursive invocation (the name of the ccache binary must be \"%s\")",
+ MYNAME);
+ }
+ orig_args->argv[0] = compiler;
+}
+
+bool
+is_precompiled_header(const char *path)
+{
+ return str_eq(get_extension(path), ".gch")
+ || str_eq(get_extension(path), ".pch")
+ || str_eq(get_extension(path), ".pth");
+}
+
+static bool
+color_output_possible(void)
+{
+ const char *term_env = getenv("TERM");
+ return isatty(STDERR_FILENO) && term_env && strcasecmp(term_env, "DUMB") != 0;
+}
+
+static bool
+detect_pch(const char *option, const char *arg, bool *found_pch)
+{
+ struct stat st;
+
+ // Try to be smart about detecting precompiled headers.
+ char *pch_file = NULL;
+ if (str_eq(option, "-include-pch") || str_eq(option, "-include-pth")) {
+ if (stat(arg, &st) == 0) {
+ cc_log("Detected use of precompiled header: %s", arg);
+ pch_file = x_strdup(arg);
+ }
+ } else {
+ char *gchpath = format("%s.gch", arg);
+ if (stat(gchpath, &st) == 0) {
+ cc_log("Detected use of precompiled header: %s", gchpath);
+ pch_file = x_strdup(gchpath);
+ } else {
+ char *pchpath = format("%s.pch", arg);
+ if (stat(pchpath, &st) == 0) {
+ cc_log("Detected use of precompiled header: %s", pchpath);
+ pch_file = x_strdup(pchpath);
+ } else {
+ // clang may use pretokenized headers.
+ char *pthpath = format("%s.pth", arg);
+ if (stat(pthpath, &st) == 0) {
+ cc_log("Detected use of pretokenized header: %s", pthpath);
+ pch_file = x_strdup(pthpath);
+ }
+ free(pthpath);
+ }
+ free(pchpath);
+ }
+ free(gchpath);
+ }
+
+ if (pch_file) {
+ if (included_pch_file) {
+ cc_log("Multiple precompiled headers used: %s and %s\n",
+ included_pch_file, pch_file);
+ stats_update(STATS_ARGS);
+ return false;
+ }
+ included_pch_file = pch_file;
+ *found_pch = true;
+ }
+ return true;
+}
+
+// Process the compiler options into options suitable for passing to the
+// preprocessor and the real compiler. The preprocessor options don't include
+// -E; this is added later. Returns true on success, otherwise false.
+bool
+cc_process_args(struct args *args, struct args **preprocessor_args,
+ struct args **compiler_args)
+{
+ bool found_c_opt = false;
+ bool found_S_opt = false;
+ bool found_pch = false;
+ bool found_fpch_preprocess = false;
+ const char *explicit_language = NULL; // As specified with -x.
+ const char *file_language; // As deduced from file extension.
+ const char *actual_language; // Language to actually use.
+ const char *input_charset = NULL;
+ // Is the dependency makefile name overridden with -MF?
+ bool dependency_filename_specified = false;
+ // Is the dependency makefile target name specified with -MT or -MQ?
+ bool dependency_target_specified = false;
+ // expanded_args is a copy of the original arguments given to the compiler
+ // but with arguments from @file and similar constructs expanded. It's only
+ // used as a temporary data structure to loop over.
+ struct args *expanded_args = args_copy(args);
+ // stripped_args essentially contains all original arguments except those
+ // that only should be passed to the preprocessor (if run_second_cpp is
+ // false) and except dependency options (like -MD and friends).
+ struct args *stripped_args = args_init(0, NULL);
+ // cpp_args contains arguments that were not added to stripped_args, i.e.
+ // those that should only be passed to the preprocessor if run_second_cpp is
+ // false. If run_second_cpp is true, they will be passed to the compiler as
+ // well.
+ struct args *cpp_args = args_init(0, NULL);
+ // dep_args contains dependency options like -MD. They only passed to the
+ // preprocessor, never to the compiler.
+ struct args *dep_args = args_init(0, NULL);
+
+ bool found_color_diagnostics = false;
+ int debug_level = 0;
+ const char *debug_argument = NULL;
+
+ int argc = expanded_args->argc;
+ char **argv = expanded_args->argv;
+ args_add(stripped_args, argv[0]);
+
+ bool result = true;
+ for (int i = 1; i < argc; i++) {
+ // The user knows best: just swallow the next arg.
+ if (str_eq(argv[i], "--ccache-skip")) {
+ i++;
+ if (i == argc) {
+ cc_log("--ccache-skip lacks an argument");
+ result = false;
+ goto out;
+ }
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
+
+ // Special case for -E.
+ if (str_eq(argv[i], "-E")) {
+ stats_update(STATS_PREPROCESSING);
+ result = false;
+ goto out;
+ }
+
+ // Handle "@file" argument.
+ if (str_startswith(argv[i], "@") || str_startswith(argv[i], "-@")) {
+ char *argpath = argv[i] + 1;
+
+ if (argpath[-1] == '-') {
+ ++argpath;
+ }
+ struct args *file_args = args_init_from_gcc_atfile(argpath);
+ if (!file_args) {
+ cc_log("Couldn't read arg file %s", argpath);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+
+ args_insert(expanded_args, i, file_args, true);
+ argc = expanded_args->argc;
+ argv = expanded_args->argv;
+ i--;
+ continue;
+ }
+
+ // Handle cuda "-optf" and "--options-file" argument.
+ if (str_eq(argv[i], "-optf") || str_eq(argv[i], "--options-file")) {
+ if (i > argc) {
+ cc_log("Expected argument after -optf/--options-file");
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+ ++i;
+
+ // Argument is a comma-separated list of files.
+ char *str_start = argv[i];
+ char *str_end = strchr(str_start, ',');
+ int index = i + 1;
+
+ if (!str_end) {
+ str_end = str_start + strlen(str_start);
+ }
+
+ while (str_end) {
+ *str_end = '\0';
+ struct args *file_args = args_init_from_gcc_atfile(str_start);
+ if (!file_args) {
+ cc_log("Couldn't read cuda options file %s", str_start);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+
+ int new_index = file_args->argc + index;
+ args_insert(expanded_args, index, file_args, false);
+ index = new_index;
+ str_start = str_end;
+ str_end = strchr(str_start, ',');
+ }
+
+ argc = expanded_args->argc;
+ argv = expanded_args->argv;
+ continue;
+ }
+
+ // These are always too hard.
+ if (compopt_too_hard(argv[i]) || str_startswith(argv[i], "-fdump-")) {
+ cc_log("Compiler option %s is unsupported", argv[i]);
+ stats_update(STATS_UNSUPPORTED_OPTION);
+ result = false;
+ goto out;
+ }
+
+ // These are too hard in direct mode.
+ if (conf->direct_mode && compopt_too_hard_for_direct_mode(argv[i])) {
+ cc_log("Unsupported compiler option for direct mode: %s", argv[i]);
+ conf->direct_mode = false;
+ }
+
+ // -Xarch_* options are too hard.
+ if (str_startswith(argv[i], "-Xarch_")) {
+ cc_log("Unsupported compiler option :%s", argv[i]);
+ stats_update(STATS_UNSUPPORTED_OPTION);
+ result = false;
+ goto out;
+ }
+
+ // Handle -arch options.
+ if (str_eq(argv[i], "-arch")) {
+ if (arch_args_size == MAX_ARCH_ARGS - 1) {
+ cc_log("Too many -arch compiler options; ccache supports at most %d",
+ MAX_ARCH_ARGS);
+ stats_update(STATS_UNSUPPORTED_OPTION);
+ result = false;
+ goto out;
+ }
+
+ ++i;
+ arch_args[arch_args_size] = x_strdup(argv[i]); // It will leak.
+ ++arch_args_size;
+ if (arch_args_size == 2) {
+ conf->run_second_cpp = true;
+ }
+ continue;
+ }
+
+ if (str_eq(argv[i], "-fpch-preprocess")
+ || str_eq(argv[i], "-emit-pch")
+ || str_eq(argv[i], "-emit-pth")) {
+ found_fpch_preprocess = true;
+ }
+
+ // We must have -c.
+ if (str_eq(argv[i], "-c")) {
+ found_c_opt = true;
+ continue;
+ }
+
+ // -S changes the default extension.
+ if (str_eq(argv[i], "-S")) {
+ args_add(stripped_args, argv[i]);
+ found_S_opt = true;
+ continue;
+ }
+
+ // Special handling for -x: remember the last specified language before the
+ // input file and strip all -x options from the arguments.
+ if (str_eq(argv[i], "-x")) {
+ if (i == argc-1) {
+ cc_log("Missing argument to %s", argv[i]);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+ if (!input_file) {
+ explicit_language = argv[i+1];
+ }
+ i++;
+ continue;
+ }
+ if (str_startswith(argv[i], "-x")) {
+ if (!input_file) {
+ explicit_language = &argv[i][2];
+ }
+ continue;
+ }
+
+ // We need to work out where the output was meant to go.
+ if (str_eq(argv[i], "-o")) {
+ if (i == argc-1) {
+ cc_log("Missing argument to %s", argv[i]);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+ output_obj = make_relative_path(x_strdup(argv[i+1]));
+ i++;
+ continue;
+ }
+
+ // Alternate form of -o with no space.
+ if (str_startswith(argv[i], "-o")) {
+ output_obj = make_relative_path(x_strdup(&argv[i][2]));
+ continue;
+ }
+
+ if (str_eq(argv[i], "-gsplit-dwarf")) {
+ cc_log("Enabling caching of dwarf files since -gsplit-dwarf is used");
+ using_split_dwarf = true;
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
+ if (str_startswith(argv[i], "-fdebug-prefix-map=")) {
+ debug_prefix_map = x_strdup(argv[i] + 19);
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
+
+ // Debugging is handled specially, so that we know if we can strip line
+ // number info.
+ if (str_startswith(argv[i], "-g")) {
+ const char *pLevel = argv[i] + 2;
+ if (str_startswith(argv[i], "-ggdb")) {
+ pLevel = argv[i] + 5;
+ } else if (str_startswith(argv[i], "-gstabs")) {
+ pLevel = argv[i] + 7;
+ } else if (str_startswith(argv[i], "-gcoff")) {
+ pLevel = argv[i] + 6;
+ } else if (str_startswith(argv[i], "-gxcoff")) {
+ pLevel = argv[i] + 7;
+ } else if (str_startswith(argv[i], "-gvms")) {
+ pLevel = argv[i] + 5;
+ }
+
+ // Deduce level from argument, default is 2.
+ int foundlevel = -1;
+ if (pLevel[0] == '\0') {
+ foundlevel = 2;
+ } else if (pLevel[0] >= '0' && pLevel[0] <= '9') {
+ foundlevel = atoi(pLevel);
+ }
+
+ if (foundlevel >= 0) {
+ debug_level = foundlevel;
+ debug_argument = argv[i];
+ continue;
+ }
+ }
+
+ // These options require special handling, because they behave differently
+ // with gcc -E, when the output file is not specified.
+ if (str_eq(argv[i], "-MD") || str_eq(argv[i], "-MMD")) {
+ generating_dependencies = true;
+ args_add(dep_args, argv[i]);
+ continue;
+ }
+ if (str_startswith(argv[i], "-MF")) {
+ dependency_filename_specified = true;
+ free(output_dep);
+
+ char *arg;
+ bool separate_argument = (strlen(argv[i]) == 3);
+ if (separate_argument) {
+ // -MF arg
+ if (i >= argc - 1) {
+ cc_log("Missing argument to %s", argv[i]);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+ arg = argv[i + 1];
+ i++;
+ } else {
+ // -MFarg
+ arg = &argv[i][3];
+ }
+ output_dep = make_relative_path(x_strdup(arg));
+ // Keep the format of the args the same.
+ if (separate_argument) {
+ args_add(dep_args, "-MF");
+ args_add(dep_args, output_dep);
+ } else {
+ char *option = format("-MF%s", output_dep);
+ args_add(dep_args, option);
+ free(option);
+ }
+ continue;
+ }
+ if (str_startswith(argv[i], "-MQ") || str_startswith(argv[i], "-MT")) {
+ dependency_target_specified = true;
+
+ char *relpath;
+ if (strlen(argv[i]) == 3) {
+ // -MQ arg or -MT arg
+ if (i >= argc - 1) {
+ cc_log("Missing argument to %s", argv[i]);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+ args_add(dep_args, argv[i]);
+ relpath = make_relative_path(x_strdup(argv[i + 1]));
+ args_add(dep_args, relpath);
+ free(relpath);
+ i++;
+ } else {
+ char *arg_opt = x_strndup(argv[i], 3);
+ relpath = make_relative_path(x_strdup(argv[i] + 3));
+ char *option = format("%s%s", arg_opt, relpath);
+ args_add(dep_args, option);
+ free(arg_opt);
+ free(relpath);
+ free(option);
+ }
+ continue;
+ }
+ if (str_eq(argv[i], "-fprofile-arcs")) {
+ profile_arcs = true;
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
+ if (str_eq(argv[i], "-ftest-coverage")) {
+ generating_coverage = true;
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
+ if (str_eq(argv[i], "--coverage") // = -fprofile-arcs -ftest-coverage
+ || str_eq(argv[i], "-coverage")) { // Undocumented but still works.
+ profile_arcs = true;
+ generating_coverage = true;
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
+ if (str_startswith(argv[i], "-fprofile-dir=")) {
+ profile_dir = x_strdup(argv[i] + 14);
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
+ if (str_startswith(argv[i], "--sysroot=")) {
+ char *relpath = make_relative_path(x_strdup(argv[i] + 10));
+ char *option = format("--sysroot=%s", relpath);
+ args_add(stripped_args, option);
+ free(relpath);
+ free(option);
+ continue;
+ }
+ if (str_startswith(argv[i], "-Wp,")) {
+ if (str_eq(argv[i], "-Wp,-P")
+ || strstr(argv[i], ",-P,")
+ || str_endswith(argv[i], ",-P")) {
+ // -P removes preprocessor information in such a way that the object
+ // file from compiling the preprocessed file will not be equal to the
+ // object file produced when compiling without ccache.
+ cc_log("Too hard option -Wp,-P detected");
+ stats_update(STATS_UNSUPPORTED_OPTION);
+ failed();
+ } else if (str_startswith(argv[i], "-Wp,-MD,")
+ && !strchr(argv[i] + 8, ',')) {
+ generating_dependencies = true;
+ dependency_filename_specified = true;
+ free(output_dep);
+ output_dep = make_relative_path(x_strdup(argv[i] + 8));
+ args_add(dep_args, argv[i]);
+ continue;
+ } else if (str_startswith(argv[i], "-Wp,-MMD,")
+ && !strchr(argv[i] + 9, ',')) {
+ generating_dependencies = true;
+ dependency_filename_specified = true;
+ free(output_dep);
+ output_dep = make_relative_path(x_strdup(argv[i] + 9));
+ args_add(dep_args, argv[i]);
+ continue;
+ } else if (str_startswith(argv[i], "-Wp,-D")
+ && !strchr(argv[i] + 6, ',')) {
+ // Treat it like -D.
+ args_add(cpp_args, argv[i] + 4);
+ continue;
+ } else if (str_eq(argv[i], "-Wp,-MP")
+ || (strlen(argv[i]) > 8
+ && str_startswith(argv[i], "-Wp,-M")
+ && argv[i][7] == ','
+ && (argv[i][6] == 'F'
+ || argv[i][6] == 'Q'
+ || argv[i][6] == 'T')
+ && !strchr(argv[i] + 8, ','))) {
+ // TODO: Make argument to MF/MQ/MT relative.
+ args_add(dep_args, argv[i]);
+ continue;
+ } else if (conf->direct_mode) {
+ // -Wp, can be used to pass too hard options to the preprocessor.
+ // Hence, disable direct mode.
+ cc_log("Unsupported compiler option for direct mode: %s", argv[i]);
+ conf->direct_mode = false;
+ }
+
+ // Any other -Wp,* arguments are only relevant for the preprocessor.
+ args_add(cpp_args, argv[i]);
+ continue;
+ }
+ if (str_eq(argv[i], "-MP")) {
+ args_add(dep_args, argv[i]);
+ continue;
+ }
+
+ // Input charset needs to be handled specially.
+ if (str_startswith(argv[i], "-finput-charset=")) {
+ input_charset = argv[i];
+ continue;
+ }
+
+ if (str_eq(argv[i], "--serialize-diagnostics")) {
+ if (i >= argc - 1) {
+ cc_log("Missing argument to %s", argv[i]);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+ output_dia = make_relative_path(x_strdup(argv[i+1]));
+ i++;
+ continue;
+ }
+
+ if (str_startswith(argv[i], "-fprofile-")) {
+ char *arg = x_strdup(argv[i]);
+ const char *arg_profile_dir = strchr(argv[i], '=');
+ if (arg_profile_dir) {
+ // Convert to absolute path.
+ char *dir = x_realpath(arg_profile_dir + 1);
+ if (!dir) {
+ // Directory doesn't exist.
+ dir = x_strdup(arg_profile_dir + 1);
+ }
+
+ // We can get a better hit rate by using the real path here.
+ free(arg);
+ char *option = x_strndup(argv[i], arg_profile_dir - argv[i]);
+ arg = format("%s=%s", option, dir);
+ cc_log("Rewriting %s to %s", argv[i], arg);
+ free(option);
+ free(dir);
+ }
+
+ bool supported_profile_option = false;
+ if (str_startswith(argv[i], "-fprofile-generate")
+ || str_eq(argv[i], "-fprofile-arcs")) {
+ profile_generate = true;
+ supported_profile_option = true;
+ } else if (str_startswith(argv[i], "-fprofile-use")
+ || str_eq(argv[i], "-fbranch-probabilities")) {
+ profile_use = true;
+ supported_profile_option = true;
+ } else if (str_eq(argv[i], "-fprofile-dir")) {
+ supported_profile_option = true;
+ }
+
+ if (supported_profile_option) {
+ args_add(stripped_args, arg);
+ free(arg);
+
+ // If the profile directory has already been set, give up... Hard to
+ // know what the user means, and what the compiler will do.
+ if (arg_profile_dir && profile_dir) {
+ cc_log("Profile directory already set; giving up");
+ result = false;
+ goto out;
+ } else if (arg_profile_dir) {
+ cc_log("Setting profile directory to %s", profile_dir);
+ profile_dir = x_strdup(arg_profile_dir);
+ }
+ continue;
+ }
+ cc_log("Unknown profile option: %s", argv[i]);
+ free(arg);
+ }
+
+ if (str_eq(argv[i], "-fcolor-diagnostics")
+ || str_eq(argv[i], "-fno-color-diagnostics")
+ || str_eq(argv[i], "-fdiagnostics-color")
+ || str_eq(argv[i], "-fdiagnostics-color=always")
+ || str_eq(argv[i], "-fno-diagnostics-color")
+ || str_eq(argv[i], "-fdiagnostics-color=never")) {
+ args_add(stripped_args, argv[i]);
+ found_color_diagnostics = true;
+ continue;
+ }
+ if (str_eq(argv[i], "-fdiagnostics-color=auto")) {
+ if (color_output_possible()) {
+ // Output is redirected, so color output must be forced.
+ args_add(stripped_args, "-fdiagnostics-color=always");
+ cc_log("Automatically forcing colors");
+ } else {
+ args_add(stripped_args, argv[i]);
+ }
+ found_color_diagnostics = true;
+ continue;
+ }
+
+ // Options taking an argument that we may want to rewrite to relative paths
+ // to get better hit rate. A secondary effect is that paths in the standard
+ // error output produced by the compiler will be normalized.
+ if (compopt_takes_path(argv[i])) {
+ if (i == argc-1) {
+ cc_log("Missing argument to %s", argv[i]);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+
+ if (!detect_pch(argv[i], argv[i+1], &found_pch)) {
+ result = false;
+ goto out;
+ }
+
+ char *relpath = make_relative_path(x_strdup(argv[i+1]));
+ if (compopt_affects_cpp(argv[i])) {
+ args_add(cpp_args, argv[i]);
+ args_add(cpp_args, relpath);
+ } else {
+ args_add(stripped_args, argv[i]);
+ args_add(stripped_args, relpath);
+ }
+ free(relpath);
+
+ i++;
+ continue;
+ }
+
+ // Same as above but options with concatenated argument beginning with a
+ // slash.
+ if (argv[i][0] == '-') {
+ char *slash_pos = strchr(argv[i], '/');
+ if (slash_pos) {
+ char *option = x_strndup(argv[i], slash_pos - argv[i]);
+ if (compopt_takes_concat_arg(option) && compopt_takes_path(option)) {
+ char *relpath = make_relative_path(x_strdup(slash_pos));
+ char *new_option = format("%s%s", option, relpath);
+ if (compopt_affects_cpp(option)) {
+ args_add(cpp_args, new_option);
+ } else {
+ args_add(stripped_args, new_option);
+ }
+ free(new_option);
+ free(relpath);
+ free(option);
+ continue;
+ } else {
+ free(option);
+ }
+ }
+ }
+
+ // Options that take an argument.
+ if (compopt_takes_arg(argv[i])) {
+ if (i == argc-1) {
+ cc_log("Missing argument to %s", argv[i]);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+
+ if (compopt_affects_cpp(argv[i])) {
+ args_add(cpp_args, argv[i]);
+ args_add(cpp_args, argv[i+1]);
+ } else {
+ args_add(stripped_args, argv[i]);
+ args_add(stripped_args, argv[i+1]);
+ }
+
+ i++;
+ continue;
+ }
+
+ // Other options.
+ if (argv[i][0] == '-') {
+ if (compopt_affects_cpp(argv[i])
+ || compopt_prefix_affects_cpp(argv[i])) {
+ args_add(cpp_args, argv[i]);
+ } else {
+ args_add(stripped_args, argv[i]);
+ }
+ continue;
+ }
+
+ // If an argument isn't a plain file then assume its an option, not an
+ // input file. This allows us to cope better with unusual compiler options.
+ struct stat st;
+ if (stat(argv[i], &st) != 0 || !S_ISREG(st.st_mode)) {
+ cc_log("%s is not a regular file, not considering as input file",
+ argv[i]);
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
+
+ if (input_file) {
+ if (language_for_file(argv[i])) {
+ cc_log("Multiple input files: %s and %s", input_file, argv[i]);
+ stats_update(STATS_MULTIPLE);
+ } else if (!found_c_opt) {
+ cc_log("Called for link with %s", argv[i]);
+ if (strstr(argv[i], "conftest.")) {
+ stats_update(STATS_CONFTEST);
+ } else {
+ stats_update(STATS_LINK);
+ }
+ } else {
+ cc_log("Unsupported source extension: %s", argv[i]);
+ stats_update(STATS_SOURCELANG);
+ }
+ result = false;
+ goto out;
+ }
+
+ // The source code file path gets put into the notes.
+ if (generating_coverage) {
+ input_file = x_strdup(argv[i]);
+ continue;
+ }
+
+ if (is_symlink(argv[i])) {
+ // Don't rewrite source file path if it's a symlink since
+ // make_relative_path resolves symlinks using realpath(3) and this leads
+ // to potentially choosing incorrect relative header files. See the
+ // "symlink to source file" test.
+ input_file = x_strdup(argv[i]);
+ } else {
+ // Rewrite to relative to increase hit rate.
+ input_file = make_relative_path(x_strdup(argv[i]));
+ }
+ } // for
+
+ if (debug_level > 0) {
+ generating_debuginfo = true;
+ args_add(stripped_args, debug_argument);
+ if (conf->unify) {
+ cc_log("%s used; disabling unify mode", debug_argument);
+ conf->unify = false;
+ }
+ if (debug_level >= 3 && !conf->run_second_cpp) {
+ cc_log("%s used; not compiling preprocessed code", debug_argument);
+ conf->run_second_cpp = true;
+ }
+ }
+
+ if (found_S_opt) {
+ // Even if -gsplit-dwarf is given, the .dwo file is not generated when -S
+ // is also given.
+ using_split_dwarf = false;
+ cc_log("Disabling caching of dwarf files since -S is used");
+ }
+
+ if (!input_file) {
+ cc_log("No input file found");
+ stats_update(STATS_NOINPUT);
+ result = false;
+ goto out;
+ }
+
+ if (found_pch || found_fpch_preprocess) {
+ using_precompiled_header = true;
+ if (!(conf->sloppiness & SLOPPY_TIME_MACROS)) {
+ cc_log("You have to specify \"time_macros\" sloppiness when using"
+ " precompiled headers to get direct hits");
+ cc_log("Disabling direct mode");
+ stats_update(STATS_CANTUSEPCH);
+ result = false;
+ goto out;
+ }
+ }
+
+ if (explicit_language && str_eq(explicit_language, "none")) {
+ explicit_language = NULL;
+ }
+ file_language = language_for_file(input_file);
+ if (explicit_language) {
+ if (!language_is_supported(explicit_language)) {
+ cc_log("Unsupported language: %s", explicit_language);
+ stats_update(STATS_SOURCELANG);
+ result = false;
+ goto out;
+ }
+ actual_language = explicit_language;
+ } else {
+ actual_language = file_language;
+ }
+
+ output_is_precompiled_header =
+ actual_language && strstr(actual_language, "-header");
+
+ if (output_is_precompiled_header
+ && !(conf->sloppiness & SLOPPY_PCH_DEFINES)) {
+ cc_log("You have to specify \"pch_defines,time_macros\" sloppiness when"
+ " creating precompiled headers");
+ stats_update(STATS_CANTUSEPCH);
+ result = false;
+ goto out;
+ }
+
+ if (!found_c_opt && !found_S_opt) {
+ if (output_is_precompiled_header) {
+ args_add(stripped_args, "-c");
+ } else {
+ cc_log("No -c option found");
+ // I find that having a separate statistic for autoconf tests is useful,
+ // as they are the dominant form of "called for link" in many cases.
+ if (strstr(input_file, "conftest.")) {
+ stats_update(STATS_CONFTEST);
+ } else {
+ stats_update(STATS_LINK);
+ }
+ result = false;
+ goto out;
+ }
+ }
+
+ if (!actual_language) {
+ cc_log("Unsupported source extension: %s", input_file);
+ stats_update(STATS_SOURCELANG);
+ result = false;
+ goto out;
+ }
+
+ direct_i_file = language_is_preprocessed(actual_language);
+
+ if (output_is_precompiled_header && !conf->run_second_cpp) {
+ // It doesn't work to create the .gch from preprocessed source.
+ cc_log("Creating precompiled header; not compiling preprocessed code");
+ conf->run_second_cpp = true;
+ }
+
+ if (str_eq(conf->cpp_extension, "")) {
+ const char *p_language = p_language_for_language(actual_language);
+ free(conf->cpp_extension);
+ conf->cpp_extension = x_strdup(extension_for_language(p_language) + 1);
+ }
+
+ // Don't try to second guess the compilers heuristics for stdout handling.
+ if (output_obj && str_eq(output_obj, "-")) {
+ stats_update(STATS_OUTSTDOUT);
+ cc_log("Output file is -");
+ result = false;
+ goto out;
+ }
+
+ if (!output_obj) {
+ if (output_is_precompiled_header) {
+ output_obj = format("%s.gch", input_file);
+ } else {
+ output_obj = basename(input_file);
+ char *p = strrchr(output_obj, '.');
+ if (!p || !p[1]) {
+ cc_log("Badly formed object filename");
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+ p[1] = found_S_opt ? 's' : 'o';
+ p[2] = 0;
+ }
+ }
+
+ if (using_split_dwarf) {
+ char *p = strrchr(output_obj, '.');
+ if (!p || !p[1]) {
+ cc_log("Badly formed object filename");
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+
+ char *base_name = remove_extension(output_obj);
+ output_dwo = format("%s.dwo", base_name);
+ free(base_name);
+ }
+
+ // Cope with -o /dev/null.
+ struct stat st;
+ if (!str_eq(output_obj, "/dev/null")
+ && stat(output_obj, &st) == 0
+ && !S_ISREG(st.st_mode)) {
+ cc_log("Not a regular file: %s", output_obj);
+ stats_update(STATS_DEVICE);
+ result = false;
+ goto out;
+ }
+
+ // Some options shouldn't be passed to the real compiler when it compiles
+ // preprocessed code:
+ //
+ // -finput-charset=XXX (otherwise conversion happens twice)
+ // -x XXX (otherwise the wrong language is selected)
+ if (input_charset) {
+ args_add(cpp_args, input_charset);
+ }
+ if (found_pch) {
+ args_add(cpp_args, "-fpch-preprocess");
+ }
+ if (explicit_language) {
+ args_add(cpp_args, "-x");
+ args_add(cpp_args, explicit_language);
+ }
+
+ // Since output is redirected, compilers will not color their output by
+ // default, so force it explicitly if it would be otherwise done.
+ if (!found_color_diagnostics && color_output_possible()) {
+ if (compiler_is_clang(args)) {
+ if (!str_eq(actual_language, "assembler")) {
+ args_add(stripped_args, "-fcolor-diagnostics");
+ cc_log("Automatically enabling colors");
+ }
+ } else if (compiler_is_gcc(args)) {
+ // GCC has it since 4.9, but that'd require detecting what GCC version is
+ // used for the actual compile. However it requires also GCC_COLORS to be
+ // set (and not empty), so use that for detecting if GCC would use
+ // colors.
+ if (getenv("GCC_COLORS") && getenv("GCC_COLORS")[0] != '\0') {
+ args_add(stripped_args, "-fdiagnostics-color");
+ cc_log("Automatically enabling colors");
+ }
+ }
+ }
+
+ // Add flags for dependency generation only to the preprocessor command line.
+ if (generating_dependencies) {
+ if (!dependency_filename_specified) {
+ char *base_name = remove_extension(output_obj);
+ char *default_depfile_name = format("%s.d", base_name);
+ free(base_name);
+ args_add(dep_args, "-MF");
+ args_add(dep_args, default_depfile_name);
+ output_dep = make_relative_path(x_strdup(default_depfile_name));
+ }
+
+ if (!dependency_target_specified) {
+ args_add(dep_args, "-MQ");
+ args_add(dep_args, output_obj);
+ }
+ }
+ if (generating_coverage) {
+ char *base_name = remove_extension(output_obj);
+ char *default_covfile_name = format("%s.gcno", base_name);
+ free(base_name);
+ output_cov = make_relative_path(x_strdup(default_covfile_name));
+ }
+
+ *compiler_args = args_copy(stripped_args);
+ if (conf->run_second_cpp) {
+ args_extend(*compiler_args, cpp_args);
+ } else if (explicit_language) {
+ // Workaround for a bug in Apple's patched distcc -- it doesn't properly
+ // reset the language specified with -x, so if -x is given, we have to
+ // specify the preprocessed language explicitly.
+ args_add(*compiler_args, "-x");
+ args_add(*compiler_args, p_language_for_language(explicit_language));
+ }
+
+ if (found_c_opt) {
+ args_add(*compiler_args, "-c");
+ }
+
+ for (size_t i = 0; i < arch_args_size; ++i) {
+ args_add(*compiler_args, "-arch");
+ args_add(*compiler_args, arch_args[i]);
+ }
+
+ // Only pass dependency arguments to the preprocesor since Intel's C++
+ // compiler doesn't produce a correct .d file when compiling preprocessed
+ // source.
+ args_extend(cpp_args, dep_args);
+
+ *preprocessor_args = args_copy(stripped_args);
+ args_extend(*preprocessor_args, cpp_args);
+
+out:
+ args_free(expanded_args);
+ args_free(stripped_args);
+ args_free(dep_args);
+ args_free(cpp_args);
+ return result;
+}
+
+static void
+create_initial_config_file(struct conf *conf, const char *path)
+{
+ if (create_parent_dirs(path) != 0) {
+ return;
+ }
+
+ unsigned max_files;
+ uint64_t max_size;
+ char *stats_dir = format("%s/0", conf->cache_dir);
+ struct stat st;
+ if (stat(stats_dir, &st) == 0) {
+ stats_get_obsolete_limits(stats_dir, &max_files, &max_size);
+ // STATS_MAXFILES and STATS_MAXSIZE was stored for each top directory.
+ max_files *= 16;
+ max_size *= 16;
+ } else {
+ max_files = 0;
+ max_size = conf->max_size;
+ }
+ free(stats_dir);
+
+ FILE *f = fopen(path, "w");
+ if (!f) {
+ return;
+ }
+ if (max_files != 0) {
+ fprintf(f, "max_files = %u\n", max_files);
+ conf->max_files = max_files;
+ }
+ if (max_size != 0) {
+ char *size = format_parsable_size_with_suffix(max_size);
+ fprintf(f, "max_size = %s\n", size);
+ free(size);
+ conf->max_size = max_size;
+ }
+ fclose(f);
+}
+
+// Read config file(s), populate variables, create configuration file in cache
+// directory if missing, etc.
+static void
+initialize(void)
+{
+ conf_free(conf);
+ conf = conf_create();
+
+ char *errmsg;
+ struct stat st;
+ char *p = getenv("CCACHE_CONFIGPATH");
+ if (p) {
+ primary_config_path = x_strdup(p);
+ } else {
+ secondary_config_path = format("%s/ccache.conf", TO_STRING(SYSCONFDIR));
+ if (!conf_read(conf, secondary_config_path, &errmsg)) {
+ if (stat(secondary_config_path, &st) == 0) {
+ fatal("%s", errmsg);
+ }
+ // Missing config file in SYSCONFDIR is OK.
+ free(errmsg);
+ }
+
+ if (str_eq(conf->cache_dir, "")) {
+ fatal("configuration setting \"cache_dir\" must not be the empty string");
+ }
+ if ((p = getenv("CCACHE_DIR"))) {
+ free(conf->cache_dir);
+ conf->cache_dir = strdup(p);
+ }
+ if (str_eq(conf->cache_dir, "")) {
+ fatal("CCACHE_DIR must not be the empty string");
+ }
+
+ primary_config_path = format("%s/ccache.conf", conf->cache_dir);
+ }
+
+ bool should_create_initial_config = false;
+ if (!conf_read(conf, primary_config_path, &errmsg)) {
+ if (stat(primary_config_path, &st) == 0) {
+ fatal("%s", errmsg);
+ }
+ should_create_initial_config = true;
+ }
+
+ if (!conf_update_from_environment(conf, &errmsg)) {
+ fatal("%s", errmsg);
+ }
+
+ if (conf->disable) {
+ should_create_initial_config = false;
+ }
+
+ if (should_create_initial_config) {
+ create_initial_config_file(conf, primary_config_path);
+ }
+
+ exitfn_init();
+ exitfn_add_nullary(stats_flush);
+ exitfn_add_nullary(clean_up_pending_tmp_files);
+
+ cc_log("=== CCACHE %s STARTED =========================================",
+ CCACHE_VERSION);
+
+ if (conf->umask != UINT_MAX) {
+ umask(conf->umask);
+ }
+}
+
+// Reset the global state. Used by the test suite.
+void
+cc_reset(void)
+{
+ conf_free(conf); conf = NULL;
+ free(primary_config_path); primary_config_path = NULL;
+ free(secondary_config_path); secondary_config_path = NULL;
+ free(current_working_dir); current_working_dir = NULL;
+ free(debug_prefix_map); debug_prefix_map = NULL;
+ free(profile_dir); profile_dir = NULL;
+ free(included_pch_file); included_pch_file = NULL;
+ args_free(orig_args); orig_args = NULL;
+ free(input_file); input_file = NULL;
+ free(output_obj); output_obj = NULL;
+ free(output_dwo); output_dwo = NULL;
+ free(output_dep); output_dep = NULL;
+ free(output_cov); output_cov = NULL;
+ free(output_dia); output_dia = NULL;
+ free(cached_obj_hash); cached_obj_hash = NULL;
+ free(cached_obj); cached_obj = NULL;
+ free(cached_dwo); cached_dwo = NULL;
+ free(cached_stderr); cached_stderr = NULL;
+ free(cached_dep); cached_dep = NULL;
+ free(cached_cov); cached_cov = NULL;
+ free(cached_dia); cached_dia = NULL;
+ free(manifest_path); manifest_path = NULL;
+ time_of_compilation = 0;
+ for (size_t i = 0; i < ignore_headers_len; i++) {
+ free(ignore_headers[i]);
+ ignore_headers[i] = NULL;
+ }
+ free(ignore_headers); ignore_headers = NULL;
+ ignore_headers_len = 0;
+ if (included_files) {
+ hashtable_destroy(included_files, 1); included_files = NULL;
+ }
+ has_absolute_include_headers = false;
+ generating_debuginfo = false;
+ generating_dependencies = false;
+ generating_coverage = false;
+ profile_arcs = false;
+ free(profile_dir); profile_dir = NULL;
+ i_tmpfile = NULL;
+ direct_i_file = false;
+ free(cpp_stderr); cpp_stderr = NULL;
+ free(stats_file); stats_file = NULL;
+ output_is_precompiled_header = false;
+
+ conf = conf_create();
+ using_split_dwarf = false;
+}
+
+// Make a copy of stderr that will not be cached, so things like distcc can
+// send networking errors to it.
+static void
+setup_uncached_err(void)
+{
+ int uncached_fd = dup(2);
+ if (uncached_fd == -1) {
+ cc_log("dup(2) failed: %s", strerror(errno));
+ failed();
+ }
+
+ // Leak a pointer to the environment.
+ char *buf = format("UNCACHED_ERR_FD=%d", uncached_fd);
+ if (putenv(buf) == -1) {
+ cc_log("putenv failed: %s", strerror(errno));
+ failed();
+ }
+}
+
+static void
+configuration_logger(const char *descr, const char *origin, void *context)
+{
+ (void)context;
+ cc_bulklog("Config: (%s) %s", origin, descr);
+}
+
+// The main ccache driver function.
+static void
+ccache(int argc, char *argv[])
+{
+#ifndef _WIN32
+ set_up_signal_handlers();
+#endif
+
+ orig_args = args_init(argc, argv);
+
+ initialize();
+ find_compiler(argv);
+
+ if (str_eq(conf->temporary_dir, "")) {
+ clean_up_internal_tempdir();
+ }
+
+ if (!str_eq(conf->log_file, "")) {
+ conf_print_items(conf, configuration_logger, NULL);
+ }
+
+ if (conf->disable) {
+ cc_log("ccache is disabled");
+ failed();
+ }
+
+ setup_uncached_err();
+
+ cc_log_argv("Command line: ", argv);
+ cc_log("Hostname: %s", get_hostname());
+ cc_log("Working directory: %s", get_current_working_dir());
+
+ if (conf->unify) {
+ cc_log("Direct mode disabled because unify mode is enabled");
+ conf->direct_mode = false;
+ }
+
+ conf->limit_multiple = MIN(MAX(conf->limit_multiple, 0.0), 1.0);
+
+ // Arguments (except -E) to send to the preprocessor.
+ struct args *preprocessor_args;
+ // Arguments to send to the real compiler.
+ struct args *compiler_args;
+ if (!cc_process_args(orig_args, &preprocessor_args, &compiler_args)) {
+ failed();
+ }
+
+ cc_log("Source file: %s", input_file);
+ if (generating_dependencies) {
+ cc_log("Dependency file: %s", output_dep);
+ }
+ if (generating_coverage) {
+ cc_log("Coverage file: %s", output_cov);
+ }
+ if (output_dia) {
+ cc_log("Diagnostic file: %s", output_dia);
+ }
+
+ if (using_split_dwarf) {
+ if (!generating_dependencies) {
+ assert(output_dwo);
+ }
+ } else {
+ assert(!output_dwo);
+ }
+
+ if (output_dwo) {
+ cc_log("Split dwarf file: %s", output_dwo);
+ }
+
+ cc_log("Object file: %s", output_obj);
+
+ struct mdfour common_hash;
+ hash_start(&common_hash);
+ calculate_common_hash(preprocessor_args, &common_hash);
+
+ // Try to find the hash using the manifest.
+ struct mdfour direct_hash = common_hash;
+ bool put_object_in_manifest = false;
+ struct file_hash *object_hash = NULL;
+ struct file_hash *object_hash_from_manifest = NULL;
+ if (conf->direct_mode) {
+ cc_log("Trying direct lookup");
+ object_hash = calculate_object_hash(preprocessor_args, &direct_hash, 1);
+ if (object_hash) {
+ update_cached_result_globals(object_hash);
+
+ // If we can return from cache at this point then do so.
+ from_cache(FROMCACHE_DIRECT_MODE, 0);
+
+ // Wasn't able to return from cache at this point. However, the object
+ // was already found in manifest, so don't readd it later.
+ put_object_in_manifest = false;
+
+ object_hash_from_manifest = object_hash;
+ } else {
+ // Add object to manifest later.
+ put_object_in_manifest = true;
+ }
+ }
+
+ if (conf->read_only_direct) {
+ cc_log("Read-only direct mode; running real compiler");
+ failed();
+ }
+
+ // Find the hash using the preprocessed output. Also updates included_files.
+ struct mdfour cpp_hash = common_hash;
+ object_hash = calculate_object_hash(preprocessor_args, &cpp_hash, 0);
+ if (!object_hash) {
+ fatal("internal error: object hash from cpp returned NULL");
+ }
+ update_cached_result_globals(object_hash);
+
+ if (object_hash_from_manifest
+ && !file_hashes_equal(object_hash_from_manifest, object_hash)) {
+ // The hash from manifest differs from the hash of the preprocessor output.
+ // This could be because:
+ //
+ // - The preprocessor produces different output for the same input (not
+ // likely).
+ // - There's a bug in ccache (maybe incorrect handling of compiler
+ // arguments).
+ // - The user has used a different CCACHE_BASEDIR (most likely).
+ //
+ // The best thing here would probably be to remove the hash entry from the
+ // manifest. For now, we use a simpler method: just remove the manifest
+ // file.
+ cc_log("Hash from manifest doesn't match preprocessor output");
+ cc_log("Likely reason: different CCACHE_BASEDIRs used");
+ cc_log("Removing manifest as a safety measure");
+ x_unlink(manifest_path);
+
+ put_object_in_manifest = true;
+ }
+
+ // If we can return from cache at this point then do.
+ from_cache(FROMCACHE_CPP_MODE, put_object_in_manifest);
+
+ if (conf->read_only) {
+ cc_log("Read-only mode; running real compiler");
+ failed();
+ }
+
+ add_prefix(compiler_args, conf->prefix_command);
+
+ // Run real compiler, sending output to cache.
+ to_cache(compiler_args);
+
+ x_exit(0);
+}
+
+static void
+configuration_printer(const char *descr, const char *origin, void *context)
+{
+ assert(context);
+ fprintf(context, "(%s) %s\n", origin, descr);
+}
+
+// The main program when not doing a compile.
+static int
+ccache_main_options(int argc, char *argv[])
+{
+ enum longopts {
+ DUMP_MANIFEST
+ };
+ static const struct option options[] = {
+ {"cleanup", no_argument, 0, 'c'},
+ {"clear", no_argument, 0, 'C'},
+ {"dump-manifest", required_argument, 0, DUMP_MANIFEST},
+ {"help", no_argument, 0, 'h'},
+ {"max-files", required_argument, 0, 'F'},
+ {"max-size", required_argument, 0, 'M'},
+ {"set-config", required_argument, 0, 'o'},
+ {"print-config", no_argument, 0, 'p'},
+ {"show-stats", no_argument, 0, 's'},
+ {"version", no_argument, 0, 'V'},
+ {"zero-stats", no_argument, 0, 'z'},
+ {0, 0, 0, 0}
+ };
+
+ int c;
+ while ((c = getopt_long(argc, argv, "cChF:M:o:psVz", options, NULL)) != -1) {
+ switch (c) {
+ case DUMP_MANIFEST:
+ manifest_dump(optarg, stdout);
+ break;
+
+ case 'c': // --cleanup
+ initialize();
+ cleanup_all(conf);
+ printf("Cleaned cache\n");
+ break;
+
+ case 'C': // --clear
+ initialize();
+ wipe_all(conf);
+ printf("Cleared cache\n");
+ break;
+
+ case 'h': // --help
+ fputs(USAGE_TEXT, stdout);
+ x_exit(0);
+
+ case 'F': // --max-files
+ {
+ initialize();
+ char *errmsg;
+ if (conf_set_value_in_file(primary_config_path, "max_files", optarg,
+ &errmsg)) {
+ unsigned files = atoi(optarg);
+ if (files == 0) {
+ printf("Unset cache file limit\n");
+ } else {
+ printf("Set cache file limit to %u\n", files);
+ }
+ } else {
+ fatal("could not set cache file limit: %s", errmsg);
+ }
+ }
+ break;
+
+ case 'M': // --max-size
+ {
+ initialize();
+ uint64_t size;
+ if (!parse_size_with_suffix(optarg, &size)) {
+ fatal("invalid size: %s", optarg);
+ }
+ char *errmsg;
+ if (conf_set_value_in_file(primary_config_path, "max_size", optarg,
+ &errmsg)) {
+ if (size == 0) {
+ printf("Unset cache size limit\n");
+ } else {
+ char *s = format_human_readable_size(size);
+ printf("Set cache size limit to %s\n", s);
+ free(s);
+ }
+ } else {
+ fatal("could not set cache size limit: %s", errmsg);
+ }
+ }
+ break;
+
+ case 'o': // --set-config
+ {
+ initialize();
+ char *p = strchr(optarg, '=');
+ if (!p) {
+ fatal("missing equal sign in \"%s\"", optarg);
+ }
+ char *key = x_strndup(optarg, p - optarg);
+ char *value = p + 1;
+ char *errmsg;
+ if (!conf_set_value_in_file(primary_config_path, key, value, &errmsg)) {
+ fatal("%s", errmsg);
+ }
+ free(key);
+ }
+ break;
+
+ case 'p': // --print-config
+ initialize();
+ conf_print_items(conf, configuration_printer, stdout);
+ break;
+
+ case 's': // --show-stats
+ initialize();
+ stats_summary(conf);
+ break;
+
+ case 'V': // --version
+ fprintf(stdout, VERSION_TEXT, CCACHE_VERSION);
+ x_exit(0);
+
+ case 'z': // --zero-stats
+ initialize();
+ stats_zero();
+ printf("Statistics cleared\n");
+ break;
+
+ default:
+ fputs(USAGE_TEXT, stderr);
+ x_exit(1);
+ }
+ }
+
+ return 0;
+}
+
+int
+ccache_main(int argc, char *argv[])
+{
+ // Check if we are being invoked as "ccache".
+ char *program_name = basename(argv[0]);
+ if (same_executable_name(program_name, MYNAME)) {
+ if (argc < 2) {
+ fputs(USAGE_TEXT, stderr);
+ x_exit(1);
+ }
+ // If the first argument isn't an option, then assume we are being passed a
+ // compiler name and options.
+ if (argv[1][0] == '-') {
+ return ccache_main_options(argc, argv);
+ }
+ }
+ free(program_name);
+
+ ccache(argc, argv);
+ return 1;
+}
diff --git a/ccache.h b/ccache.h
new file mode 100644
index 0000000..8b738ab
--- /dev/null
+++ b/ccache.h
@@ -0,0 +1,298 @@
+#ifndef CCACHE_H
+#define CCACHE_H
+
+#include "system.h"
+#include "mdfour.h"
+#include "conf.h"
+#include "counters.h"
+
+#ifdef __GNUC__
+#define ATTR_FORMAT(x, y, z) __attribute__((format (x, y, z)))
+#define ATTR_NORETURN __attribute__((noreturn));
+#else
+#define ATTR_FORMAT(x, y, z)
+#define ATTR_NORETURN
+#endif
+
+#ifndef MYNAME
+#define MYNAME "ccache"
+#endif
+
+extern const char CCACHE_VERSION[];
+
+// Statistics fields in storage order.
+enum stats {
+ STATS_NONE = 0,
+ STATS_STDOUT = 1,
+ STATS_STATUS = 2,
+ STATS_ERROR = 3,
+ STATS_TOCACHE = 4,
+ STATS_PREPROCESSOR = 5,
+ STATS_COMPILER = 6,
+ STATS_MISSING = 7,
+ STATS_CACHEHIT_CPP = 8,
+ STATS_ARGS = 9,
+ STATS_LINK = 10,
+ STATS_NUMFILES = 11,
+ STATS_TOTALSIZE = 12,
+ STATS_OBSOLETE_MAXFILES = 13,
+ STATS_OBSOLETE_MAXSIZE = 14,
+ STATS_SOURCELANG = 15,
+ STATS_DEVICE = 16,
+ STATS_NOINPUT = 17,
+ STATS_MULTIPLE = 18,
+ STATS_CONFTEST = 19,
+ STATS_UNSUPPORTED_OPTION = 20,
+ STATS_OUTSTDOUT = 21,
+ STATS_CACHEHIT_DIR = 22,
+ STATS_NOOUTPUT = 23,
+ STATS_EMPTYOUTPUT = 24,
+ STATS_BADEXTRAFILE = 25,
+ STATS_COMPCHECK = 26,
+ STATS_CANTUSEPCH = 27,
+ STATS_PREPROCESSING = 28,
+ STATS_NUMCLEANUPS = 29,
+ STATS_UNSUPPORTED_DIRECTIVE = 30,
+
+ STATS_END
+};
+
+#define SLOPPY_INCLUDE_FILE_MTIME 1
+#define SLOPPY_INCLUDE_FILE_CTIME 2
+#define SLOPPY_FILE_MACRO 4
+#define SLOPPY_TIME_MACROS 8
+#define SLOPPY_PCH_DEFINES 16
+// Allow us to match files based on their stats (size, mtime, ctime), without
+// looking at their contents.
+#define SLOPPY_FILE_STAT_MATCHES 32
+// Allow us to not include any system headers in the manifest include files,
+// similar to -MM versus -M for dependencies.
+#define SLOPPY_NO_SYSTEM_HEADERS 64
+
+#define str_eq(s1, s2) (strcmp((s1), (s2)) == 0)
+#define str_startswith(s, prefix) \
+ (strncmp((s), (prefix), strlen((prefix))) == 0)
+#define str_endswith(s, suffix) \
+ (strlen(s) >= strlen(suffix) \
+ && str_eq((s) + strlen(s) - strlen(suffix), (suffix)))
+
+// Buffer size for I/O operations. Should be a multiple of 4 KiB.
+#define READ_BUFFER_SIZE 65536
+
+// ----------------------------------------------------------------------------
+// args.c
+
+struct args {
+ char **argv;
+ int argc;
+};
+
+struct args *args_init(int, char **);
+struct args *args_init_from_string(const char *);
+struct args *args_init_from_gcc_atfile(const char *filename);
+struct args *args_copy(struct args *args);
+void args_free(struct args *args);
+void args_add(struct args *args, const char *s);
+void args_add_prefix(struct args *args, const char *s);
+void args_extend(struct args *args, struct args *to_append);
+void args_insert(struct args *dest, int index, struct args *src, bool replace);
+void args_pop(struct args *args, int n);
+void args_set(struct args *args, int index, const char *value);
+void args_strip(struct args *args, const char *prefix);
+void args_remove_first(struct args *args);
+char *args_to_string(struct args *args);
+bool args_equal(struct args *args1, struct args *args2);
+
+// ----------------------------------------------------------------------------
+// hash.c
+
+void hash_start(struct mdfour *md);
+void hash_buffer(struct mdfour *md, const void *s, size_t len);
+char *hash_result(struct mdfour *md);
+void hash_result_as_bytes(struct mdfour *md, unsigned char *out);
+bool hash_equal(struct mdfour *md1, struct mdfour *md2);
+void hash_delimiter(struct mdfour *md, const char *type);
+void hash_string(struct mdfour *md, const char *s);
+void hash_string_length(struct mdfour *md, const char *s, int length);
+void hash_int(struct mdfour *md, int x);
+bool hash_fd(struct mdfour *md, int fd);
+bool hash_file(struct mdfour *md, const char *fname);
+
+// ----------------------------------------------------------------------------
+// util.c
+
+void cc_log(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
+void cc_bulklog(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
+void cc_log_argv(const char *prefix, char **argv);
+void fatal(const char *format, ...) ATTR_FORMAT(printf, 1, 2) ATTR_NORETURN;
+
+void copy_fd(int fd_in, int fd_out);
+int copy_file(const char *src, const char *dest, int compress_level);
+int move_file(const char *src, const char *dest, int compress_level);
+int move_uncompressed_file(const char *src, const char *dest,
+ int compress_level);
+bool file_is_compressed(const char *filename);
+int create_dir(const char *dir);
+int create_parent_dirs(const char *path);
+const char *get_hostname(void);
+const char *tmp_string(void);
+char *format_hash_as_string(const unsigned char *hash, int size);
+int create_cachedirtag(const char *dir);
+char *format(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
+void reformat(char **ptr, const char *format, ...) ATTR_FORMAT(printf, 2, 3);
+char *x_strdup(const char *s);
+char *x_strndup(const char *s, size_t n);
+void *x_malloc(size_t size);
+void *x_calloc(size_t nmemb, size_t size);
+void *x_realloc(void *ptr, size_t size);
+void x_unsetenv(const char *name);
+int x_fstat(int fd, struct stat *buf);
+int x_lstat(const char *pathname, struct stat *buf);
+int x_stat(const char *pathname, struct stat *buf);
+void traverse(const char *dir, void (*fn)(const char *, struct stat *));
+char *basename(const char *path);
+char *dirname(const char *path);
+const char *get_extension(const char *path);
+char *remove_extension(const char *path);
+size_t file_size(struct stat *st);
+char *format_human_readable_size(uint64_t size);
+char *format_parsable_size_with_suffix(uint64_t size);
+bool parse_size_with_suffix(const char *str, uint64_t *size);
+char *x_realpath(const char *path);
+char *gnu_getcwd(void);
+#ifndef HAVE_STRTOK_R
+char *strtok_r(char *str, const char *delim, char **saveptr);
+#endif
+int create_tmp_fd(char **fname);
+FILE *create_tmp_file(char **fname, const char *mode);
+const char *get_home_directory(void);
+char *get_cwd(void);
+bool same_executable_name(const char *s1, const char *s2);
+size_t common_dir_prefix_length(const char *s1, const char *s2);
+char *get_relative_path(const char *from, const char *to);
+bool is_absolute_path(const char *path);
+bool is_full_path(const char *path);
+bool is_symlink(const char *path);
+void update_mtime(const char *path);
+void x_exit(int status) ATTR_NORETURN;
+int x_rename(const char *oldpath, const char *newpath);
+int tmp_unlink(const char *path);
+int x_unlink(const char *path);
+#ifndef _WIN32
+char *x_readlink(const char *path);
+#endif
+bool read_file(const char *path, size_t size_hint, char **data, size_t *size);
+char *read_text_file(const char *path, size_t size_hint);
+char *subst_env_in_string(const char *str, char **errmsg);
+
+// ----------------------------------------------------------------------------
+// stats.c
+
+void stats_update(enum stats stat);
+void stats_flush(void);
+unsigned stats_get_pending(enum stats stat);
+void stats_zero(void);
+void stats_summary(struct conf *conf);
+void stats_update_size(uint64_t size, unsigned files);
+void stats_get_obsolete_limits(const char *dir, unsigned *maxfiles,
+ uint64_t *maxsize);
+void stats_set_sizes(const char *dir, unsigned num_files, uint64_t total_size);
+void stats_add_cleanup(const char *dir, unsigned count);
+void stats_read(const char *path, struct counters *counters);
+void stats_write(const char *path, struct counters *counters);
+
+// ----------------------------------------------------------------------------
+// unify.c
+
+int unify_hash(struct mdfour *hash, const char *fname);
+
+// ----------------------------------------------------------------------------
+// exitfn.c
+
+void exitfn_init(void);
+void exitfn_add_nullary(void (*function)(void));
+void exitfn_add(void (*function)(void *), void *context);
+void exitfn_call(void);
+
+// ----------------------------------------------------------------------------
+// cleanup.c
+
+void cleanup_dir(struct conf *conf, const char *dir);
+void cleanup_all(struct conf *conf);
+void wipe_all(struct conf *conf);
+
+// ----------------------------------------------------------------------------
+// execute.c
+
+int execute(char **argv, int fd_out, int fd_err, pid_t *pid);
+char *find_executable(const char *name, const char *exclude_name);
+void print_command(FILE *fp, char **argv);
+
+// ----------------------------------------------------------------------------
+// lockfile.c
+
+bool lockfile_acquire(const char *path, unsigned staleness_limit);
+void lockfile_release(const char *path);
+
+// ----------------------------------------------------------------------------
+// ccache.c
+
+extern time_t time_of_compilation;
+void block_signals(void);
+void unblock_signals(void);
+bool cc_process_args(struct args *args, struct args **preprocessor_args,
+ struct args **compiler_args);
+void cc_reset(void);
+bool is_precompiled_header(const char *path);
+
+// ----------------------------------------------------------------------------
+
+#if HAVE_COMPAR_FN_T
+#define COMPAR_FN_T __compar_fn_t
+#else
+typedef int (*COMPAR_FN_T)(const void *, const void *);
+#endif
+
+// Work with silly DOS binary open.
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+// mkstemp() on some versions of cygwin don't handle binary files, so override.
+#ifdef __CYGWIN__
+#undef HAVE_MKSTEMP
+#endif
+
+#ifdef _WIN32
+char *win32argvtos(char *prefix, char **argv);
+char *win32getshell(char *path);
+int win32execute(char *path, char **argv, int doreturn,
+ int fd_stdout, int fd_stderr);
+void add_exe_ext_if_no_to_fullpath(char *full_path_win_ext, size_t max_size,
+ const char *ext, const char *path);
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0501
+# endif
+# include <windows.h>
+# define mkdir(a,b) mkdir(a)
+# define link(src,dst) (CreateHardLink(dst,src,NULL) ? 0 : -1)
+# define lstat(a,b) stat(a,b)
+# define execv(a,b) win32execute(a,b,0,-1,-1)
+# define execute(a,b,c,d) win32execute(*(a),a,1,b,c)
+# define DIR_DELIM_CH '/'
+# define PATH_DELIM ";"
+# define F_RDLCK 0
+# define F_WRLCK 0
+#else
+# define DIR_DELIM_CH '\\'
+# define PATH_DELIM ":"
+#endif
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif // ifndef CCACHE_H
diff --git a/cleanup.c b/cleanup.c
new file mode 100644
index 0000000..428a64b
--- /dev/null
+++ b/cleanup.c
@@ -0,0 +1,275 @@
+// Copyright (C) 2002-2006 Andrew Tridgell
+// Copyright (C) 2009-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+
+static struct files {
+ char *fname;
+ time_t mtime;
+ uint64_t size;
+} **files;
+static unsigned allocated; // Size of the files array.
+static unsigned num_files; // Number of used entries in the files array.
+
+static uint64_t cache_size;
+static size_t files_in_cache;
+static uint64_t cache_size_threshold;
+static size_t files_in_cache_threshold;
+
+// File comparison function that orders files in mtime order, oldest first.
+static int
+files_compare(struct files **f1, struct files **f2)
+{
+ if ((*f2)->mtime == (*f1)->mtime) {
+ return strcmp((*f1)->fname, (*f2)->fname);
+ }
+ if ((*f2)->mtime > (*f1)->mtime) {
+ return -1;
+ }
+ return 1;
+}
+
+// This builds the list of files in the cache.
+static void
+traverse_fn(const char *fname, struct stat *st)
+{
+ if (!S_ISREG(st->st_mode)) {
+ return;
+ }
+
+ char *p = basename(fname);
+ if (str_eq(p, "stats")) {
+ goto out;
+ }
+
+ if (str_startswith(p, ".nfs")) {
+ // Ignore temporary NFS files that may be left for open but deleted files.
+ goto out;
+ }
+
+ // Delete any tmp files older than 1 hour.
+ if (strstr(p, ".tmp.") && st->st_mtime + 3600 < time(NULL)) {
+ x_unlink(fname);
+ goto out;
+ }
+
+ if (strstr(p, "CACHEDIR.TAG")) {
+ goto out;
+ }
+
+ if (num_files == allocated) {
+ allocated = 10000 + num_files*2;
+ files = (struct files **)x_realloc(files, sizeof(struct files *)*allocated);
+ }
+
+ files[num_files] = (struct files *)x_malloc(sizeof(struct files));
+ files[num_files]->fname = x_strdup(fname);
+ files[num_files]->mtime = st->st_mtime;
+ files[num_files]->size = file_size(st);
+ cache_size += files[num_files]->size;
+ files_in_cache++;
+ num_files++;
+
+out:
+ free(p);
+}
+
+static void
+delete_file(const char *path, size_t size)
+{
+ if (x_unlink(path) == 0) {
+ cache_size -= size;
+ files_in_cache--;
+ } else if (errno != ENOENT && errno != ESTALE) {
+ cc_log("Failed to unlink %s (%s)", path, strerror(errno));
+ }
+}
+
+static void
+delete_sibling_file(const char *base, const char *extension)
+{
+ struct stat st;
+ char *path = format("%s%s", base, extension);
+ if (lstat(path, &st) == 0) {
+ delete_file(path, file_size(&st));
+ } else if (errno != ENOENT && errno != ESTALE) {
+ cc_log("Failed to stat %s: %s", path, strerror(errno));
+ }
+ free(path);
+}
+
+// Sort the files we've found and delete the oldest ones until we are below the
+// thresholds.
+static bool
+sort_and_clean(void)
+{
+ if (num_files > 1) {
+ // Sort in ascending mtime order.
+ qsort(files, num_files, sizeof(struct files *), (COMPAR_FN_T)files_compare);
+ }
+
+ // Delete enough files to bring us below the threshold.
+ char *last_base = x_strdup("");
+ bool cleaned = false;
+ for (unsigned i = 0; i < num_files; i++) {
+ const char *ext;
+
+ if ((cache_size_threshold == 0
+ || cache_size <= cache_size_threshold)
+ && (files_in_cache_threshold == 0
+ || files_in_cache <= files_in_cache_threshold)) {
+ break;
+ }
+
+ ext = get_extension(files[i]->fname);
+ if (str_eq(ext, ".o")
+ || str_eq(ext, ".d")
+ || str_eq(ext, ".gcno")
+ || str_eq(ext, ".dia")
+ || str_eq(ext, ".stderr")
+ || str_eq(ext, "")) {
+ char *base = remove_extension(files[i]->fname);
+ if (!str_eq(base, last_base)) { // Avoid redundant unlinks.
+ // Make sure that all sibling files are deleted so that a cached result
+ // is removed completely. Note the order of deletions -- the stderr
+ // file must be deleted last because if the ccache process gets killed
+ // after deleting the .stderr but before deleting the .o, the cached
+ // result would be inconsistent.
+ delete_sibling_file(base, ".o");
+ delete_sibling_file(base, ".d");
+ delete_sibling_file(base, ".gcno");
+ delete_sibling_file(base, ".dia");
+ delete_sibling_file(base, ".stderr");
+ delete_sibling_file(base, ""); // Object file from ccache 2.4.
+ }
+ free(last_base);
+ last_base = base;
+ } else {
+ // .manifest or unknown file.
+ delete_file(files[i]->fname, files[i]->size);
+ }
+ cleaned = true;
+ }
+ free(last_base);
+ return cleaned;
+}
+
+// Clean up one cache subdirectory.
+void
+cleanup_dir(struct conf *conf, const char *dir)
+{
+ cc_log("Cleaning up cache directory %s", dir);
+
+ // When "max files" or "max cache size" is reached, one of the 16 cache
+ // subdirectories is cleaned up. When doing so, files are deleted (in LRU
+ // order) until the levels are below limit_multiple.
+ cache_size_threshold = conf->max_size * conf->limit_multiple / 16;
+ files_in_cache_threshold = conf->max_files * conf->limit_multiple / 16;
+
+ num_files = 0;
+ cache_size = 0;
+ files_in_cache = 0;
+
+ // Build a list of files.
+ traverse(dir, traverse_fn);
+
+ // Clean the cache.
+ bool cleaned = sort_and_clean();
+ if (cleaned) {
+ cc_log("Cleaned up cache directory %s", dir);
+ stats_add_cleanup(dir, 1);
+ }
+
+ stats_set_sizes(dir, files_in_cache, cache_size);
+
+ // Free it up.
+ for (unsigned i = 0; i < num_files; i++) {
+ free(files[i]->fname);
+ free(files[i]);
+ files[i] = NULL;
+ }
+ if (files) {
+ free(files);
+ }
+ allocated = 0;
+ files = NULL;
+
+ num_files = 0;
+ cache_size = 0;
+ files_in_cache = 0;
+}
+
+// Clean up all cache subdirectories.
+void cleanup_all(struct conf *conf)
+{
+ for (int i = 0; i <= 0xF; i++) {
+ char *dname = format("%s/%1x", conf->cache_dir, i);
+ cleanup_dir(conf, dname);
+ free(dname);
+ }
+}
+
+// Traverse function for wiping files.
+static void wipe_fn(const char *fname, struct stat *st)
+{
+ if (!S_ISREG(st->st_mode)) {
+ return;
+ }
+
+ char *p = basename(fname);
+ if (str_eq(p, "stats")) {
+ free(p);
+ return;
+ }
+ free(p);
+
+ files_in_cache++;
+
+ x_unlink(fname);
+}
+
+// Wipe one cache subdirectory.
+void
+wipe_dir(struct conf *conf, const char *dir)
+{
+ cc_log("Clearing out cache directory %s", dir);
+
+ files_in_cache_threshold = conf->max_files * conf->limit_multiple / 16;
+ files_in_cache = 0;
+
+ traverse(dir, wipe_fn);
+
+ if (files_in_cache > 0) {
+ cc_log("Cleared out cache directory %s", dir);
+ stats_add_cleanup(dir, 1);
+ }
+
+ files_in_cache = 0;
+}
+
+// Wipe all cached files in all subdirectories.
+void wipe_all(struct conf *conf)
+{
+ for (int i = 0; i <= 0xF; i++) {
+ char *dname = format("%s/%1x", conf->cache_dir, i);
+ wipe_dir(conf, dname);
+ free(dname);
+ }
+
+ // Fix the counters.
+ cleanup_all(conf);
+}
diff --git a/compopt.c b/compopt.c
new file mode 100644
index 0000000..e5bee23
--- /dev/null
+++ b/compopt.c
@@ -0,0 +1,201 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+#include "compopt.h"
+
+#define TOO_HARD (1 << 0)
+#define TOO_HARD_DIRECT (1 << 1)
+#define TAKES_ARG (1 << 2)
+#define TAKES_CONCAT_ARG (1 << 3)
+#define TAKES_PATH (1 << 4)
+#define AFFECTS_CPP (1 << 5)
+
+struct compopt {
+ const char *name;
+ int type;
+};
+
+static const struct compopt compopts[] = {
+ {"--param", TAKES_ARG},
+ {"--save-temps", TOO_HARD},
+ {"--serialize-diagnostics", TAKES_ARG | TAKES_PATH},
+ {"-A", TAKES_ARG},
+ {"-B", TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-D", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG},
+ {"-E", TOO_HARD},
+ {"-F", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-G", TAKES_ARG},
+ {"-I", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-L", TAKES_ARG},
+ {"-M", TOO_HARD},
+ {"-MF", TAKES_ARG},
+ {"-MM", TOO_HARD},
+ {"-MQ", TAKES_ARG},
+ {"-MT", TAKES_ARG},
+ {"-P", TOO_HARD},
+ {"-U", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG},
+ {"-V", TAKES_ARG},
+ {"-Xassembler", TAKES_ARG},
+ {"-Xclang", TAKES_ARG},
+ {"-Xlinker", TAKES_ARG},
+ {"-Xpreprocessor", AFFECTS_CPP | TOO_HARD_DIRECT | TAKES_ARG},
+ {"-arch", TAKES_ARG},
+ {"-aux-info", TAKES_ARG},
+ {"-b", TAKES_ARG},
+ {"-fmodules", TOO_HARD},
+ {"-fno-working-directory", AFFECTS_CPP},
+ {"-fplugin=libcc1plugin", TOO_HARD}, // interaction with GDB
+ {"-frepo", TOO_HARD},
+ {"-fstack-usage", TOO_HARD},
+ {"-fworking-directory", AFFECTS_CPP},
+ {"-idirafter", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-iframework", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-imacros", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-imultilib", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-include", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-include-pch", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-install_name", TAKES_ARG}, // Darwin linker option
+ {"-iprefix", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-iquote", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-isysroot", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-isystem", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-iwithprefix", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-iwithprefixbefore",
+ AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-nostdinc", AFFECTS_CPP},
+ {"-nostdinc++", AFFECTS_CPP},
+ {"-remap", AFFECTS_CPP},
+ {"-save-temps", TOO_HARD},
+ {"-stdlib=", AFFECTS_CPP | TAKES_CONCAT_ARG},
+ {"-trigraphs", AFFECTS_CPP},
+ {"-u", TAKES_ARG | TAKES_CONCAT_ARG},
+};
+
+
+static int
+compare_compopts(const void *key1, const void *key2)
+{
+ const struct compopt *opt1 = (const struct compopt *)key1;
+ const struct compopt *opt2 = (const struct compopt *)key2;
+ return strcmp(opt1->name, opt2->name);
+}
+
+static int
+compare_prefix_compopts(const void *key1, const void *key2)
+{
+ const struct compopt *opt1 = (const struct compopt *)key1;
+ const struct compopt *opt2 = (const struct compopt *)key2;
+ return strncmp(opt1->name, opt2->name, strlen(opt2->name));
+}
+
+static const struct compopt *
+find(const char *option)
+{
+ struct compopt key;
+ key.name = option;
+ return bsearch(
+ &key, compopts, sizeof(compopts) / sizeof(compopts[0]),
+ sizeof(compopts[0]), compare_compopts);
+}
+
+static const struct compopt *
+find_prefix(const char *option)
+{
+ struct compopt key;
+ key.name = option;
+ return bsearch(
+ &key, compopts, sizeof(compopts) / sizeof(compopts[0]),
+ sizeof(compopts[0]), compare_prefix_compopts);
+}
+
+// Runs fn on the first two characters of option.
+bool
+compopt_short(bool (*fn)(const char *), const char *option)
+{
+ char *short_opt = x_strndup(option, 2);
+ bool retval = fn(short_opt);
+ free(short_opt);
+ return retval;
+}
+
+// For test purposes.
+bool
+compopt_verify_sortedness(void)
+{
+ for (size_t i = 1; i < sizeof(compopts)/sizeof(compopts[0]); i++) {
+ if (strcmp(compopts[i-1].name, compopts[i].name) >= 0) {
+ fprintf(stderr,
+ "compopt_verify_sortedness: %s >= %s\n",
+ compopts[i-1].name,
+ compopts[i].name);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+compopt_affects_cpp(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & AFFECTS_CPP);
+}
+
+bool
+compopt_too_hard(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TOO_HARD);
+}
+
+bool
+compopt_too_hard_for_direct_mode(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TOO_HARD_DIRECT);
+}
+
+bool
+compopt_takes_path(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TAKES_PATH);
+}
+
+bool
+compopt_takes_arg(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TAKES_ARG);
+}
+
+bool
+compopt_takes_concat_arg(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TAKES_CONCAT_ARG);
+}
+
+// Determines if the prefix of the option matches any option and affects the
+// preprocessor.
+bool
+compopt_prefix_affects_cpp(const char *option)
+{
+ // Prefix options have to take concatentated args.
+ const struct compopt *co = find_prefix(option);
+ return co && (co->type & TAKES_CONCAT_ARG) && (co->type & AFFECTS_CPP);
+}
diff --git a/compopt.h b/compopt.h
new file mode 100644
index 0000000..d72639f
--- /dev/null
+++ b/compopt.h
@@ -0,0 +1,15 @@
+#ifndef CCACHE_COMPOPT_H
+#define CCACHE_COMPOPT_H
+
+#include "system.h"
+
+bool compopt_short(bool (*fn)(const char *option), const char *option);
+bool compopt_affects_cpp(const char *option);
+bool compopt_too_hard(const char *option);
+bool compopt_too_hard_for_direct_mode(const char *option);
+bool compopt_takes_path(const char *option);
+bool compopt_takes_arg(const char *option);
+bool compopt_takes_concat_arg(const char *option);
+bool compopt_prefix_affects_cpp(const char *option);
+
+#endif // CCACHE_COMPOPT_H
diff --git a/conf.c b/conf.c
new file mode 100644
index 0000000..cfa2874
--- /dev/null
+++ b/conf.c
@@ -0,0 +1,666 @@
+// Copyright (C) 2011-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "conf.h"
+#include "ccache.h"
+
+typedef bool (*conf_item_parser)(const char *str, void *result, char **errmsg);
+typedef bool (*conf_item_verifier)(void *value, char **errmsg);
+
+struct conf_item {
+ const char *name;
+ size_t number;
+ conf_item_parser parser;
+ size_t offset;
+ conf_item_verifier verifier;
+};
+
+struct env_to_conf_item {
+ const char *env_name;
+ const char *conf_name;
+};
+
+static bool
+parse_bool(const char *str, void *result, char **errmsg)
+{
+ bool *value = (bool *)result;
+
+ if (str_eq(str, "true")) {
+ *value = true;
+ return true;
+ } else if (str_eq(str, "false")) {
+ *value = false;
+ return true;
+ } else {
+ *errmsg = format("not a boolean value: \"%s\"", str);
+ return false;
+ }
+}
+
+static bool
+parse_env_string(const char *str, void *result, char **errmsg)
+{
+ char **value = (char **)result;
+ free(*value);
+ *value = subst_env_in_string(str, errmsg);
+ return *value != NULL;
+}
+
+static bool
+parse_float(const char *str, void *result, char **errmsg)
+{
+ float *value = (float *)result;
+ errno = 0;
+ char *endptr;
+ float x = strtof(str, &endptr);
+ if (errno == 0 && *str != '\0' && *endptr == '\0') {
+ *value = x;
+ return true;
+ } else {
+ *errmsg = format("invalid floating point: \"%s\"", str);
+ return false;
+ }
+}
+
+static bool
+parse_size(const char *str, void *result, char **errmsg)
+{
+ uint64_t *value = (uint64_t *)result;
+ uint64_t size;
+ if (parse_size_with_suffix(str, &size)) {
+ *value = size;
+ return true;
+ } else {
+ *errmsg = format("invalid size: \"%s\"", str);
+ return false;
+ }
+}
+
+static bool
+parse_sloppiness(const char *str, void *result, char **errmsg)
+{
+ unsigned *value = (unsigned *)result;
+ if (!str) {
+ return *value;
+ }
+
+ char *p = x_strdup(str);
+ char *q = p;
+ char *word;
+ char *saveptr = NULL;
+ while ((word = strtok_r(q, ", ", &saveptr))) {
+ if (str_eq(word, "file_macro")) {
+ *value |= SLOPPY_FILE_MACRO;
+ } else if (str_eq(word, "file_stat_matches")) {
+ *value |= SLOPPY_FILE_STAT_MATCHES;
+ } else if (str_eq(word, "include_file_ctime")) {
+ *value |= SLOPPY_INCLUDE_FILE_CTIME;
+ } else if (str_eq(word, "include_file_mtime")) {
+ *value |= SLOPPY_INCLUDE_FILE_MTIME;
+ } else if (str_eq(word, "no_system_headers")) {
+ *value |= SLOPPY_NO_SYSTEM_HEADERS;
+ } else if (str_eq(word, "pch_defines")) {
+ *value |= SLOPPY_PCH_DEFINES;
+ } else if (str_eq(word, "time_macros")) {
+ *value |= SLOPPY_TIME_MACROS;
+ } else {
+ *errmsg = format("unknown sloppiness: \"%s\"", word);
+ free(p);
+ return false;
+ }
+ q = NULL;
+ }
+ free(p);
+ return true;
+}
+
+static bool
+parse_string(const char *str, void *result, char **errmsg)
+{
+ (void)errmsg;
+
+ char **value = (char **)result;
+ free(*value);
+ *value = x_strdup(str);
+ return true;
+}
+
+static bool
+parse_umask(const char *str, void *result, char **errmsg)
+{
+ unsigned *value = (unsigned *)result;
+ if (str_eq(str, "")) {
+ *value = UINT_MAX;
+ return true;
+ }
+
+ errno = 0;
+ char *endptr;
+ *value = strtoul(str, &endptr, 8);
+ if (errno == 0 && *str != '\0' && *endptr == '\0') {
+ return true;
+ } else {
+ *errmsg = format("not an octal integer: \"%s\"", str);
+ return false;
+ }
+}
+
+static bool
+parse_unsigned(const char *str, void *result, char **errmsg)
+{
+ unsigned *value = (unsigned *)result;
+ errno = 0;
+ char *endptr;
+ long x = strtol(str, &endptr, 10);
+ if (errno == 0 && x >= 0 && *str != '\0' && *endptr == '\0') {
+ *value = x;
+ return true;
+ } else {
+ *errmsg = format("invalid unsigned integer: \"%s\"", str);
+ return false;
+ }
+}
+
+static const char *
+bool_to_string(bool value)
+{
+ return value ? "true" : "false";
+}
+
+static bool
+verify_absolute_path(void *value, char **errmsg)
+{
+ char **path = (char **)value;
+ assert(*path);
+ if (str_eq(*path, "")) {
+ // The empty string means "disable" in this case.
+ return true;
+ } else if (is_absolute_path(*path)) {
+ return true;
+ } else {
+ *errmsg = format("not an absolute path: \"%s\"", *path);
+ return false;
+ }
+}
+
+static bool
+verify_dir_levels(void *value, char **errmsg)
+{
+ unsigned *levels = (unsigned *)value;
+ assert(levels);
+ if (*levels >= 1 && *levels <= 8) {
+ return true;
+ } else {
+ *errmsg = format("cache directory levels must be between 1 and 8");
+ return false;
+ }
+}
+
+#define ITEM(name, type) \
+ parse_ ## type, offsetof(struct conf, name), NULL
+#define ITEM_V(name, type, verification) \
+ parse_ ## type, offsetof(struct conf, name), verify_ ## verification
+
+#include "confitems_lookup.c"
+#include "envtoconfitems_lookup.c"
+
+static const struct conf_item *
+find_conf(const char *name)
+{
+ return confitems_get(name, strlen(name));
+}
+
+static const struct env_to_conf_item *
+find_env_to_conf(const char *name)
+{
+ return envtoconfitems_get(name, strlen(name));
+}
+
+static bool
+handle_conf_setting(struct conf *conf, const char *key, const char *value,
+ char **errmsg, bool from_env_variable, bool negate_boolean,
+ const char *origin)
+{
+ const struct conf_item *item = find_conf(key);
+ if (!item) {
+ *errmsg = format("unknown configuration option \"%s\"", key);
+ return false;
+ }
+
+ if (from_env_variable && item->parser == parse_bool) {
+ // Special rule for boolean settings from the environment: any value means
+ // true.
+ bool *value = (bool *)((char *)conf + item->offset);
+ *value = !negate_boolean;
+ goto out;
+ }
+
+ if (!item->parser(value, (char *)conf + item->offset, errmsg)) {
+ return false;
+ }
+ if (item->verifier && !item->verifier((char *)conf + item->offset, errmsg)) {
+ return false;
+ }
+
+out:
+ conf->item_origins[item->number] = origin;
+ return true;
+}
+
+static bool
+parse_line(const char *line, char **key, char **value, char **errmsg)
+{
+#define SKIP_WS(x) while (isspace(*x)) { ++x; }
+
+ *key = NULL;
+ *value = NULL;
+
+ const char *p = line;
+ SKIP_WS(p);
+ if (*p == '\0' || *p == '#') {
+ return true;
+ }
+ const char *q = p;
+ while (isalpha(*q) || *q == '_') {
+ ++q;
+ }
+ *key = x_strndup(p, q - p);
+ p = q;
+ SKIP_WS(p);
+ if (*p != '=') {
+ *errmsg = x_strdup("missing equal sign");
+ free(*key);
+ *key = NULL;
+ return false;
+ }
+ ++p;
+
+ // Skip leading whitespace.
+ SKIP_WS(p);
+ q = p;
+ while (*q) {
+ ++q;
+ }
+ // Skip trailing whitespace.
+ while (isspace(q[-1])) {
+ --q;
+ }
+ *value = x_strndup(p, q - p);
+
+ return true;
+
+#undef SKIP_WS
+}
+
+// Create a conf struct with default values.
+struct conf *
+conf_create(void)
+{
+ struct conf *conf = x_malloc(sizeof(*conf));
+ conf->base_dir = x_strdup("");
+ conf->cache_dir = format("%s/.ccache", get_home_directory());
+ conf->cache_dir_levels = 2;
+ conf->compiler = x_strdup("");
+ conf->compiler_check = x_strdup("mtime");
+ conf->compression = false;
+ conf->compression_level = 6;
+ conf->cpp_extension = x_strdup("");
+ conf->direct_mode = true;
+ conf->disable = false;
+ conf->extra_files_to_hash = x_strdup("");
+ conf->hard_link = false;
+ conf->hash_dir = true;
+ conf->ignore_headers_in_manifest = x_strdup("");
+ conf->keep_comments_cpp = false;
+ conf->limit_multiple = 0.8f;
+ conf->log_file = x_strdup("");
+ conf->max_files = 0;
+ conf->max_size = (uint64_t)5 * 1000 * 1000 * 1000;
+ conf->path = x_strdup("");
+ conf->prefix_command = x_strdup("");
+ conf->prefix_command_cpp = x_strdup("");
+ conf->read_only = false;
+ conf->read_only_direct = false;
+ conf->recache = false;
+ conf->run_second_cpp = true;
+ conf->sloppiness = 0;
+ conf->stats = true;
+ conf->temporary_dir = x_strdup("");
+ conf->umask = UINT_MAX; // Default: don't set umask.
+ conf->unify = false;
+ conf->item_origins = x_malloc(CONFITEMS_TOTAL_KEYWORDS * sizeof(char *));
+ for (size_t i = 0; i < CONFITEMS_TOTAL_KEYWORDS; ++i) {
+ conf->item_origins[i] = "default";
+ }
+ return conf;
+}
+
+void
+conf_free(struct conf *conf)
+{
+ if (!conf) {
+ return;
+ }
+ free(conf->base_dir);
+ free(conf->cache_dir);
+ free(conf->compiler);
+ free(conf->compiler_check);
+ free(conf->cpp_extension);
+ free(conf->extra_files_to_hash);
+ free(conf->ignore_headers_in_manifest);
+ free(conf->log_file);
+ free(conf->path);
+ free(conf->prefix_command);
+ free(conf->prefix_command_cpp);
+ free(conf->temporary_dir);
+ free(conf->item_origins);
+ free(conf);
+}
+
+// Note: The path pointer is stored in conf, so path must outlive conf.
+bool
+conf_read(struct conf *conf, const char *path, char **errmsg)
+{
+ assert(errmsg);
+ *errmsg = NULL;
+
+ FILE *f = fopen(path, "r");
+ if (!f) {
+ *errmsg = format("%s: %s", path, strerror(errno));
+ return false;
+ }
+
+ unsigned line_number = 0;
+ bool result = true;
+ char buf[10000];
+ while (fgets(buf, sizeof(buf), f)) {
+ ++line_number;
+
+ char *key;
+ char *value;
+ char *errmsg2;
+ bool ok = parse_line(buf, &key, &value, &errmsg2);
+ if (ok && key) { // key == NULL if comment or blank line.
+ ok = handle_conf_setting(conf, key, value, &errmsg2, false, false, path);
+ }
+ free(key);
+ free(value);
+ if (!ok) {
+ *errmsg = format("%s:%u: %s", path, line_number, errmsg2);
+ free(errmsg2);
+ result = false;
+ goto out;
+ }
+ }
+ if (ferror(f)) {
+ *errmsg = x_strdup(strerror(errno));
+ result = false;
+ }
+
+out:
+ fclose(f);
+ return result;
+}
+
+bool
+conf_update_from_environment(struct conf *conf, char **errmsg)
+{
+ for (char **p = environ; *p; ++p) {
+ if (!str_startswith(*p, "CCACHE_")) {
+ continue;
+ }
+ char *q = strchr(*p, '=');
+ if (!q) {
+ continue;
+ }
+
+ bool negate;
+ size_t key_start;
+ if (str_startswith(*p + 7, "NO")) {
+ negate = true;
+ key_start = 9;
+ } else {
+ negate = false;
+ key_start = 7;
+ }
+ char *key = x_strndup(*p + key_start, q - *p - key_start);
+
+ ++q; // Now points to the value.
+
+ const struct env_to_conf_item *env_to_conf_item = find_env_to_conf(key);
+ if (!env_to_conf_item) {
+ free(key);
+ continue;
+ }
+
+ char *errmsg2;
+ if (!handle_conf_setting(
+ conf, env_to_conf_item->conf_name, q, &errmsg2, true, negate,
+ "environment")) {
+ *errmsg = format("%s: %s", key, errmsg2);
+ free(errmsg2);
+ free(key);
+ return false;
+ }
+
+ free(key);
+ }
+
+ return true;
+}
+
+bool
+conf_set_value_in_file(const char *path, const char *key, const char *value,
+ char **errmsg)
+{
+ const struct conf_item *item = find_conf(key);
+ if (!item) {
+ *errmsg = format("unknown configuration option \"%s\"", key);
+ return false;
+ }
+
+ FILE *infile = fopen(path, "r");
+ if (!infile) {
+ *errmsg = format("%s: %s", path, strerror(errno));
+ return false;
+ }
+
+ char *outpath = format("%s.tmp", path);
+ FILE *outfile = create_tmp_file(&outpath, "w");
+ if (!outfile) {
+ *errmsg = format("%s: %s", outpath, strerror(errno));
+ free(outpath);
+ fclose(infile);
+ return false;
+ }
+
+ bool found = false;
+ char buf[10000];
+ while (fgets(buf, sizeof(buf), infile)) {
+ char *key2;
+ char *value2;
+ char *errmsg2;
+ bool ok = parse_line(buf, &key2, &value2, &errmsg2);
+ if (ok && key2 && str_eq(key2, key)) {
+ found = true;
+ fprintf(outfile, "%s = %s\n", key, value);
+ } else {
+ fputs(buf, outfile);
+ }
+ free(key2);
+ free(value2);
+ }
+
+ if (!found) {
+ fprintf(outfile, "%s = %s\n", key, value);
+ }
+
+ fclose(infile);
+ fclose(outfile);
+ if (x_rename(outpath, path) != 0) {
+ *errmsg = format("rename %s to %s: %s", outpath, path, strerror(errno));
+ return false;
+ }
+ free(outpath);
+
+ return true;
+}
+
+bool
+conf_print_items(struct conf *conf,
+ void (*printer)(const char *descr, const char *origin,
+ void *context),
+ void *context)
+{
+ char *s = x_strdup("");
+
+ reformat(&s, "base_dir = %s", conf->base_dir);
+ printer(s, conf->item_origins[find_conf("base_dir")->number], context);
+
+ reformat(&s, "cache_dir = %s", conf->cache_dir);
+ printer(s, conf->item_origins[find_conf("cache_dir")->number], context);
+
+ reformat(&s, "cache_dir_levels = %u", conf->cache_dir_levels);
+ printer(s, conf->item_origins[find_conf("cache_dir_levels")->number],
+ context);
+
+ reformat(&s, "compiler = %s", conf->compiler);
+ printer(s, conf->item_origins[find_conf("compiler")->number], context);
+
+ reformat(&s, "compiler_check = %s", conf->compiler_check);
+ printer(s, conf->item_origins[find_conf("compiler_check")->number], context);
+
+ reformat(&s, "compression = %s", bool_to_string(conf->compression));
+ printer(s, conf->item_origins[find_conf("compression")->number], context);
+
+ reformat(&s, "compression_level = %u", conf->compression_level);
+ printer(s, conf->item_origins[find_conf("compression_level")->number],
+ context);
+
+ reformat(&s, "cpp_extension = %s", conf->cpp_extension);
+ printer(s, conf->item_origins[find_conf("cpp_extension")->number], context);
+
+ reformat(&s, "direct_mode = %s", bool_to_string(conf->direct_mode));
+ printer(s, conf->item_origins[find_conf("direct_mode")->number], context);
+
+ reformat(&s, "disable = %s", bool_to_string(conf->disable));
+ printer(s, conf->item_origins[find_conf("disable")->number], context);
+
+ reformat(&s, "extra_files_to_hash = %s", conf->extra_files_to_hash);
+ printer(s, conf->item_origins[find_conf("extra_files_to_hash")->number],
+ context);
+
+ reformat(&s, "hard_link = %s", bool_to_string(conf->hard_link));
+ printer(s, conf->item_origins[find_conf("hard_link")->number], context);
+
+ reformat(&s, "hash_dir = %s", bool_to_string(conf->hash_dir));
+ printer(s, conf->item_origins[find_conf("hash_dir")->number], context);
+
+ reformat(&s, "ignore_headers_in_manifest = %s",
+ conf->ignore_headers_in_manifest);
+ printer(s,
+ conf->item_origins[find_conf("ignore_headers_in_manifest")->number],
+ context);
+
+ reformat(&s, "keep_comments_cpp = %s",
+ bool_to_string(conf->keep_comments_cpp));
+ printer(s, conf->item_origins[find_conf(
+ "keep_comments_cpp")->number], context);
+
+ reformat(&s, "limit_multiple = %.1f", (double)conf->limit_multiple);
+ printer(s, conf->item_origins[find_conf("limit_multiple")->number], context);
+
+ reformat(&s, "log_file = %s", conf->log_file);
+ printer(s, conf->item_origins[find_conf("log_file")->number], context);
+
+ reformat(&s, "max_files = %u", conf->max_files);
+ printer(s, conf->item_origins[find_conf("max_files")->number], context);
+
+ char *s2 = format_parsable_size_with_suffix(conf->max_size);
+ reformat(&s, "max_size = %s", s2);
+ printer(s, conf->item_origins[find_conf("max_size")->number], context);
+ free(s2);
+
+ reformat(&s, "path = %s", conf->path);
+ printer(s, conf->item_origins[find_conf("path")->number], context);
+
+ reformat(&s, "prefix_command = %s", conf->prefix_command);
+ printer(s, conf->item_origins[find_conf("prefix_command")->number], context);
+
+ reformat(&s, "prefix_command_cpp = %s", conf->prefix_command_cpp);
+ printer(s, conf->item_origins[find_conf(
+ "prefix_command_cpp")->number], context);
+
+ reformat(&s, "read_only = %s", bool_to_string(conf->read_only));
+ printer(s, conf->item_origins[find_conf("read_only")->number], context);
+
+ reformat(&s, "read_only_direct = %s", bool_to_string(conf->read_only_direct));
+ printer(s, conf->item_origins[find_conf("read_only_direct")->number],
+ context);
+
+ reformat(&s, "recache = %s", bool_to_string(conf->recache));
+ printer(s, conf->item_origins[find_conf("recache")->number], context);
+
+ reformat(&s, "run_second_cpp = %s", bool_to_string(conf->run_second_cpp));
+ printer(s, conf->item_origins[find_conf("run_second_cpp")->number], context);
+
+ reformat(&s, "sloppiness = ");
+ if (conf->sloppiness & SLOPPY_FILE_MACRO) {
+ reformat(&s, "%sfile_macro, ", s);
+ }
+ if (conf->sloppiness & SLOPPY_INCLUDE_FILE_MTIME) {
+ reformat(&s, "%sinclude_file_mtime, ", s);
+ }
+ if (conf->sloppiness & SLOPPY_INCLUDE_FILE_CTIME) {
+ reformat(&s, "%sinclude_file_ctime, ", s);
+ }
+ if (conf->sloppiness & SLOPPY_TIME_MACROS) {
+ reformat(&s, "%stime_macros, ", s);
+ }
+ if (conf->sloppiness & SLOPPY_PCH_DEFINES) {
+ reformat(&s, "%spch_defines, ", s);
+ }
+ if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) {
+ reformat(&s, "%sfile_stat_matches, ", s);
+ }
+ if (conf->sloppiness & SLOPPY_NO_SYSTEM_HEADERS) {
+ reformat(&s, "%sno_system_headers, ", s);
+ }
+ if (conf->sloppiness) {
+ // Strip last ", ".
+ s[strlen(s) - 2] = '\0';
+ }
+ printer(s, conf->item_origins[find_conf("sloppiness")->number], context);
+
+ reformat(&s, "stats = %s", bool_to_string(conf->stats));
+ printer(s, conf->item_origins[find_conf("stats")->number], context);
+
+ reformat(&s, "temporary_dir = %s", conf->temporary_dir);
+ printer(s, conf->item_origins[find_conf("temporary_dir")->number], context);
+
+ if (conf->umask == UINT_MAX) {
+ reformat(&s, "umask = ");
+ } else {
+ reformat(&s, "umask = %03o", conf->umask);
+ }
+ printer(s, conf->item_origins[find_conf("umask")->number], context);
+
+ reformat(&s, "unify = %s", bool_to_string(conf->unify));
+ printer(s, conf->item_origins[find_conf("unify")->number], context);
+
+ free(s);
+ return true;
+}
diff --git a/conf.h b/conf.h
new file mode 100644
index 0000000..232dcfd
--- /dev/null
+++ b/conf.h
@@ -0,0 +1,53 @@
+#ifndef CONF_H
+#define CONF_H
+
+#include "system.h"
+
+struct conf {
+ char *base_dir;
+ char *cache_dir;
+ unsigned cache_dir_levels;
+ char *compiler;
+ char *compiler_check;
+ bool compression;
+ unsigned compression_level;
+ char *cpp_extension;
+ bool direct_mode;
+ bool disable;
+ char *extra_files_to_hash;
+ bool hard_link;
+ bool hash_dir;
+ char *ignore_headers_in_manifest;
+ bool keep_comments_cpp;
+ float limit_multiple;
+ char *log_file;
+ unsigned max_files;
+ uint64_t max_size;
+ char *path;
+ char *prefix_command;
+ char *prefix_command_cpp;
+ bool read_only;
+ bool read_only_direct;
+ bool recache;
+ bool run_second_cpp;
+ unsigned sloppiness;
+ bool stats;
+ char *temporary_dir;
+ unsigned umask;
+ bool unify;
+
+ const char **item_origins;
+};
+
+struct conf *conf_create(void);
+void conf_free(struct conf *conf);
+bool conf_read(struct conf *conf, const char *path, char **errmsg);
+bool conf_update_from_environment(struct conf *conf, char **errmsg);
+bool conf_set_value_in_file(const char *path, const char *key,
+ const char *value, char **errmsg);
+bool conf_print_items(struct conf *conf,
+ void (*printer)(const char *descr, const char *origin,
+ void *context),
+ void *context);
+
+#endif
diff --git a/config.guess b/config.guess
new file mode 100755
index 0000000..ad5f74a
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1534 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012 Free Software Foundation, Inc.
+
+timestamp='2012-07-31'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo ${UNAME_MACHINE}-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
+esac
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..f990225
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,256 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* Define to 1 if you have the `__compar_fn_t' typedef. */
+#undef HAVE_COMPAR_FN_T
+
+/* Define to 1 if you have the <ctype.h> header file. */
+#undef HAVE_CTYPE_H
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if your compiler supports extern inline */
+#undef HAVE_EXTERN_INLINE
+
+/* Define to 1 if you have the `GetFinalPathNameByHandleW' function. */
+#undef HAVE_GETFINALPATHNAMEBYHANDLEW
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `getopt_long' function. */
+#undef HAVE_GETOPT_LONG
+
+/* Define to 1 if you have the `getpwuid' function. */
+#undef HAVE_GETPWUID
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if the system has the type `intmax_t'. */
+#undef HAVE_INTMAX_T
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `localeconv' function. */
+#undef HAVE_LOCALECONV
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if the system has the type `long long'. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if the system has the type `long long int'. */
+#undef HAVE_LONG_LONG_INT
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#undef HAVE_PTRDIFF_T
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define to 1 if you have the `realpath' function. */
+#undef HAVE_REALPATH
+
+/* Define to 1 if you have a C99 compliant `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
+/* Define to 1 if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if `decimal_point' is a member of `struct lconv'. */
+#undef HAVE_STRUCT_LCONV_DECIMAL_POINT
+
+/* Define to 1 if `thousands_sep' is a member of `struct lconv'. */
+#undef HAVE_STRUCT_LCONV_THOUSANDS_SEP
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if the system has the type `uintmax_t'. */
+#undef HAVE_UINTMAX_T
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#undef HAVE_UINTPTR_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#undef HAVE_UNSIGNED_LONG_LONG_INT
+
+/* Define to 1 if you have the `utimes' function. */
+#undef HAVE_UTIMES
+
+/* Define to 1 if you have the <varargs.h> header file. */
+#undef HAVE_VARARGS_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `va_copy' function or macro. */
+#undef HAVE_VA_COPY
+
+/* Define to 1 if you have a C99 compliant `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the `__va_copy' function or macro. */
+#undef HAVE___VA_COPY
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define on OpenBSD to activate all library features */
+#undef _BSD_SOURCE
+
+/* Define on Irix to enable u_int */
+#undef _BSD_TYPES
+
+/* Define on Darwin to activate all library features */
+#undef _DARWIN_C_SOURCE
+
+/* Define on Linux to activate all library features */
+#undef _GNU_SOURCE
+
+/* Define on NetBSD to activate all library features */
+#undef _NETBSD_SOURCE
+
+/* Define to activate features from IEEE Stds 1003.1-2001 */
+#undef _POSIX_C_SOURCE
+
+/* Windows Vista or newer is required */
+#undef _WIN32_WINNT
+
+/* Define to the level of X/Open that your system supports */
+#undef _XOPEN_SOURCE
+
+/* Define to activate Unix95-and-earlier features */
+#undef _XOPEN_SOURCE_EXTENDED
+
+/* Define on FreeBSD to activate all library features */
+#undef __BSD_VISIBLE
+
+/* Define to activate Unix95-and-earlier features */
+#undef __EXTENSIONS__
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to the widest signed integer type if <stdint.h> and <inttypes.h> do
+ not define. */
+#undef intmax_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to the widest unsigned integer type if <stdint.h> and <inttypes.h>
+ do not define. */
+#undef uintmax_t
+
+/* Define to the type of an unsigned integer type wide enough to hold a
+ pointer, if such a type exists, and if the system does not define it. */
+#undef uintptr_t
diff --git a/config.sub b/config.sub
new file mode 100755
index 0000000..b15df57
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1786 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012 Free Software Foundation, Inc.
+
+timestamp='2012-07-31'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | be32 | be64 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | epiphany \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | open8 \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pyramid \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | we32k \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pyramid-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i386-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755
index 0000000..f21410a
--- /dev/null
+++ b/configure
@@ -0,0 +1,7422 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_header_list=
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+EGREP
+GREP
+AR
+RANLIB
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+test_suites
+include_dev_mk
+extra_libs
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_bundled_zlib
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-bundled-zlib use bundled zlib instead of the system's default
+ zlib
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
+# ----------------------------------------------------
+# Tries to find if the field MEMBER exists in type AGGR, after including
+# INCLUDES, setting cache variable VAR accordingly.
+ac_fn_c_check_member ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+$as_echo_n "checking for $2.$3... " >&6; }
+if eval \${$4+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (ac_aggr.$3)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$4=yes"
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (sizeof ac_aggr.$3)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$4=yes"
+else
+ eval "$4=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$4
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_member
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+as_fn_append ac_header_list " stdarg.h"
+as_fn_append ac_header_list " varargs.h"
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: Configuring ccache" >&5
+$as_echo "$as_me: Configuring ccache" >&6;}
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+case $host in
+ *mingw32* | *mingw64* | *cygwin* | *wince* | *mingwce*)
+ windows_os=yes
+
+$as_echo "#define _WIN32_WINNT 0x0600" >>confdefs.h
+
+ ;;
+esac
+
+
+
+
+
+
+# The later defininition of _XOPEN_SOURCE disables certain features
+# on Linux, so we need _GNU_SOURCE to re-enable them (makedev, tm_zone).
+
+$as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+
+# The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables
+# certain features on NetBSD, so we need _NETBSD_SOURCE to re-enable
+# them.
+
+$as_echo "#define _NETBSD_SOURCE 1" >>confdefs.h
+
+
+# The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables
+# certain features on FreeBSD, so we need __BSD_VISIBLE to re-enable
+# them.
+
+$as_echo "#define __BSD_VISIBLE 1" >>confdefs.h
+
+
+# The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables
+# u_int on Irix 5.3. Defining _BSD_TYPES brings it back.
+
+$as_echo "#define _BSD_TYPES 1" >>confdefs.h
+
+
+# The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables
+# certain features on Mac OS X, so we need _DARWIN_C_SOURCE to re-enable
+# them.
+
+$as_echo "#define _DARWIN_C_SOURCE 1" >>confdefs.h
+
+
+define_xopen_source=yes
+
+ac_sys_system=`uname -s`
+if test "$ac_sys_system" = "AIX" -o "$ac_sys_system" = "Monterey64" \
+ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then
+ ac_sys_release=`uname -v`
+else
+ ac_sys_release=`uname -r`
+fi
+
+# Some systems cannot stand _XOPEN_SOURCE being defined at all; they
+# disable features if it is defined, without any means to access these
+# features as extensions. For these systems, we skip the definition of
+# _XOPEN_SOURCE. Before adding a system to the list to gain access to
+# some feature, make sure there is no alternative way to access this
+# feature. Also, when using wildcards, make sure you have verified the
+# need for not defining _XOPEN_SOURCE on all systems matching the
+# wildcard, and that the wildcard does not include future systems
+# (which may remove their limitations).
+case $ac_sys_system/$ac_sys_release in
+ # On OpenBSD, select(2) is not available if _XOPEN_SOURCE is defined,
+ # even though select is a POSIX function. Reported by J. Ribbens.
+ # Reconfirmed for OpenBSD 3.3 by Zachary Hamm, for 3.4 by Jason Ish.
+ OpenBSD/2.* | OpenBSD/3.[0123456789] | OpenBSD/4.[0123])
+ define_xopen_source=no
+ # OpenBSD undoes our definition of __BSD_VISIBLE if _XOPEN_SOURCE is
+ # also defined. This can be overridden by defining _BSD_SOURCE
+ # As this has a different meaning on Linux, only define it on OpenBSD
+
+$as_echo "#define _BSD_SOURCE 1" >>confdefs.h
+
+ ;;
+ # Defining _XOPEN_SOURCE on NetBSD version prior to the introduction of
+ # _NETBSD_SOURCE disables certain features (eg. setgroups). Reported by
+ # Marc Recht
+ NetBSD/1.5 | NetBSD/1.5.* | NetBSD/1.6 | NetBSD/1.6.* | NetBSD/1.6[A-S])
+ define_xopen_source=no;;
+ # On Solaris 2.6, sys/wait.h is inconsistent in the usage
+ # of union __?sigval. Reported by Stuart Bishop.
+ SunOS/5.6)
+ define_xopen_source=no;;
+ # On UnixWare 7, u_long is never defined with _XOPEN_SOURCE,
+ # but used in /usr/include/netinet/tcp.h. Reported by Tim Rice.
+ # Reconfirmed for 7.1.4 by Martin v. Loewis.
+ OpenUNIX/8.0.0| UnixWare/7.1.[0-4])
+ define_xopen_source=no;;
+ # On OpenServer 5, u_short is never defined with _XOPEN_SOURCE,
+ # but used in struct sockaddr.sa_family. Reported by Tim Rice.
+ SCO_SV/3.2)
+ define_xopen_source=no;;
+ # On FreeBSD 4, the math functions C89 does not cover are never defined
+ # with _XOPEN_SOURCE and __BSD_VISIBLE does not re-enable them.
+ FreeBSD/4.*)
+ define_xopen_source=no;;
+ # On MacOS X 10.2, a bug in ncurses.h means that it craps out if
+ # _XOPEN_EXTENDED_SOURCE is defined. Apparently, this is fixed in 10.3, which
+ # identifies itself as Darwin/7.*
+ # On Mac OS X 10.4, defining _POSIX_C_SOURCE or _XOPEN_SOURCE
+ # disables platform specific features beyond repair.
+ # On Mac OS X 10.3, defining _POSIX_C_SOURCE or _XOPEN_SOURCE
+ # has no effect, don't bother defining them
+ Darwin/[6789].*)
+ define_xopen_source=no;;
+ # On AIX 4 and 5.1, mbstate_t is defined only when _XOPEN_SOURCE == 500 but
+ # used in wcsnrtombs() and mbsnrtowcs() even if _XOPEN_SOURCE is not defined
+ # or has another value. By not (re)defining it, the defaults come in place.
+ AIX/4)
+ define_xopen_source=no;;
+ AIX/5|AIX/7)
+ if test `uname -r` -eq 1; then
+ define_xopen_source=no
+ fi
+ ;;
+ # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
+ # defining NI_NUMERICHOST.
+ QNX/6.3.2)
+ define_xopen_source=no
+ ;;
+
+esac
+
+if test $define_xopen_source = yes
+then
+ # On Solaris w/ g++ it appears that _XOPEN_SOURCE has to be
+ # defined precisely as g++ defines it
+ # Furthermore, on Solaris 10, XPG6 requires the use of a C99
+ # compiler
+ case $ac_sys_system/$ac_sys_release in
+ SunOS/5.8|SunOS/5.9|SunOS/5.10)
+
+$as_echo "#define _XOPEN_SOURCE 500" >>confdefs.h
+
+ ;;
+ *)
+
+$as_echo "#define _XOPEN_SOURCE 600" >>confdefs.h
+
+ ;;
+ esac
+
+ # On Tru64 Unix 4.0F, defining _XOPEN_SOURCE also requires
+ # definition of _XOPEN_SOURCE_EXTENDED and _POSIX_C_SOURCE, or else
+ # several APIs are not declared. Since this is also needed in some
+ # cases for HP-UX, we define it globally.
+ # except for Solaris 10, where it must not be defined,
+ # as it implies XPG4.2
+ case $ac_sys_system/$ac_sys_release in
+ SunOS/5.10|SunOS/5.11)
+
+$as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
+
+ ;;
+ *)
+
+$as_echo "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h
+
+ ;;
+ esac
+
+
+$as_echo "#define _POSIX_C_SOURCE 200112L" >>confdefs.h
+
+
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+ your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str;
+ int number;
+ float fnumber;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg (args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+}
+
+int
+main ()
+{
+
+ // Check bool.
+ _Bool success = false;
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+ || dynamic_array[ni.number - 1] != 543);
+
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c99"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+
+fi
+
+
+if test "$ac_cv_prog_cc_c99" = no; then
+ as_fn_error $? "cannot find a C99-compatible compiler" "$LINENO" 5
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AR" = x; then
+ AR=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+if test -z "$AR"; then
+ as_fn_error $? "cannot find ar" "$LINENO" 5
+fi
+
+# If GCC, turn on warnings.
+if test "x$GCC" = "xyes"; then
+ CFLAGS="$CFLAGS -Wall -W"
+else
+ CFLAGS="$CFLAGS -O"
+fi
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+ as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
+$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
+if eval \${$as_ac_Header+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_hdr>
+
+int
+main ()
+{
+if ((DIR *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_ac_Header=yes"
+else
+ eval "$as_ac_Header=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$as_ac_Header
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
+_ACEOF
+
+ac_header_dirent=$ac_hdr; break
+fi
+
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if ${ac_cv_search_opendir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char opendir ();
+int
+main ()
+{
+return opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' dir; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_opendir+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_opendir+:} false; then :
+
+else
+ ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if ${ac_cv_search_opendir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char opendir ();
+int
+main ()
+{
+return opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' x; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_opendir+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_opendir+:} false; then :
+
+else
+ ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if ${ac_cv_header_time+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_time=yes
+else
+ ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
+$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
+if ${ac_cv_header_sys_wait_h+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+int
+main ()
+{
+ int s;
+ wait (&s);
+ s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_sys_wait_h=yes
+else
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5
+$as_echo "$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
+
+$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default"
+if test "x$ac_cv_type_long_long" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LONG_LONG 1
+_ACEOF
+
+
+fi
+
+
+for ac_header in ctype.h pwd.h stdlib.h string.h strings.h sys/time.h sys/mman.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in termios.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "termios.h" "ac_cv_header_termios_h" "$ac_includes_default"
+if test "x$ac_cv_header_termios_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_TERMIOS_H 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in gethostname
+do :
+ ac_fn_c_check_func "$LINENO" "gethostname" "ac_cv_func_gethostname"
+if test "x$ac_cv_func_gethostname" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETHOSTNAME 1
+_ACEOF
+
+fi
+done
+
+for ac_func in getopt_long
+do :
+ ac_fn_c_check_func "$LINENO" "getopt_long" "ac_cv_func_getopt_long"
+if test "x$ac_cv_func_getopt_long" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETOPT_LONG 1
+_ACEOF
+
+fi
+done
+
+for ac_func in getpwuid
+do :
+ ac_fn_c_check_func "$LINENO" "getpwuid" "ac_cv_func_getpwuid"
+if test "x$ac_cv_func_getpwuid" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETPWUID 1
+_ACEOF
+
+fi
+done
+
+for ac_func in gettimeofday
+do :
+ ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
+if test "x$ac_cv_func_gettimeofday" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETTIMEOFDAY 1
+_ACEOF
+
+fi
+done
+
+for ac_func in mkstemp
+do :
+ ac_fn_c_check_func "$LINENO" "mkstemp" "ac_cv_func_mkstemp"
+if test "x$ac_cv_func_mkstemp" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_MKSTEMP 1
+_ACEOF
+
+fi
+done
+
+for ac_func in realpath
+do :
+ ac_fn_c_check_func "$LINENO" "realpath" "ac_cv_func_realpath"
+if test "x$ac_cv_func_realpath" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_REALPATH 1
+_ACEOF
+
+fi
+done
+
+for ac_func in strndup
+do :
+ ac_fn_c_check_func "$LINENO" "strndup" "ac_cv_func_strndup"
+if test "x$ac_cv_func_strndup" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STRNDUP 1
+_ACEOF
+
+fi
+done
+
+for ac_func in strtok_r
+do :
+ ac_fn_c_check_func "$LINENO" "strtok_r" "ac_cv_func_strtok_r"
+if test "x$ac_cv_func_strtok_r" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STRTOK_R 1
+_ACEOF
+
+fi
+done
+
+for ac_func in unsetenv
+do :
+ ac_fn_c_check_func "$LINENO" "unsetenv" "ac_cv_func_unsetenv"
+if test "x$ac_cv_func_unsetenv" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_UNSETENV 1
+_ACEOF
+
+fi
+done
+
+for ac_func in utimes
+do :
+ ac_fn_c_check_func "$LINENO" "utimes" "ac_cv_func_utimes"
+if test "x$ac_cv_func_utimes" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_UTIMES 1
+_ACEOF
+
+fi
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compar_fn_t in stdlib.h" >&5
+$as_echo_n "checking for compar_fn_t in stdlib.h... " >&6; }
+if ${ccache_cv_COMPAR_FN_T+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+int
+main ()
+{
+void test_fn(void) { qsort(NULL, 0, 0, (__compar_fn_t)NULL); }
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ccache_cv_COMPAR_FN_T=yes
+else
+ ccache_cv_COMPAR_FN_T=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ccache_cv_COMPAR_FN_T" >&5
+$as_echo "$ccache_cv_COMPAR_FN_T" >&6; }
+if test x"$ccache_cv_COMPAR_FN_T" = x"yes"; then
+
+$as_echo "#define HAVE_COMPAR_FN_T 1" >>confdefs.h
+
+fi
+
+# $Id: snprintf.m4,v 1.1.1.1 2008/01/06 03:24:00 holger Exp $
+
+# Copyright (c) 2008 Holger Weiss <holger@jhweiss.de>.
+#
+# This code may freely be used, modified and/or redistributed for any purpose.
+# It would be nice if additions and fixes to this file (including trivial code
+# cleanups) would be sent back in order to let me include them in the version
+# available at <http://www.jhweiss.de/software/snprintf.html>. However, this is
+# not a requirement for using or redistributing (possibly modified) versions of
+# this file, nor is leaving this notice intact mandatory.
+
+# HW_HEADER_STDARG_H
+# ------------------
+# Define HAVE_STDARG_H to 1 if <stdarg.h> is available.
+# HW_HEADER_STDARG_H
+
+# HW_HEADER_VARARGS_H
+# -------------------
+# Define HAVE_VARARGS_H to 1 if <varargs.h> is available.
+# HW_HEADER_VARARGS_H
+
+# HW_FUNC_VA_COPY
+# ---------------
+# Set $hw_cv_func_va_copy to "yes" or "no". Define HAVE_VA_COPY to 1 if
+# $hw_cv_func_va_copy is set to "yes". Note that it's "unspecified whether
+# va_copy and va_end are macros or identifiers declared with external linkage."
+# (C99: 7.15.1, 1) Therefore, the presence of va_copy(3) cannot simply "be
+# tested with #ifdef", as suggested by the Autoconf manual (5.5.1).
+# HW_FUNC_VA_COPY
+
+# HW_FUNC___VA_COPY
+# -----------------
+# Set $hw_cv_func___va_copy to "yes" or "no". Define HAVE___VA_COPY to 1 if
+# $hw_cv_func___va_copy is set to "yes".
+# HW_FUNC___VA_COPY
+
+# HW_FUNC_VSNPRINTF
+# -----------------
+# Set $hw_cv_func_vsnprintf and $hw_cv_func_vsnprintf_c99 to "yes" or "no",
+# respectively. Define HAVE_VSNPRINTF to 1 only if $hw_cv_func_vsnprintf_c99
+# is set to "yes". Otherwise, define vsnprintf to rpl_vsnprintf and make sure
+# the replacement function will be built.
+# HW_FUNC_VSNPRINTF
+
+# HW_FUNC_SNPRINTF
+# ----------------
+# Set $hw_cv_func_snprintf and $hw_cv_func_snprintf_c99 to "yes" or "no",
+# respectively. Define HAVE_SNPRINTF to 1 only if $hw_cv_func_snprintf_c99
+# is set to "yes". Otherwise, define snprintf to rpl_snprintf and make sure
+# the replacement function will be built.
+# HW_FUNC_SNPRINTF
+
+# HW_FUNC_VASPRINTF
+# -----------------
+# Set $hw_cv_func_vasprintf to "yes" or "no". Define HAVE_VASPRINTF to 1 if
+# $hw_cv_func_vasprintf is set to "yes". Otherwise, define vasprintf to
+# rpl_vasprintf and make sure the replacement function will be built.
+# HW_FUNC_VASPRINTF
+
+# HW_FUNC_ASPRINTF
+# ----------------
+# Set $hw_cv_func_asprintf to "yes" or "no". Define HAVE_ASPRINTF to 1 if
+# $hw_cv_func_asprintf is set to "yes". Otherwise, define asprintf to
+# rpl_asprintf and make sure the replacement function will be built.
+# HW_FUNC_ASPRINTF
+
+# _HW_FUNC_XPRINTF_REPLACE
+# ------------------------
+# Arrange for building snprintf.c. Must be called if one or more of the
+# functions provided by snprintf.c are needed.
+# _HW_FUNC_XPRINTF_REPLACE
+
+
+
+
+
+ for ac_header in $ac_header_list
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned long long int" >&5
+$as_echo_n "checking for unsigned long long int... " >&6; }
+if ${ac_cv_type_unsigned_long_long_int+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_unsigned_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ /* For now, do not test the preprocessor; as of 2007 there are too many
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
+ /* Test literals. */
+ long long int ll = 9223372036854775807ll;
+ long long int nll = -9223372036854775807LL;
+ unsigned long long int ull = 18446744073709551615ULL;
+ /* Test constant expressions. */
+ typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
+ ? 1 : -1)];
+ typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
+ ? 1 : -1)];
+ int i = 63;
+int
+main ()
+{
+/* Test availability of runtime routines for shift and division. */
+ long long int llmax = 9223372036854775807ll;
+ unsigned long long int ullmax = 18446744073709551615ull;
+ return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+ ac_cv_type_unsigned_long_long_int=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_unsigned_long_long_int" >&5
+$as_echo "$ac_cv_type_unsigned_long_long_int" >&6; }
+ if test $ac_cv_type_unsigned_long_long_int = yes; then
+
+$as_echo "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h
+
+ fi
+
+
+ ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf"
+if test "x$ac_cv_func_vsnprintf" = xyes; then :
+ hw_cv_func_vsnprintf=yes
+else
+ hw_cv_func_vsnprintf=no
+fi
+
+ if test "$hw_cv_func_vsnprintf" = yes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf is C99 compliant" >&5
+$as_echo_n "checking whether vsnprintf is C99 compliant... " >&6; }
+if ${hw_cv_func_vsnprintf_c99+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ hw_cv_func_vsnprintf_c99=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#if HAVE_STDARG_H
+ #include <stdarg.h>
+ #endif
+ #include <stdio.h>
+ static int testprintf(char *buf, size_t size, const char *format, ...)
+ {
+ int result;
+ va_list ap;
+ va_start(ap, format);
+ result = vsnprintf(buf, size, format, ap);
+ va_end(ap);
+ return result;
+ }
+int
+main ()
+{
+char buf[43];
+ if (testprintf(buf, 4, "The answer is %27.2g.", 42.0) != 42 ||
+ testprintf(buf, 0, "No, it's %32zu.", (size_t)42) != 42 ||
+ buf[0] != 'T' || buf[3] != '\0')
+ return 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ hw_cv_func_vsnprintf_c99=yes
+else
+ hw_cv_func_vsnprintf_c99=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hw_cv_func_vsnprintf_c99" >&5
+$as_echo "$hw_cv_func_vsnprintf_c99" >&6; }
+else
+ hw_cv_func_snprintf_c99=no
+fi
+ if test "$hw_cv_func_vsnprintf_c99" = yes; then :
+
+$as_echo "#define HAVE_VSNPRINTF 1" >>confdefs.h
+
+else
+ for ac_header in inttypes.h locale.h stddef.h stdint.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ ac_fn_c_check_member "$LINENO" "struct lconv" "decimal_point" "ac_cv_member_struct_lconv_decimal_point" "#include <locale.h>
+"
+if test "x$ac_cv_member_struct_lconv_decimal_point" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_LCONV_DECIMAL_POINT 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct lconv" "thousands_sep" "ac_cv_member_struct_lconv_thousands_sep" "#include <locale.h>
+"
+if test "x$ac_cv_member_struct_lconv_thousands_sep" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_LCONV_THOUSANDS_SEP 1
+_ACEOF
+
+
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long int" >&5
+$as_echo_n "checking for long long int... " >&6; }
+if ${ac_cv_type_long_long_int+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
+ if test $ac_cv_type_long_long_int = yes; then
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+ #ifndef LLONG_MAX
+ # define HALF \
+ (1LL << (sizeof (long long int) * CHAR_BIT - 2))
+ # define LLONG_MAX (HALF - 1 + HALF)
+ #endif
+int
+main ()
+{
+long long int n = 1;
+ int i;
+ for (i = 0; ; i++)
+ {
+ long long int m = n << i;
+ if (m >> i != n)
+ return 1;
+ if (LLONG_MAX / 2 < m)
+ break;
+ }
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_type_long_long_int=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_long_int" >&5
+$as_echo "$ac_cv_type_long_long_int" >&6; }
+ if test $ac_cv_type_long_long_int = yes; then
+
+$as_echo "#define HAVE_LONG_LONG_INT 1" >>confdefs.h
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned long long int" >&5
+$as_echo_n "checking for unsigned long long int... " >&6; }
+if ${ac_cv_type_unsigned_long_long_int+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_unsigned_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ /* For now, do not test the preprocessor; as of 2007 there are too many
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
+ /* Test literals. */
+ long long int ll = 9223372036854775807ll;
+ long long int nll = -9223372036854775807LL;
+ unsigned long long int ull = 18446744073709551615ULL;
+ /* Test constant expressions. */
+ typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
+ ? 1 : -1)];
+ typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
+ ? 1 : -1)];
+ int i = 63;
+int
+main ()
+{
+/* Test availability of runtime routines for shift and division. */
+ long long int llmax = 9223372036854775807ll;
+ unsigned long long int ullmax = 18446744073709551615ull;
+ return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+ ac_cv_type_unsigned_long_long_int=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_unsigned_long_long_int" >&5
+$as_echo "$ac_cv_type_unsigned_long_long_int" >&6; }
+ if test $ac_cv_type_unsigned_long_long_int = yes; then
+
+$as_echo "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h
+
+ fi
+
+ ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+
+
+ ac_fn_c_check_type "$LINENO" "intmax_t" "ac_cv_type_intmax_t" "$ac_includes_default"
+if test "x$ac_cv_type_intmax_t" = xyes; then :
+
+$as_echo "#define HAVE_INTMAX_T 1" >>confdefs.h
+
+else
+ test $ac_cv_type_long_long_int = yes \
+ && ac_type='long long int' \
+ || ac_type='long int'
+
+cat >>confdefs.h <<_ACEOF
+#define intmax_t $ac_type
+_ACEOF
+
+fi
+
+
+
+
+ ac_fn_c_check_type "$LINENO" "uintmax_t" "ac_cv_type_uintmax_t" "$ac_includes_default"
+if test "x$ac_cv_type_uintmax_t" = xyes; then :
+
+$as_echo "#define HAVE_UINTMAX_T 1" >>confdefs.h
+
+else
+ test $ac_cv_type_unsigned_long_long_int = yes \
+ && ac_type='unsigned long long int' \
+ || ac_type='unsigned long int'
+
+cat >>confdefs.h <<_ACEOF
+#define uintmax_t $ac_type
+_ACEOF
+
+fi
+
+
+
+ ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "$ac_includes_default"
+if test "x$ac_cv_type_uintptr_t" = xyes; then :
+
+$as_echo "#define HAVE_UINTPTR_T 1" >>confdefs.h
+
+else
+ for ac_type in 'unsigned int' 'unsigned long int' \
+ 'unsigned long long int'; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(sizeof (void *) <= sizeof ($ac_type))];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+cat >>confdefs.h <<_ACEOF
+#define uintptr_t $ac_type
+_ACEOF
+
+ ac_type=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test -z "$ac_type" && break
+ done
+fi
+
+
+ ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default"
+if test "x$ac_cv_type_ptrdiff_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_PTRDIFF_T 1
+_ACEOF
+
+
+fi
+
+ for ac_func in localeconv
+do :
+ ac_fn_c_check_func "$LINENO" "localeconv" "ac_cv_func_localeconv"
+if test "x$ac_cv_func_localeconv" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LOCALECONV 1
+_ACEOF
+
+fi
+done
+
+
+ if test "x$_hw_cv_func_xprintf_replace_done" != xyes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this sort of thing. */
+ typedef int charset[2];
+ const charset cs = { 0, 0 };
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *pcpcc;
+ char **ppc;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ pcpcc = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++pcpcc;
+ ppc = (char**) pcpcc;
+ pcpcc = (char const *const *) ppc;
+ { /* SCO 3.2v4 cc rejects this sort of thing. */
+ char tx;
+ char *t = &tx;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ if (s) return 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; } bx;
+ struct s *b = &bx; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ if (!foo) return 0;
+ }
+ return !cs[0] && !zero.x;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+
+
+
+ case " $LIBOBJS " in
+ *" snprintf.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
+ ;;
+esac
+
+ _hw_cv_func_xprintf_replace_done=yes
+fi
+
+fi
+
+
+ ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf"
+if test "x$ac_cv_func_snprintf" = xyes; then :
+ hw_cv_func_snprintf=yes
+else
+ hw_cv_func_snprintf=no
+fi
+
+ if test "$hw_cv_func_snprintf" = yes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf is C99 compliant" >&5
+$as_echo_n "checking whether snprintf is C99 compliant... " >&6; }
+if ${hw_cv_func_snprintf_c99+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ hw_cv_func_snprintf_c99=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+char buf[43];
+ if (snprintf(buf, 4, "The answer is %27.2g.", 42.0) != 42 ||
+ snprintf(buf, 0, "No, it's %32zu.", (size_t)42) != 42 ||
+ buf[0] != 'T' || buf[3] != '\0')
+ return 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ hw_cv_func_snprintf_c99=yes
+else
+ hw_cv_func_snprintf_c99=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hw_cv_func_snprintf_c99" >&5
+$as_echo "$hw_cv_func_snprintf_c99" >&6; }
+else
+ hw_cv_func_snprintf_c99=no
+fi
+ if test "$hw_cv_func_snprintf_c99" = yes; then :
+
+$as_echo "#define HAVE_SNPRINTF 1" >>confdefs.h
+
+else
+
+ if test "x$_hw_cv_func_xprintf_replace_done" != xyes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this sort of thing. */
+ typedef int charset[2];
+ const charset cs = { 0, 0 };
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *pcpcc;
+ char **ppc;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ pcpcc = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++pcpcc;
+ ppc = (char**) pcpcc;
+ pcpcc = (char const *const *) ppc;
+ { /* SCO 3.2v4 cc rejects this sort of thing. */
+ char tx;
+ char *t = &tx;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ if (s) return 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; } bx;
+ struct s *b = &bx; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ if (!foo) return 0;
+ }
+ return !cs[0] && !zero.x;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+
+
+
+ case " $LIBOBJS " in
+ *" snprintf.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
+ ;;
+esac
+
+ _hw_cv_func_xprintf_replace_done=yes
+fi
+
+fi
+
+
+
+
+
+
+
+ for ac_func in vasprintf
+do :
+ ac_fn_c_check_func "$LINENO" "vasprintf" "ac_cv_func_vasprintf"
+if test "x$ac_cv_func_vasprintf" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_VASPRINTF 1
+_ACEOF
+ hw_cv_func_vasprintf=yes
+else
+ hw_cv_func_vasprintf=no
+fi
+done
+
+ if test "$hw_cv_func_vasprintf" = no; then :
+ for ac_header in stdlib.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdlib_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STDLIB_H 1
+_ACEOF
+
+fi
+
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for va_copy" >&5
+$as_echo_n "checking for va_copy... " >&6; }
+if ${hw_cv_func_va_copy+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ hw_cv_func_va_copy=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#if HAVE_STDARG_H
+ #include <stdarg.h>
+ #elif HAVE_VARARGS_H
+ #include <varargs.h>
+ #endif
+int
+main ()
+{
+va_list ap, aq; va_copy(aq, ap);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ hw_cv_func_va_copy=yes
+else
+ hw_cv_func_va_copy=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hw_cv_func_va_copy" >&5
+$as_echo "$hw_cv_func_va_copy" >&6; }
+ if test "$hw_cv_func_va_copy" = yes; then :
+
+$as_echo "#define HAVE_VA_COPY 1" >>confdefs.h
+
+fi
+
+ if test "$hw_cv_func_va_copy" = no; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __va_copy" >&5
+$as_echo_n "checking for __va_copy... " >&6; }
+if ${hw_cv_func___va_copy+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ hw_cv_func___va_copy=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#if HAVE_STDARG_H
+ #include <stdarg.h>
+ #elif HAVE_VARARGS_H
+ #include <varargs.h>
+ #endif
+int
+main ()
+{
+va_list ap, aq; __va_copy(aq, ap);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ hw_cv_func___va_copy=yes
+else
+ hw_cv_func___va_copy=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hw_cv_func___va_copy" >&5
+$as_echo "$hw_cv_func___va_copy" >&6; }
+ if test "$hw_cv_func___va_copy" = yes; then :
+
+$as_echo "#define HAVE___VA_COPY 1" >>confdefs.h
+
+fi
+
+fi
+
+ if test "x$_hw_cv_func_xprintf_replace_done" != xyes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this sort of thing. */
+ typedef int charset[2];
+ const charset cs = { 0, 0 };
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *pcpcc;
+ char **ppc;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ pcpcc = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++pcpcc;
+ ppc = (char**) pcpcc;
+ pcpcc = (char const *const *) ppc;
+ { /* SCO 3.2v4 cc rejects this sort of thing. */
+ char tx;
+ char *t = &tx;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ if (s) return 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; } bx;
+ struct s *b = &bx; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ if (!foo) return 0;
+ }
+ return !cs[0] && !zero.x;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+
+
+
+ case " $LIBOBJS " in
+ *" snprintf.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
+ ;;
+esac
+
+ _hw_cv_func_xprintf_replace_done=yes
+fi
+
+fi
+
+
+ for ac_func in asprintf
+do :
+ ac_fn_c_check_func "$LINENO" "asprintf" "ac_cv_func_asprintf"
+if test "x$ac_cv_func_asprintf" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_ASPRINTF 1
+_ACEOF
+ hw_cv_func_asprintf=yes
+else
+ hw_cv_func_asprintf=no
+fi
+done
+
+ if test "$hw_cv_func_asprintf" = no; then :
+
+ if test "x$_hw_cv_func_xprintf_replace_done" != xyes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this sort of thing. */
+ typedef int charset[2];
+ const charset cs = { 0, 0 };
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *pcpcc;
+ char **ppc;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ pcpcc = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++pcpcc;
+ ppc = (char**) pcpcc;
+ pcpcc = (char const *const *) ppc;
+ { /* SCO 3.2v4 cc rejects this sort of thing. */
+ char tx;
+ char *t = &tx;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ if (s) return 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; } bx;
+ struct s *b = &bx; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ if (!foo) return 0;
+ }
+ return !cs[0] && !zero.x;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+
+
+
+ case " $LIBOBJS " in
+ *" snprintf.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
+ ;;
+esac
+
+ _hw_cv_func_xprintf_replace_done=yes
+fi
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing cos" >&5
+$as_echo_n "checking for library containing cos... " >&6; }
+if ${ac_cv_search_cos+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cos ();
+int
+main ()
+{
+return cos ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' m; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_cos=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_cos+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_cos+:} false; then :
+
+else
+ ac_cv_search_cos=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_cos" >&5
+$as_echo "$ac_cv_search_cos" >&6; }
+ac_res=$ac_cv_search_cos
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+
+
+# Check whether --with-bundled-zlib was given.
+if test "${with_bundled_zlib+set}" = set; then :
+ withval=$with_bundled_zlib;
+fi
+
+if test x${with_bundled_zlib} = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for zlib >= 1.2.3" >&5
+$as_echo_n "checking for zlib >= 1.2.3... " >&6; }
+if ${ccache_cv_zlib_1_2_3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <zlib.h>
+int
+main ()
+{
+
+ #if (ZLIB_VERNUM >= 0x1230)
+ #else
+ #error "ZLIB_VERNUM < 0x1230"
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ccache_cv_zlib_1_2_3=yes
+else
+ ccache_cv_zlib_1_2_3=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ccache_cv_zlib_1_2_3" >&5
+$as_echo "$ccache_cv_zlib_1_2_3" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzdopen in -lz" >&5
+$as_echo_n "checking for gzdopen in -lz... " >&6; }
+if ${ac_cv_lib_z_gzdopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gzdopen ();
+int
+main ()
+{
+return gzdopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_z_gzdopen=yes
+else
+ ac_cv_lib_z_gzdopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzdopen" >&5
+$as_echo "$ac_cv_lib_z_gzdopen" >&6; }
+if test "x$ac_cv_lib_z_gzdopen" = xyes; then :
+ true
+fi
+
+ if test $ccache_cv_zlib_1_2_3 = yes && test $ac_cv_lib_z_gzdopen = yes; then
+ use_bundled_zlib=no
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using bundled zlib" >&5
+$as_echo "$as_me: WARNING: using bundled zlib" >&2;}
+ use_bundled_zlib=yes
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: using bundled zlib as requested" >&5
+$as_echo "$as_me: using bundled zlib as requested" >&6;}
+ use_bundled_zlib=yes
+fi
+
+if test x${use_bundled_zlib} = xyes; then
+ CPPFLAGS="$CPPFLAGS -I\$(srcdir)/zlib"
+ extra_libs="zlib/libz.a"
+ mkdir -p zlib
+else
+ LIBS="$LIBS -lz"
+fi
+
+if test x${windows_os} = xyes; then
+ LIBS="$LIBS -lws2_32"
+ for ac_func in GetFinalPathNameByHandleW
+do :
+ ac_fn_c_check_func "$LINENO" "GetFinalPathNameByHandleW" "ac_cv_func_GetFinalPathNameByHandleW"
+if test "x$ac_cv_func_GetFinalPathNameByHandleW" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETFINALPATHNAMEBYHANDLEW 1
+_ACEOF
+
+else
+ LIBS="$LIBS -lpsapi"
+fi
+done
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_bigendian=unknown
+ # See if we're dealing with a universal compiler.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __APPLE_CC__
+ not a universal capable compiler
+ #endif
+ typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ # Check for potential -arch flags. It is not universal unless
+ # there are at least two -arch flags with different values.
+ ac_arch=
+ ac_prev=
+ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+ if test -n "$ac_prev"; then
+ case $ac_word in
+ i?86 | x86_64 | ppc | ppc64)
+ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+ ac_arch=$ac_word
+ else
+ ac_cv_c_bigendian=universal
+ break
+ fi
+ ;;
+ esac
+ ac_prev=
+ elif test "x$ac_word" = "x-arch"; then
+ ac_prev=arch
+ fi
+ done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if sys/param.h defines the BYTE_ORDER macro.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+ && LITTLE_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to _BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # Compile a test program.
+ if test "$cross_compiling" = yes; then :
+ # Try to guess by grepping values from an object file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+short int ascii_mm[] =
+ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+ short int ascii_ii[] =
+ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+ int use_ascii (int i) {
+ return ascii_mm[i] + ascii_ii[i];
+ }
+ short int ebcdic_ii[] =
+ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+ short int ebcdic_mm[] =
+ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+ int use_ebcdic (int i) {
+ return ebcdic_mm[i] + ebcdic_ii[i];
+ }
+ extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+ ac_cv_c_bigendian=yes
+ fi
+ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long int l;
+ char c[sizeof (long int)];
+ } u;
+ u.l = 1;
+ return u.c[sizeof (long int) - 1] == 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_c_bigendian=no
+else
+ ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+ yes)
+ $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+ no)
+ ;; #(
+ universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+ ;; #(
+ *)
+ as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for extern inline" >&5
+$as_echo_n "checking for extern inline... " >&6; }
+if ${ac_cv_c_extern_inline+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ac_cv_c_extern_inline=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ extern $ac_cv_c_inline double foo(double x);
+ extern $ac_cv_c_inline double foo(double x) { return x+1.0; };
+ double foo (double x) { return x + 1.0; };
+
+int
+main ()
+{
+foo(1.0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_extern_inline="yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_extern_inline" >&5
+$as_echo "$ac_cv_c_extern_inline" >&6; }
+if test "$ac_cv_c_extern_inline" != no ; then
+
+$as_echo "#define HAVE_EXTERN_INLINE 1" >>confdefs.h
+
+fi
+
+if test ! -f $srcdir/dev_mode_disabled && test "$RUN_FROM_BUILD_FARM" != yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Developer mode enabled" >&5
+$as_echo "$as_me: Developer mode enabled" >&6;}
+ ac_config_files="$ac_config_files dev.mk"
+
+ include_dev_mk='include dev.mk'
+ version=`(git --git-dir=$srcdir/.git describe --dirty 2>/dev/null || echo vunknown) | sed -e 's/v//' -e 's/-/+/' -e 's/-/_/g'`
+ echo "const char CCACHE_VERSION[] = \"$version\";" >version.c
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Developer mode disabled" >&5
+$as_echo "$as_me: Developer mode disabled" >&6;}
+fi
+
+if test ! -f $srcdir/version.c; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unable to determine ccache version" >&5
+$as_echo "$as_me: WARNING: unable to determine ccache version" >&2;}
+ echo "const char CCACHE_VERSION[] = \"unknown\";" >version.c
+fi
+
+test_suites=`ls $srcdir/test/test_*.c | egrep -v 'BASE|BACKUP|LOCAL|REMOTE' | xargs echo`
+
+ac_config_files="$ac_config_files Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "dev.mk") CONFIG_FILES="$CONFIG_FILES dev.mk" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+cat <<EOF >config.h.tmp
+#ifndef CCACHE_CONFIG_H
+#define CCACHE_CONFIG_H
+EOF
+cat config.h >>config.h.tmp
+echo '#endif' >>config.h.tmp
+mv config.h.tmp config.h
+
+mkdir -p .deps test
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: now build ccache by running make" >&5
+$as_echo "$as_me: now build ccache by running make" >&6;}
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..4095f4b
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,188 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT()
+AC_PREREQ(2.52)
+
+AC_MSG_NOTICE([Configuring ccache])
+
+AC_CONFIG_HEADER(config.h)
+
+AC_CANONICAL_HOST
+
+case $host in
+ *mingw32* | *mingw64* | *cygwin* | *wince* | *mingwce*)
+ windows_os=yes
+ AC_DEFINE(_WIN32_WINNT,0x0600, Windows Vista or newer is required)
+ ;;
+esac
+
+AC_SUBST(extra_libs)
+AC_SUBST(include_dev_mk)
+AC_SUBST(test_suites)
+
+m4_include(m4/feature_macros.m4)
+
+dnl Checks for programs.
+AC_PROG_CC_C99
+if test "$ac_cv_prog_cc_c99" = no; then
+ AC_MSG_ERROR(cannot find a C99-compatible compiler)
+fi
+
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_CHECK_TOOL(AR, ar)
+if test -z "$AR"; then
+ AC_MSG_ERROR(cannot find ar)
+fi
+
+# If GCC, turn on warnings.
+if test "x$GCC" = "xyes"; then
+ CFLAGS="$CFLAGS -Wall -W"
+else
+ CFLAGS="$CFLAGS -O"
+fi
+
+AC_HEADER_DIRENT
+AC_HEADER_TIME
+AC_HEADER_SYS_WAIT
+
+AC_CHECK_TYPES(long long)
+
+AC_CHECK_HEADERS(ctype.h pwd.h stdlib.h string.h strings.h sys/time.h sys/mman.h)
+AC_CHECK_HEADERS(termios.h)
+
+AC_CHECK_FUNCS(gethostname)
+AC_CHECK_FUNCS(getopt_long)
+AC_CHECK_FUNCS(getpwuid)
+AC_CHECK_FUNCS(gettimeofday)
+AC_CHECK_FUNCS(mkstemp)
+AC_CHECK_FUNCS(realpath)
+AC_CHECK_FUNCS(strndup)
+AC_CHECK_FUNCS(strtok_r)
+AC_CHECK_FUNCS(unsetenv)
+AC_CHECK_FUNCS(utimes)
+
+AC_CACHE_CHECK([for compar_fn_t in stdlib.h],ccache_cv_COMPAR_FN_T, [
+ AC_TRY_COMPILE(
+ [#include <stdlib.h>],
+ [void test_fn(void) { qsort(NULL, 0, 0, (__compar_fn_t)NULL); }],
+ ccache_cv_COMPAR_FN_T=yes,
+ ccache_cv_COMPAR_FN_T=no)])
+if test x"$ccache_cv_COMPAR_FN_T" = x"yes"; then
+ AC_DEFINE(HAVE_COMPAR_FN_T, 1,
+ Define to 1 if you have the `__compar_fn_t' typedef.)
+fi
+
+dnl Replacements of snprintf and friends.
+m4_include(m4/snprintf.m4)
+HW_FUNC_VSNPRINTF
+HW_FUNC_SNPRINTF
+HW_FUNC_VASPRINTF
+HW_FUNC_ASPRINTF
+
+dnl Check if -lm is needed.
+AC_SEARCH_LIBS(cos, m)
+
+
+dnl Check for zlib
+AC_ARG_WITH(bundled-zlib,
+ [AS_HELP_STRING([--with-bundled-zlib],
+ [use bundled zlib instead of the system's default zlib])])
+if test x${with_bundled_zlib} = x; then
+ AC_CACHE_CHECK(
+ [for zlib >= 1.2.3],
+ [ccache_cv_zlib_1_2_3],
+ AC_TRY_COMPILE(
+ [#include <zlib.h>],
+ [
+ #if (ZLIB_VERNUM >= 0x1230)
+ #else
+ #error "ZLIB_VERNUM < 0x1230"
+ #endif
+ ],
+ [ccache_cv_zlib_1_2_3=yes],
+ [ccache_cv_zlib_1_2_3=no]))
+ AC_CHECK_LIB(z, gzdopen, true)
+ if test $ccache_cv_zlib_1_2_3 = yes && test $ac_cv_lib_z_gzdopen = yes; then
+ use_bundled_zlib=no
+ else
+ AC_MSG_WARN(using bundled zlib)
+ use_bundled_zlib=yes
+ fi
+else
+ AC_MSG_NOTICE(using bundled zlib as requested)
+ use_bundled_zlib=yes
+fi
+
+if test x${use_bundled_zlib} = xyes; then
+ CPPFLAGS="$CPPFLAGS -I\$(srcdir)/zlib"
+ extra_libs="zlib/libz.a"
+ mkdir -p zlib
+else
+ LIBS="$LIBS -lz"
+fi
+
+dnl Linking on Windows needs ws2_32
+if test x${windows_os} = xyes; then
+ LIBS="$LIBS -lws2_32"
+ AC_CHECK_FUNCS(GetFinalPathNameByHandleW,[],[LIBS="$LIBS -lpsapi"])
+fi
+
+AC_C_BIGENDIAN
+
+AC_C_INLINE
+
+dnl Check for "extern inline".
+AC_CACHE_CHECK(
+ for extern inline,
+ ac_cv_c_extern_inline,
+ [
+ ac_cv_c_extern_inline=no
+ AC_TRY_COMPILE(
+ [
+ extern $ac_cv_c_inline double foo(double x);
+ extern $ac_cv_c_inline double foo(double x) { return x+1.0; };
+ double foo (double x) { return x + 1.0; };
+ ],
+ [foo(1.0)],
+ [ac_cv_c_extern_inline="yes"])])
+if test "$ac_cv_c_extern_inline" != no ; then
+ AC_DEFINE(HAVE_EXTERN_INLINE, 1,
+ Define to 1 if your compiler supports extern inline)
+fi
+
+dnl Enable developer mode if dev.mk.in exists.
+if test ! -f $srcdir/dev_mode_disabled && test "$RUN_FROM_BUILD_FARM" != yes; then
+ AC_MSG_NOTICE(Developer mode enabled)
+ AC_CONFIG_FILES([dev.mk])
+ include_dev_mk='include dev.mk'
+ version=`(git --git-dir=$srcdir/.git describe --dirty 2>/dev/null || echo vunknown) | sed -e 's/v//' -e 's/-/+/' -e 's/-/_/g'`
+ echo "const char CCACHE_VERSION@<:@@:>@ = \"$version\";" >version.c
+else
+ AC_MSG_NOTICE(Developer mode disabled)
+fi
+
+if test ! -f $srcdir/version.c; then
+ AC_MSG_WARN(unable to determine ccache version)
+ echo "const char CCACHE_VERSION@<:@@:>@ = \"unknown\";" >version.c
+fi
+
+dnl Find test suite files.
+test_suites=`ls $srcdir/test/test_*.c | egrep -v 'BASE|BACKUP|LOCAL|REMOTE' | xargs echo`
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+
+cat <<EOF >config.h.tmp
+#ifndef CCACHE_CONFIG_H
+#define CCACHE_CONFIG_H
+EOF
+cat config.h >>config.h.tmp
+echo '#endif' >>config.h.tmp
+mv config.h.tmp config.h
+
+mkdir -p .deps test
+
+
+AC_MSG_NOTICE(now build ccache by running make)
diff --git a/confitems.gperf b/confitems.gperf
new file mode 100644
index 0000000..531bc92
--- /dev/null
+++ b/confitems.gperf
@@ -0,0 +1,40 @@
+%language=ANSI-C
+%enum
+%struct-type
+%readonly-tables
+%define hash-function-name confitems_hash
+%define lookup-function-name confitems_get
+%define initializer-suffix ,0,NULL,0,NULL
+struct conf_item;
+%%
+base_dir, 0, ITEM_V(base_dir, env_string, absolute_path)
+cache_dir, 1, ITEM(cache_dir, env_string)
+cache_dir_levels, 2, ITEM_V(cache_dir_levels, unsigned, dir_levels)
+compiler, 3, ITEM(compiler, string)
+compiler_check, 4, ITEM(compiler_check, string)
+compression, 5, ITEM(compression, bool)
+compression_level, 6, ITEM(compression_level, unsigned)
+cpp_extension, 7, ITEM(cpp_extension, string)
+direct_mode, 8, ITEM(direct_mode, bool)
+disable, 9, ITEM(disable, bool)
+extra_files_to_hash, 10, ITEM(extra_files_to_hash, env_string)
+hard_link, 11, ITEM(hard_link, bool)
+hash_dir, 12, ITEM(hash_dir, bool)
+ignore_headers_in_manifest, 13, ITEM(ignore_headers_in_manifest, env_string)
+keep_comments_cpp, 14, ITEM(keep_comments_cpp, bool)
+limit_multiple, 15, ITEM(limit_multiple, float)
+log_file, 16, ITEM(log_file, env_string)
+max_files, 17, ITEM(max_files, unsigned)
+max_size, 18, ITEM(max_size, size)
+path, 19, ITEM(path, env_string)
+prefix_command, 20, ITEM(prefix_command, env_string)
+prefix_command_cpp, 21, ITEM(prefix_command_cpp, env_string)
+read_only, 22, ITEM(read_only, bool)
+read_only_direct, 23, ITEM(read_only_direct, bool)
+recache, 24, ITEM(recache, bool)
+run_second_cpp, 25, ITEM(run_second_cpp, bool)
+sloppiness, 26, ITEM(sloppiness, sloppiness)
+stats, 27, ITEM(stats, bool)
+temporary_dir, 28, ITEM(temporary_dir, env_string)
+umask, 29, ITEM(umask, umask)
+unify, 30, ITEM(unify, bool)
diff --git a/confitems_lookup.c b/confitems_lookup.c
new file mode 100644
index 0000000..7482557
--- /dev/null
+++ b/confitems_lookup.c
@@ -0,0 +1,191 @@
+/* ANSI-C code produced by gperf version 3.0.4 */
+/* Command-line: gperf confitems.gperf */
+/* Computed positions: -k'1-2' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 8 "confitems.gperf"
+struct conf_item;
+/* maximum key range = 46, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+confitems_hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 0, 13, 0,
+ 5, 10, 50, 0, 30, 20, 50, 0, 10, 20,
+ 5, 0, 0, 50, 5, 0, 10, 15, 50, 50,
+ 20, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50
+ };
+ return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
+}
+
+static
+#ifdef __GNUC__
+__inline
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+const struct conf_item *
+confitems_get (register const char *str, register unsigned int len)
+{
+ enum
+ {
+ TOTAL_KEYWORDS = 31,
+ MIN_WORD_LENGTH = 4,
+ MAX_WORD_LENGTH = 26,
+ MIN_HASH_VALUE = 4,
+ MAX_HASH_VALUE = 49
+ };
+
+ static const struct conf_item wordlist[] =
+ {
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+#line 29 "confitems.gperf"
+ {"path", 19, ITEM(path, env_string)},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+ {"",0,NULL,0,NULL},
+#line 13 "confitems.gperf"
+ {"compiler", 3, ITEM(compiler, string)},
+#line 11 "confitems.gperf"
+ {"cache_dir", 1, ITEM(cache_dir, env_string)},
+ {"",0,NULL,0,NULL},
+#line 15 "confitems.gperf"
+ {"compression", 5, ITEM(compression, bool)},
+ {"",0,NULL,0,NULL},
+#line 17 "confitems.gperf"
+ {"cpp_extension", 7, ITEM(cpp_extension, string)},
+#line 14 "confitems.gperf"
+ {"compiler_check", 4, ITEM(compiler_check, string)},
+#line 37 "confitems.gperf"
+ {"stats", 27, ITEM(stats, bool)},
+#line 12 "confitems.gperf"
+ {"cache_dir_levels", 2, ITEM_V(cache_dir_levels, unsigned, dir_levels)},
+#line 16 "confitems.gperf"
+ {"compression_level", 6, ITEM(compression_level, unsigned)},
+#line 26 "confitems.gperf"
+ {"log_file", 16, ITEM(log_file, env_string)},
+#line 30 "confitems.gperf"
+ {"prefix_command", 20, ITEM(prefix_command, env_string)},
+#line 36 "confitems.gperf"
+ {"sloppiness", 26, ITEM(sloppiness, sloppiness)},
+#line 10 "confitems.gperf"
+ {"base_dir", 0, ITEM_V(base_dir, env_string, absolute_path)},
+#line 34 "confitems.gperf"
+ {"recache", 24, ITEM(recache, bool)},
+#line 31 "confitems.gperf"
+ {"prefix_command_cpp", 21, ITEM(prefix_command_cpp, env_string)},
+#line 32 "confitems.gperf"
+ {"read_only", 22, ITEM(read_only, bool)},
+#line 40 "confitems.gperf"
+ {"unify", 30, ITEM(unify, bool)},
+ {"",0,NULL,0,NULL},
+#line 24 "confitems.gperf"
+ {"keep_comments_cpp", 14, ITEM(keep_comments_cpp, bool)},
+#line 28 "confitems.gperf"
+ {"max_size", 18, ITEM(max_size, size)},
+#line 27 "confitems.gperf"
+ {"max_files", 17, ITEM(max_files, unsigned)},
+ {"",0,NULL,0,NULL},
+#line 33 "confitems.gperf"
+ {"read_only_direct", 23, ITEM(read_only_direct, bool)},
+#line 19 "confitems.gperf"
+ {"disable", 9, ITEM(disable, bool)},
+#line 38 "confitems.gperf"
+ {"temporary_dir", 28, ITEM(temporary_dir, env_string)},
+#line 35 "confitems.gperf"
+ {"run_second_cpp", 25, ITEM(run_second_cpp, bool)},
+ {"",0,NULL,0,NULL},
+#line 18 "confitems.gperf"
+ {"direct_mode", 8, ITEM(direct_mode, bool)},
+ {"",0,NULL,0,NULL},
+#line 22 "confitems.gperf"
+ {"hash_dir", 12, ITEM(hash_dir, bool)},
+#line 21 "confitems.gperf"
+ {"hard_link", 11, ITEM(hard_link, bool)},
+#line 39 "confitems.gperf"
+ {"umask", 29, ITEM(umask, umask)},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+ {"",0,NULL,0,NULL},
+#line 25 "confitems.gperf"
+ {"limit_multiple", 15, ITEM(limit_multiple, float)},
+ {"",0,NULL,0,NULL},
+#line 23 "confitems.gperf"
+ {"ignore_headers_in_manifest", 13, ITEM(ignore_headers_in_manifest, env_string)},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+#line 20 "confitems.gperf"
+ {"extra_files_to_hash", 10, ITEM(extra_files_to_hash, env_string)}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = confitems_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
+static const size_t CONFITEMS_TOTAL_KEYWORDS = 31;
diff --git a/counters.c b/counters.c
new file mode 100644
index 0000000..1693c97
--- /dev/null
+++ b/counters.c
@@ -0,0 +1,61 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// A simple array of unsigned integers used for the statistics counters.
+
+#include "ccache.h"
+
+// Allocate and initialize a struct counters. Data entries up to the size are
+// set to 0.
+struct counters *
+counters_init(size_t initial_size)
+{
+ struct counters *c = x_malloc(sizeof(*c));
+ c->data = NULL;
+ c->size = 0;
+ c->allocated = 0;
+ counters_resize(c, initial_size);
+ return c;
+}
+
+// Free a counters struct.
+void
+counters_free(struct counters *c)
+{
+ free(c->data);
+ free(c);
+}
+
+// Set a new size. New data entries are set to 0.
+void
+counters_resize(struct counters *c, size_t new_size)
+{
+ if (new_size > c->size) {
+ bool realloc = false;
+ while (c->allocated < new_size) {
+ c->allocated += 32 + c->allocated;
+ realloc = true;
+ }
+ if (realloc) {
+ c->data = x_realloc(c->data, c->allocated * sizeof(c->data[0]));
+ }
+ for (size_t i = c->size; i < new_size; i++) {
+ c->data[i] = 0;
+ }
+ }
+
+ c->size = new_size;
+}
diff --git a/counters.h b/counters.h
new file mode 100644
index 0000000..91dd75e
--- /dev/null
+++ b/counters.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef COUNTERS_H
+#define COUNTERS_H
+
+#include <stddef.h>
+
+struct counters {
+ unsigned *data; // counter value
+ size_t size; // logical array size
+ size_t allocated; // allocated size
+};
+
+struct counters *counters_init(size_t initial_size);
+void counters_resize(struct counters *c, size_t new_size);
+void counters_free(struct counters *c);
+
+#endif
diff --git a/dev.mk.in b/dev.mk.in
new file mode 100644
index 0000000..d141b78
--- /dev/null
+++ b/dev.mk.in
@@ -0,0 +1,164 @@
+# GNU make syntax reigns in this file.
+
+all_cflags += -Werror
+all_cppflags += -MD -MP -MF .deps/$(subst .._,,$(subst /,_,$<)).d
+
+ASCIIDOC = asciidoc
+CPPCHECK = cppcheck
+CPPCHECK_SUPPRESSIONS = cppcheck-suppressions.txt
+GPERF = gperf
+XSLTPROC = xsltproc
+MANPAGE_XSL = $(shell if [ -e /usr/local/etc/asciidoc/docbook-xsl/manpage.xsl ]; \
+ then echo /usr/local/etc/asciidoc/docbook-xsl/manpage.xsl; \
+ else echo /etc/asciidoc/docbook-xsl/manpage.xsl; fi)
+
+
+version := \
+ $(shell (git --git-dir=$(srcdir)/.git describe --dirty || git --git-dir=$(srcdir)/.git describe || echo vunknown) \
+ 2>/dev/null | sed -e 's/v//' -e 's/-/+/' -e 's/-/_/g')
+
+dist_dir = ccache-$(version)
+dist_archives = \
+ ccache-$(version).tar.bz2 \
+ ccache-$(version).tar.gz
+ifneq ($(shell uname), Darwin)
+ dist_archives += ccache-$(version).tar.xz
+endif
+
+generated_docs = ccache.1 AUTHORS.html LICENSE.html MANUAL.html NEWS.html
+built_dist_files = $(generated_docs)
+
+headers = \
+ ccache.h \
+ compopt.h \
+ conf.h \
+ counters.h \
+ getopt_long.h \
+ hashtable.h \
+ hashtable_itr.h \
+ hashtable_private.h \
+ hashutil.h \
+ language.h \
+ macroskip.h \
+ manifest.h \
+ mdfour.h \
+ murmurhashneutral2.h \
+ system.h \
+ test/framework.h \
+ test/suites.h \
+ test/util.h
+
+files_to_clean += *.tar.bz2 *.tar.gz *.tar.xz *.xml .deps/* perfdir.*
+files_to_distclean += $(built_dist_files) version.c test/suites.h
+files_to_distclean += .deps version.c dev.mk
+
+source_dist_files = \
+ $(base_sources) \
+ $(headers) \
+ $(test_sources) \
+ AUTHORS.txt \
+ GPL-3.0.txt \
+ HACKING.txt \
+ LICENSE.txt \
+ MANUAL.txt \
+ Makefile.in \
+ NEWS.txt \
+ README.md \
+ autogen.sh \
+ config.guess \
+ config.h.in \
+ config.sub \
+ configure \
+ configure.ac \
+ confitems.gperf \
+ confitems_lookup.c \
+ dev.mk.in \
+ envtoconfitems.gperf \
+ envtoconfitems_lookup.c \
+ install-sh \
+ m4 \
+ main.c \
+ test.sh \
+ zlib/*.c \
+ zlib/*.h
+
+dist_files = \
+ $(addprefix $(srcdir)/, $(source_dist_files)) \
+ $(built_dist_files)
+
+uncrustify_exclude_files = \
+ getopt_long.c \
+ hashtable.c \
+ hashtable_itr.c \
+ snprintf.c
+
+ifneq ($(shell sed 's/.*"\(.*\)".*/\1/' version.c 2>/dev/null),$(version))
+ $(shell echo 'const char CCACHE_VERSION[] = "$(version)";' >version.c)
+endif
+version.o: version.c
+
+%_lookup.c: %.gperf
+ $(GPERF) $< | awk '/#ifdef __GNUC__/ { ++i; if (i == 2) { print "static"; }} {print}' >$@
+ echo "static const size_t `echo $* | tr a-z A-Z`_TOTAL_KEYWORDS = `sed -nr 's/.*TOTAL_KEYWORDS = ([0-9]+).*/\1/p' $@`;" >>$@
+
+.PHONY: dist
+dist: $(dist_archives)
+
+$(dist_archives): $(dist_files)
+ tmpdir=$$(mktemp -d /tmp/tmp-ccache-dist.XXXXXX) && \
+ dir=$$tmpdir/$(dist_dir) && \
+ mkdir $$dir && \
+ (cd $(srcdir) && \
+ rsync -r --relative $(source_dist_files) $$dir) && \
+ cp $(srcdir)/INSTALL-from-release-archive.md $$dir/INSTALL.md && \
+ cp $(built_dist_files) $$dir && \
+ echo "Remove this file to enable developer mode." >$$dir/dev_mode_disabled && \
+ (cd $$tmpdir && \
+ tarcompression= && \
+ case $@ in \
+ *.bz2) tarcompression=-j ;; \
+ *.gz) tarcompression=-z ;; \
+ *.xz) tarcompression=-J ;; \
+ esac && \
+ tar -c $$tarcompression -f $(CURDIR)/$@ $(dist_dir)) && \
+ rm -rf $$tmpdir
+
+.PHONY: distcheck
+distcheck: $(firstword $(dist_archives))
+ tmpdir=$$(mktemp -d /tmp/tmp-ccache-distcheck.XXXXXX) && \
+ (cd $$tmpdir && \
+ tar xjf $(CURDIR)/$< && \
+ mkdir -p $(dist_dir)/build && \
+ cd $(dist_dir)/build && \
+ ../configure --prefix=$$tmpdir/root && \
+ $(MAKE) install && \
+ $(MAKE) installcheck) && \
+ rm -rf $$tmpdir
+
+.PHONY: docs
+docs: $(generated_docs)
+
+%.html: %.txt
+ $(ASCIIDOC) -a revnumber=$(version) -a toc -b xhtml11 $<
+
+%.xml: %.txt
+ $(ASCIIDOC) -a revnumber=$(version) -d manpage -b docbook $<
+
+ccache.1: MANUAL.xml
+ $(XSLTPROC) --nonet $(MANPAGE_XSL) $<
+
+.PHONY: check-syntax
+check-syntax:
+ $(CC) $(all_cppflags) -I. $(all_cflags) -S -o /dev/null $(CHK_SOURCES)
+
+.PHONY: cppcheck
+cppcheck:
+ $(CPPCHECK) --suppressions-list=$(CPPCHECK_SUPPRESSIONS) \
+ --inline-suppr -q --enable=all \
+ $(non_3pp_sources) main.c $(test_sources)
+
+.PHONY: uncrustify
+uncrustify:
+ uncrustify -c uncrustify.cfg --no-backup --replace $(filter-out $(uncrustify_exclude_files), $(base_sources)) $(test_sources)
+
+-include .deps/*.d
diff --git a/dev_mode_disabled b/dev_mode_disabled
new file mode 100644
index 0000000..ba72f4f
--- /dev/null
+++ b/dev_mode_disabled
@@ -0,0 +1 @@
+Remove this file to enable developer mode.
diff --git a/envtoconfitems.gperf b/envtoconfitems.gperf
new file mode 100644
index 0000000..81d8444
--- /dev/null
+++ b/envtoconfitems.gperf
@@ -0,0 +1,41 @@
+%language=ANSI-C
+%enum
+%struct-type
+%readonly-tables
+%define hash-function-name envtoconfitems_hash
+%define lookup-function-name envtoconfitems_get
+%define slot-name env_name
+%define initializer-suffix ,""
+struct env_to_conf_item;
+%%
+BASEDIR, "base_dir"
+CC, "compiler"
+COMPILERCHECK, "compiler_check"
+COMPRESS, "compression"
+COMPRESSLEVEL, "compression_level"
+CPP2, "run_second_cpp"
+COMMENTS, "keep_comments_cpp"
+DIR, "cache_dir"
+DIRECT, "direct_mode"
+DISABLE, "disable"
+EXTENSION, "cpp_extension"
+EXTRAFILES, "extra_files_to_hash"
+HARDLINK, "hard_link"
+HASHDIR, "hash_dir"
+IGNOREHEADERS, "ignore_headers_in_manifest"
+LIMIT_MULTIPLE, "limit_multiple"
+LOGFILE, "log_file"
+MAXFILES, "max_files"
+MAXSIZE, "max_size"
+NLEVELS, "cache_dir_levels"
+PATH, "path"
+PREFIX, "prefix_command"
+PREFIX_CPP, "prefix_command_cpp"
+READONLY, "read_only"
+READONLY_DIRECT, "read_only_direct"
+RECACHE, "recache"
+SLOPPINESS, "sloppiness"
+STATS, "stats"
+TEMPDIR, "temporary_dir"
+UMASK, "umask"
+UNIFY, "unify"
diff --git a/envtoconfitems_lookup.c b/envtoconfitems_lookup.c
new file mode 100644
index 0000000..1265bd6
--- /dev/null
+++ b/envtoconfitems_lookup.c
@@ -0,0 +1,202 @@
+/* ANSI-C code produced by gperf version 3.0.4 */
+/* Command-line: gperf envtoconfitems.gperf */
+/* Computed positions: -k'1,5' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 9 "envtoconfitems.gperf"
+struct env_to_conf_item;
+/* maximum key range = 42, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+envtoconfitems_hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 20, 0, 0, 10,
+ 0, 44, 5, 15, 0, 44, 10, 25, 9, 0,
+ 5, 10, 5, 15, 10, 5, 44, 44, 44, 44,
+ 0, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[4]+1];
+ /*FALLTHROUGH*/
+ case 4:
+ case 3:
+ case 2:
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval;
+}
+
+static
+#ifdef __GNUC__
+__inline
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+const struct env_to_conf_item *
+envtoconfitems_get (register const char *str, register unsigned int len)
+{
+ enum
+ {
+ TOTAL_KEYWORDS = 31,
+ MIN_WORD_LENGTH = 2,
+ MAX_WORD_LENGTH = 15,
+ MIN_HASH_VALUE = 2,
+ MAX_HASH_VALUE = 43
+ };
+
+ static const struct env_to_conf_item wordlist[] =
+ {
+ {"",""}, {"",""},
+#line 12 "envtoconfitems.gperf"
+ {"CC", "compiler"},
+#line 18 "envtoconfitems.gperf"
+ {"DIR", "cache_dir"},
+#line 16 "envtoconfitems.gperf"
+ {"CPP2", "run_second_cpp"},
+ {"",""},
+#line 19 "envtoconfitems.gperf"
+ {"DIRECT", "direct_mode"},
+#line 20 "envtoconfitems.gperf"
+ {"DISABLE", "disable"},
+#line 17 "envtoconfitems.gperf"
+ {"COMMENTS", "keep_comments_cpp"},
+#line 31 "envtoconfitems.gperf"
+ {"PATH", "path"},
+#line 41 "envtoconfitems.gperf"
+ {"UNIFY", "unify"},
+#line 32 "envtoconfitems.gperf"
+ {"PREFIX", "prefix_command"},
+#line 36 "envtoconfitems.gperf"
+ {"RECACHE", "recache"},
+#line 13 "envtoconfitems.gperf"
+ {"COMPILERCHECK", "compiler_check"},
+ {"",""},
+#line 33 "envtoconfitems.gperf"
+ {"PREFIX_CPP", "prefix_command_cpp"},
+#line 30 "envtoconfitems.gperf"
+ {"NLEVELS", "cache_dir_levels"},
+#line 27 "envtoconfitems.gperf"
+ {"LOGFILE", "log_file"},
+#line 34 "envtoconfitems.gperf"
+ {"READONLY", "read_only"},
+#line 21 "envtoconfitems.gperf"
+ {"EXTENSION", "cpp_extension"},
+#line 40 "envtoconfitems.gperf"
+ {"UMASK", "umask"},
+ {"",""},
+#line 24 "envtoconfitems.gperf"
+ {"HASHDIR", "hash_dir"},
+#line 14 "envtoconfitems.gperf"
+ {"COMPRESS", "compression"},
+ {"",""},
+#line 35 "envtoconfitems.gperf"
+ {"READONLY_DIRECT", "read_only_direct"},
+ {"",""},
+#line 39 "envtoconfitems.gperf"
+ {"TEMPDIR", "temporary_dir"},
+#line 15 "envtoconfitems.gperf"
+ {"COMPRESSLEVEL", "compression_level"},
+#line 26 "envtoconfitems.gperf"
+ {"LIMIT_MULTIPLE", "limit_multiple"},
+#line 38 "envtoconfitems.gperf"
+ {"STATS", "stats"},
+ {"",""},
+#line 29 "envtoconfitems.gperf"
+ {"MAXSIZE", "max_size"},
+#line 28 "envtoconfitems.gperf"
+ {"MAXFILES", "max_files"},
+ {"",""},
+#line 37 "envtoconfitems.gperf"
+ {"SLOPPINESS", "sloppiness"},
+ {"",""},
+#line 11 "envtoconfitems.gperf"
+ {"BASEDIR", "base_dir"},
+#line 23 "envtoconfitems.gperf"
+ {"HARDLINK", "hard_link"},
+ {"",""},
+#line 22 "envtoconfitems.gperf"
+ {"EXTRAFILES", "extra_files_to_hash"},
+ {"",""}, {"",""},
+#line 25 "envtoconfitems.gperf"
+ {"IGNOREHEADERS", "ignore_headers_in_manifest"}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = envtoconfitems_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].env_name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
+static const size_t ENVTOCONFITEMS_TOTAL_KEYWORDS = 31;
diff --git a/execute.c b/execute.c
new file mode 100644
index 0000000..566ef9e
--- /dev/null
+++ b/execute.c
@@ -0,0 +1,348 @@
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2011-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+
+extern struct conf *conf;
+
+static char *
+find_executable_in_path(const char *name, const char *exclude_name, char *path);
+
+#ifdef _WIN32
+// Re-create a win32 command line string based on **argv.
+// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+char *
+win32argvtos(char *prefix, char **argv)
+{
+ int i = 0;
+ int k = 0;
+ char *arg = prefix ? prefix : argv[i++];
+ do {
+ int bs = 0;
+ for (int j = 0; arg[j]; j++) {
+ switch (arg[j]) {
+ case '\\':
+ bs++;
+ break;
+ case '"':
+ bs = (bs << 1) + 1;
+ default:
+ k += bs + 1;
+ bs = 0;
+ }
+ }
+ k += (bs << 1) + 3;
+ } while ((arg = argv[i++]));
+
+ char *ptr = malloc(k + 1);
+ char *str = ptr;
+ if (!str) {
+ return NULL;
+ }
+
+ i = 0;
+ arg = prefix ? prefix : argv[i++];
+ do {
+ int bs = 0;
+ *ptr++ = '"';
+ for (int j = 0; arg[j]; j++) {
+ switch (arg[j]) {
+ case '\\':
+ bs++;
+ break;
+ case '"':
+ bs = (bs << 1) + 1;
+ default:
+ while (bs && bs--) {
+ *ptr++ = '\\';
+ }
+ *ptr++ = arg[j];
+ }
+ }
+ bs <<= 1;
+ while (bs && bs--) {
+ *ptr++ = '\\';
+ }
+ *ptr++ = '"';
+ *ptr++ = ' ';
+ // cppcheck-suppress unreadVariable
+ } while ((arg = argv[i++]));
+ ptr[-1] = '\0';
+
+ return str;
+}
+
+char *
+win32getshell(char *path)
+{
+ char *path_env;
+ char *sh = NULL;
+ const char *ext = get_extension(path);
+ if (ext && strcasecmp(ext, ".sh") == 0 && (path_env = getenv("PATH"))) {
+ sh = find_executable_in_path("sh.exe", NULL, path_env);
+ }
+ if (!sh && getenv("CCACHE_DETECT_SHEBANG")) {
+ // Detect shebang.
+ FILE *fp = fopen(path, "r");
+ if (fp) {
+ char buf[10];
+ fgets(buf, sizeof(buf), fp);
+ buf[9] = 0;
+ if (str_eq(buf, "#!/bin/sh") && (path_env = getenv("PATH"))) {
+ sh = find_executable_in_path("sh.exe", NULL, path_env);
+ }
+ fclose(fp);
+ }
+ }
+
+ return sh;
+}
+
+void add_exe_ext_if_no_to_fullpath(char *full_path_win_ext, size_t max_size,
+ const char *ext, const char *path) {
+ if (!ext || (!str_eq(".exe", ext)
+ && !str_eq(".bat", ext)
+ && !str_eq(".EXE", ext)
+ && !str_eq(".BAT", ext))) {
+ snprintf(full_path_win_ext, max_size, "%s.exe", path);
+ } else {
+ snprintf(full_path_win_ext, max_size, "%s", path);
+ }
+}
+
+int
+win32execute(char *path, char **argv, int doreturn,
+ int fd_stdout, int fd_stderr)
+{
+ PROCESS_INFORMATION pi;
+ memset(&pi, 0x00, sizeof(pi));
+
+ STARTUPINFO si;
+ memset(&si, 0x00, sizeof(si));
+
+ char *sh = win32getshell(path);
+ if (sh) {
+ path = sh;
+ }
+
+ si.cb = sizeof(STARTUPINFO);
+ if (fd_stdout != -1) {
+ si.hStdOutput = (HANDLE)_get_osfhandle(fd_stdout);
+ si.hStdError = (HANDLE)_get_osfhandle(fd_stderr);
+ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ if (si.hStdOutput == INVALID_HANDLE_VALUE
+ || si.hStdError == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+ } else {
+ // Redirect subprocess stdout, stderr into current process.
+ si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ if (si.hStdOutput == INVALID_HANDLE_VALUE
+ || si.hStdError == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+ }
+
+ char *args = win32argvtos(sh, argv);
+ const char *ext = strrchr(path, '.');
+ char full_path_win_ext[MAX_PATH] = {0};
+ add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext, path);
+ BOOL ret =
+ CreateProcess(full_path_win_ext, args, NULL, NULL, 1, 0, NULL, NULL,
+ &si, &pi);
+ if (fd_stdout != -1) {
+ close(fd_stdout);
+ close(fd_stderr);
+ }
+ free(args);
+ if (ret == 0) {
+ LPVOID lpMsgBuf;
+ DWORD dw = GetLastError();
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
+ 0, NULL);
+
+ LPVOID lpDisplayBuf =
+ (LPVOID) LocalAlloc(LMEM_ZEROINIT,
+ (lstrlen((LPCTSTR) lpMsgBuf)
+ + lstrlen((LPCTSTR) __FILE__) + 200)
+ * sizeof(TCHAR));
+ _snprintf((LPTSTR) lpDisplayBuf,
+ LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+ TEXT("%s failed with error %d: %s"), __FILE__, dw, lpMsgBuf);
+
+ cc_log("can't execute %s; OS returned error: %s",
+ full_path_win_ext, (char *)lpDisplayBuf);
+
+ LocalFree(lpMsgBuf);
+ LocalFree(lpDisplayBuf);
+
+ return -1;
+ }
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ DWORD exitcode;
+ GetExitCodeProcess(pi.hProcess, &exitcode);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ if (!doreturn) {
+ x_exit(exitcode);
+ }
+ return exitcode;
+}
+
+#else
+
+// Execute a compiler backend, capturing all output to the given paths the full
+// path to the compiler to run is in argv[0].
+int
+execute(char **argv, int fd_out, int fd_err, pid_t *pid)
+{
+ cc_log_argv("Executing ", argv);
+
+ block_signals();
+ *pid = fork();
+ unblock_signals();
+
+ if (*pid == -1) {
+ fatal("Failed to fork: %s", strerror(errno));
+ }
+
+ if (*pid == 0) {
+ // Child.
+ dup2(fd_out, 1);
+ close(fd_out);
+ dup2(fd_err, 2);
+ close(fd_err);
+ x_exit(execv(argv[0], argv));
+ }
+
+ close(fd_out);
+ close(fd_err);
+
+ int status;
+ if (waitpid(*pid, &status, 0) != *pid) {
+ fatal("waitpid failed: %s", strerror(errno));
+ }
+
+ block_signals();
+ *pid = 0;
+ unblock_signals();
+
+ if (WEXITSTATUS(status) == 0 && WIFSIGNALED(status)) {
+ return -1;
+ }
+
+ return WEXITSTATUS(status);
+}
+#endif
+
+// Find an executable by name in $PATH. Exclude any that are links to
+// exclude_name.
+char *
+find_executable(const char *name, const char *exclude_name)
+{
+ if (is_absolute_path(name)) {
+ return x_strdup(name);
+ }
+
+ char *path = conf->path;
+ if (str_eq(path, "")) {
+ path = getenv("PATH");
+ }
+ if (!path) {
+ cc_log("No PATH variable");
+ return NULL;
+ }
+
+ return find_executable_in_path(name, exclude_name, path);
+}
+
+static char *
+find_executable_in_path(const char *name, const char *exclude_name, char *path)
+{
+ path = x_strdup(path);
+
+ // Search the path looking for the first compiler of the right name that
+ // isn't us.
+ char *saveptr = NULL;
+ for (char *tok = strtok_r(path, PATH_DELIM, &saveptr);
+ tok;
+ tok = strtok_r(NULL, PATH_DELIM, &saveptr)) {
+#ifdef _WIN32
+ char namebuf[MAX_PATH];
+ int ret = SearchPath(tok, name, NULL, sizeof(namebuf), namebuf, NULL);
+ if (!ret) {
+ char *exename = format("%s.exe", name);
+ ret = SearchPath(tok, exename, NULL, sizeof(namebuf), namebuf, NULL);
+ free(exename);
+ }
+ (void) exclude_name;
+ if (ret) {
+ free(path);
+ return x_strdup(namebuf);
+ }
+#else
+ struct stat st1, st2;
+ char *fname = format("%s/%s", tok, name);
+ // Look for a normal executable file.
+ if (access(fname, X_OK) == 0 &&
+ lstat(fname, &st1) == 0 &&
+ stat(fname, &st2) == 0 &&
+ S_ISREG(st2.st_mode)) {
+ if (S_ISLNK(st1.st_mode)) {
+ char *buf = x_realpath(fname);
+ if (buf) {
+ char *p = basename(buf);
+ if (str_eq(p, exclude_name)) {
+ // It's a link to "ccache"!
+ free(p);
+ free(buf);
+ continue;
+ }
+ free(buf);
+ free(p);
+ }
+ }
+
+ // Found it!
+ free(path);
+ return fname;
+ }
+ free(fname);
+#endif
+ }
+
+ free(path);
+ return NULL;
+}
+
+void
+print_command(FILE *fp, char **argv)
+{
+ for (int i = 0; argv[i]; i++) {
+ fprintf(fp, "%s%s", (i == 0) ? "" : " ", argv[i]);
+ }
+ fprintf(fp, "\n");
+}
diff --git a/exitfn.c b/exitfn.c
new file mode 100644
index 0000000..5c2c482
--- /dev/null
+++ b/exitfn.c
@@ -0,0 +1,82 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+
+struct exit_function {
+ void (*function)(void *);
+ void *context;
+ struct exit_function *next;
+};
+
+struct nullary_exit_function {
+ void (*function)(void);
+};
+
+static struct exit_function *exit_functions;
+
+static void
+call_nullary_exit_function(void *context)
+{
+ struct nullary_exit_function *p = (struct nullary_exit_function *)context;
+ p->function();
+ free(p);
+}
+
+// Initialize exit functions. Must be called once before exitfn_add* are used.
+void
+exitfn_init(void)
+{
+ if (atexit(exitfn_call) != 0) {
+ fatal("atexit failed: %s", strerror(errno));
+ }
+}
+
+// Add a nullary function to be called when ccache exits. Functions are called
+// in reverse order.
+void
+exitfn_add_nullary(void (*function)(void))
+{
+ struct nullary_exit_function *p = x_malloc(sizeof(*p));
+ p->function = function;
+ exitfn_add(call_nullary_exit_function, p);
+}
+
+// Add a function to be called with a context parameter when ccache exits.
+// Functions are called in reverse order.
+void
+exitfn_add(void (*function)(void *), void *context)
+{
+ struct exit_function *p = x_malloc(sizeof(*p));
+ p->function = function;
+ p->context = context;
+ p->next = exit_functions;
+ exit_functions = p;
+}
+
+// Call added functions.
+void
+exitfn_call(void)
+{
+ struct exit_function *p = exit_functions;
+ exit_functions = NULL;
+ while (p) {
+ p->function(p->context);
+ struct exit_function *q = p;
+ p = p->next;
+ free(q);
+ }
+}
diff --git a/getopt_long.c b/getopt_long.c
new file mode 100644
index 0000000..e426b1a
--- /dev/null
+++ b/getopt_long.c
@@ -0,0 +1,197 @@
+/*
+ * getopt_long() -- long options parser
+ *
+ * Portions Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Portions Copyright (c) 2003
+ * PostgreSQL Global Development Group
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifndef HAVE_GETOPT_LONG
+
+#include "getopt_long.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define BADCH '?'
+#define BADARG ':'
+#define EMSG ""
+
+int
+getopt_long(int argc, char *const argv[],
+ const char *optstring,
+ const struct option * longopts, int *longindex)
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (!*place)
+ { /* update scanning pointer */
+ if (optind >= argc)
+ {
+ place = EMSG;
+ return -1;
+ }
+
+ place = argv[optind];
+
+ if (place[0] != '-')
+ {
+ place = EMSG;
+ return -1;
+ }
+
+ place++;
+
+ if (place[0] && place[0] == '-' && place[1] == '\0')
+ { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return -1;
+ }
+
+ if (place[0] && place[0] == '-' && place[1])
+ {
+ /* long option */
+ size_t namelen;
+ int i;
+
+ place++;
+
+ namelen = strcspn(place, "=");
+ for (i = 0; longopts[i].name != NULL; i++)
+ {
+ if (strlen(longopts[i].name) == namelen
+ && strncmp(place, longopts[i].name, namelen) == 0)
+ {
+ if (longopts[i].has_arg)
+ {
+ if (place[namelen] == '=')
+ optarg = place + namelen + 1;
+ else if (optind < argc - 1)
+ {
+ optind++;
+ optarg = argv[optind];
+ }
+ else
+ {
+ if (optstring[0] == ':')
+ return BADARG;
+ if (opterr)
+ fprintf(stderr,
+ "%s: option requires an argument -- %s\n",
+ argv[0], place);
+ place = EMSG;
+ optind++;
+ return BADCH;
+ }
+ }
+ else
+ {
+ optarg = NULL;
+ if (place[namelen] != 0)
+ {
+ /* XXX error? */
+ }
+ }
+
+ optind++;
+
+ if (longindex)
+ *longindex = i;
+
+ place = EMSG;
+
+ if (longopts[i].flag == NULL)
+ return longopts[i].val;
+ else
+ {
+ *longopts[i].flag = longopts[i].val;
+ return 0;
+ }
+ }
+ }
+
+ if (opterr && optstring[0] != ':')
+ fprintf(stderr,
+ "%s: illegal option -- %s\n", argv[0], place);
+ place = EMSG;
+ optind++;
+ return BADCH;
+ }
+ }
+
+ /* short option */
+ optopt = (int) *place++;
+
+ oli = strchr(optstring, optopt);
+ if (!oli)
+ {
+ if (!*place)
+ ++optind;
+ if (opterr && *optstring != ':')
+ fprintf(stderr,
+ "%s: illegal option -- %c\n", argv[0], optopt);
+ return BADCH;
+ }
+
+ if (oli[1] != ':')
+ { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else
+ { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (argc <= ++optind)
+ { /* no arg */
+ place = EMSG;
+ if (*optstring == ':')
+ return BADARG;
+ if (opterr)
+ fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ argv[0], optopt);
+ return BADCH;
+ }
+ else
+ /* white space */
+ optarg = argv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return optopt;
+}
+
+#endif /* HAVE_GETOPT_LONG */
diff --git a/getopt_long.h b/getopt_long.h
new file mode 100644
index 0000000..c14b4be
--- /dev/null
+++ b/getopt_long.h
@@ -0,0 +1,30 @@
+/*
+ * Portions Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Portions Copyright (c) 2003-2010, PostgreSQL Global Development Group
+ */
+#ifndef GETOPT_LONG_H
+#define GETOPT_LONG_H
+
+extern int opterr;
+extern int optind;
+extern int optopt;
+extern char *optarg;
+
+struct option
+{
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+#define no_argument 0
+#define required_argument 1
+
+extern int getopt_long(int argc, char *const argv[],
+ const char *optstring,
+ const struct option * longopts, int *longindex);
+
+#endif /* GETOPT_LONG_H */
diff --git a/hash.c b/hash.c
new file mode 100644
index 0000000..3b462ca
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,128 @@
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+
+#define HASH_DELIMITER "\000cCaChE"
+
+void
+hash_start(struct mdfour *md)
+{
+ mdfour_begin(md);
+}
+
+void
+hash_buffer(struct mdfour *md, const void *s, size_t len)
+{
+ mdfour_update(md, (unsigned char *)s, len);
+}
+
+// Return the hash result as a hex string. Caller frees.
+char *
+hash_result(struct mdfour *md)
+{
+ unsigned char sum[16];
+
+ hash_result_as_bytes(md, sum);
+ return format_hash_as_string(sum, (unsigned) md->totalN);
+}
+
+// Return the hash result as 16 binary bytes.
+void
+hash_result_as_bytes(struct mdfour *md, unsigned char *out)
+{
+ hash_buffer(md, NULL, 0);
+ mdfour_result(md, out);
+}
+
+bool
+hash_equal(struct mdfour *md1, struct mdfour *md2)
+{
+ unsigned char sum1[16];
+ hash_result_as_bytes(md1, sum1);
+ unsigned char sum2[16];
+ hash_result_as_bytes(md2, sum2);
+ return memcmp(sum1, sum2, sizeof(sum1)) == 0;
+}
+
+// Hash some data that is unlikely to occur in the input. The idea is twofold:
+//
+// - Delimit things like arguments from each other (e.g., so that -I -O2 and
+// -I-O2 hash differently).
+// - Tag different types of hashed information so that it's possible to do
+// conditional hashing of information in a safe way (e.g., if we want to hash
+// information X if CCACHE_A is set and information Y if CCACHE_B is set,
+// there should never be a hash collision risk).
+void
+hash_delimiter(struct mdfour *md, const char *type)
+{
+ hash_buffer(md, HASH_DELIMITER, sizeof(HASH_DELIMITER));
+ hash_buffer(md, type, strlen(type) + 1); // Include NUL.
+}
+
+void
+hash_string(struct mdfour *md, const char *s)
+{
+ hash_string_length(md, s, strlen(s));
+}
+
+void
+hash_string_length(struct mdfour *md, const char *s, int length)
+{
+ hash_buffer(md, s, length);
+}
+
+void
+hash_int(struct mdfour *md, int x)
+{
+ hash_buffer(md, (char *)&x, sizeof(x));
+}
+
+// Add contents of an open file to the hash. Returns true on success, otherwise
+// false.
+bool
+hash_fd(struct mdfour *md, int fd)
+{
+ char buf[READ_BUFFER_SIZE];
+ ssize_t n;
+
+ while ((n = read(fd, buf, sizeof(buf))) != 0) {
+ if (n == -1 && errno != EINTR) {
+ break;
+ }
+ if (n > 0) {
+ hash_buffer(md, buf, n);
+ }
+ }
+ return n == 0;
+}
+
+// Add contents of a file to the hash. Returns true on success, otherwise
+// false.
+bool
+hash_file(struct mdfour *md, const char *fname)
+{
+ int fd = open(fname, O_RDONLY|O_BINARY);
+ if (fd == -1) {
+ cc_log("Failed to open %s: %s", fname, strerror(errno));
+ return false;
+ }
+
+ bool ret = hash_fd(md, fd);
+ close(fd);
+ return ret;
+}
diff --git a/hashtable.c b/hashtable.c
new file mode 100644
index 0000000..02ab454
--- /dev/null
+++ b/hashtable.c
@@ -0,0 +1,303 @@
+/*
+ Copyright (c) 2002, 2004, Christopher Clark
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of the original author; nor the names of any
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+/*
+Credit for primes table: Aaron Krowne
+ http://br.endernet.org/~akrowne/
+ http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
+*/
+static const unsigned int primes[] = {
+53, 97, 193, 389,
+769, 1543, 3079, 6151,
+12289, 24593, 49157, 98317,
+196613, 393241, 786433, 1572869,
+3145739, 6291469, 12582917, 25165843,
+50331653, 100663319, 201326611, 402653189,
+805306457, 1610612741
+};
+const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
+const float max_load_factor = 0.65;
+
+/*****************************************************************************/
+struct hashtable *
+create_hashtable(unsigned int minsize,
+ unsigned int (*hashf) (void*),
+ int (*eqf) (void*,void*))
+{
+ struct hashtable *h;
+ unsigned int pindex, size = primes[0];
+ /* Check requested hashtable isn't too large */
+ if (minsize > (1u << 30)) return NULL;
+ /* Enforce size as prime */
+ for (pindex=0; pindex < prime_table_length; pindex++) {
+ if (primes[pindex] > minsize) { size = primes[pindex]; break; }
+ }
+ h = (struct hashtable *)malloc(sizeof(struct hashtable));
+ if (NULL == h) return NULL; /*oom*/
+ h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
+ if (NULL == h->table) { free(h); return NULL; } /*oom*/
+ memset(h->table, 0, size * sizeof(struct entry *));
+ h->tablelength = size;
+ h->primeindex = pindex;
+ h->entrycount = 0;
+ h->hashfn = hashf;
+ h->eqfn = eqf;
+ h->loadlimit = (unsigned int) ceil(size * max_load_factor);
+ return h;
+}
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k)
+{
+ /* Aim to protect against poor hash functions by adding logic here
+ * - logic taken from java 1.4 hashtable source */
+ unsigned int i = h->hashfn(k);
+ i += ~(i << 9);
+ i ^= ((i >> 14) | (i << 18)); /* >>> */
+ i += (i << 4);
+ i ^= ((i >> 10) | (i << 22)); /* >>> */
+ return i;
+}
+
+/*****************************************************************************/
+static int
+hashtable_expand(struct hashtable *h)
+{
+ /* Double the size of the table to accommodate more entries */
+ struct entry **newtable;
+ struct entry *e;
+ unsigned int newsize, i, index;
+ /* Check we're not hitting max capacity */
+ if (h->primeindex == (prime_table_length - 1)) return 0;
+ newsize = primes[++(h->primeindex)];
+
+ newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
+ if (NULL != newtable)
+ {
+ memset(newtable, 0, newsize * sizeof(struct entry *));
+ /* This algorithm is not 'stable'. ie. it reverses the list
+ * when it transfers entries between the tables */
+ for (i = 0; i < h->tablelength; i++) {
+ while (NULL != (e = h->table[i])) {
+ h->table[i] = e->next;
+ index = indexFor(newsize,e->h);
+ e->next = newtable[index];
+ newtable[index] = e;
+ }
+ }
+ free(h->table);
+ h->table = newtable;
+ }
+ /* Plan B: realloc instead */
+ else
+ {
+ struct entry **pE;
+ newtable = (struct entry **)
+ realloc(h->table, newsize * sizeof(struct entry *));
+ if (NULL == newtable) { (h->primeindex)--; return 0; }
+ h->table = newtable;
+ memset(newtable[h->tablelength], 0, newsize - h->tablelength);
+ for (i = 0; i < h->tablelength; i++) {
+ for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
+ index = indexFor(newsize,e->h);
+ if (index == i)
+ {
+ pE = &(e->next);
+ }
+ else
+ {
+ *pE = e->next;
+ e->next = newtable[index];
+ newtable[index] = e;
+ }
+ }
+ }
+ }
+ h->tablelength = newsize;
+ h->loadlimit = (unsigned int) ceil(newsize * max_load_factor);
+ return -1;
+}
+
+/*****************************************************************************/
+unsigned int
+hashtable_count(struct hashtable *h)
+{
+ return h->entrycount;
+}
+
+/*****************************************************************************/
+int
+hashtable_insert(struct hashtable *h, void *k, void *v)
+{
+ /* This method allows duplicate keys - but they shouldn't be used */
+ unsigned int index;
+ struct entry *e;
+ if (++(h->entrycount) > h->loadlimit)
+ {
+ /* Ignore the return value. If expand fails, we should
+ * still try cramming just this value into the existing table
+ * -- we may not have memory for a larger table, but one more
+ * element may be ok. Next time we insert, we'll try expanding again.*/
+ hashtable_expand(h);
+ }
+ e = (struct entry *)malloc(sizeof(struct entry));
+ if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
+ e->h = hash(h,k);
+ index = indexFor(h->tablelength,e->h);
+ e->k = k;
+ e->v = v;
+ e->next = h->table[index];
+ h->table[index] = e;
+ return -1;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_search(struct hashtable *h, void *k)
+{
+ struct entry *e;
+ unsigned int hashvalue, index;
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hashvalue);
+ e = h->table[index];
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
+ e = e->next;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_remove(struct hashtable *h, void *k)
+{
+ /* TODO: consider compacting the table when the load factor drops enough,
+ * or provide a 'compact' method. */
+
+ struct entry *e;
+ struct entry **pE;
+ void *v;
+ unsigned int hashvalue, index;
+
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hash(h,k));
+ pE = &(h->table[index]);
+ e = *pE;
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+ {
+ *pE = e->next;
+ h->entrycount--;
+ v = e->v;
+ freekey(e->k);
+ free(e);
+ return v;
+ }
+ pE = &(e->next);
+ e = e->next;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+/* destroy */
+void
+hashtable_destroy(struct hashtable *h, int free_values)
+{
+ unsigned int i;
+ struct entry *e, *f;
+ struct entry **table = h->table;
+ if (free_values)
+ {
+ for (i = 0; i < h->tablelength; i++)
+ {
+ e = table[i];
+ while (NULL != e)
+ { f = e; e = e->next; freekey(f->k); free(f->v); free(f); }
+ }
+ }
+ else
+ {
+ for (i = 0; i < h->tablelength; i++)
+ {
+ e = table[i];
+ while (NULL != e)
+ { f = e; e = e->next; freekey(f->k); free(f); }
+ }
+ }
+ free(h->table);
+ free(h);
+}
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/hashtable.h b/hashtable.h
new file mode 100644
index 0000000..4280007
--- /dev/null
+++ b/hashtable.h
@@ -0,0 +1,230 @@
+/*
+ Copyright (c) 2002, 2004, Christopher Clark
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of the original author; nor the names of any
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HASHTABLE_CWC22_H__
+#define __HASHTABLE_CWC22_H__
+
+#include "config.h"
+
+struct hashtable;
+
+/* Example of use:
+ *
+ * struct hashtable *h;
+ * struct some_key *k;
+ * struct some_value *v;
+ *
+ * static unsigned int hash_from_key_fn( void *k );
+ * static int keys_equal_fn ( void *key1, void *key2 );
+ *
+ * h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
+ * k = (struct some_key *) malloc(sizeof(struct some_key));
+ * v = (struct some_value *) malloc(sizeof(struct some_value));
+ *
+ * (initialise k and v to suitable values)
+ *
+ * if (! hashtable_insert(h,k,v) )
+ * { exit(-1); }
+ *
+ * if (NULL == (found = hashtable_search(h,k) ))
+ * { printf("not found!"); }
+ *
+ * if (NULL == (found = hashtable_remove(h,k) ))
+ * { printf("Not found\n"); }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ *
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+/*****************************************************************************
+ * create_hashtable
+
+ * @name create_hashtable
+ * @param minsize minimum initial size of hashtable
+ * @param hashfunction function for hashing keys
+ * @param key_eq_fn function for determining key equality
+ * @return newly created hashtable or NULL on failure
+ */
+
+struct hashtable *
+create_hashtable(unsigned int minsize,
+ unsigned int (*hashfunction) (void*),
+ int (*key_eq_fn) (void*,void*));
+
+/*****************************************************************************
+ * hashtable_insert
+
+ * @name hashtable_insert
+ * @param h the hashtable to insert into
+ * @param k the key - hashtable claims ownership and will free on removal
+ * @param v the value - does not claim ownership
+ * @return non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+
+int
+hashtable_insert(struct hashtable *h, void *k, void *v);
+
+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
+int fnname (struct hashtable *h, keytype *k, valuetype *v) \
+{ \
+ return hashtable_insert(h,k,v); \
+}
+
+/*****************************************************************************
+ * hashtable_search
+
+ * @name hashtable_search
+ * @param h the hashtable to search
+ * @param k the key to search for - does not claim ownership
+ * @return the value associated with the key, or NULL if none found
+ */
+
+void *
+hashtable_search(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
+valuetype * fnname (struct hashtable *h, keytype *k) \
+{ \
+ return (valuetype *) (hashtable_search(h,k)); \
+}
+
+/*****************************************************************************
+ * hashtable_remove
+
+ * @name hashtable_remove
+ * @param h the hashtable to remove the item from
+ * @param k the key to search for - does not claim ownership
+ * @return the value associated with the key, or NULL if none found
+ */
+
+void * /* returns value */
+hashtable_remove(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
+valuetype * fnname (struct hashtable *h, keytype *k) \
+{ \
+ return (valuetype *) (hashtable_remove(h,k)); \
+}
+
+
+/*****************************************************************************
+ * hashtable_count
+
+ * @name hashtable_count
+ * @param h the hashtable
+ * @return the number of items stored in the hashtable
+ */
+unsigned int
+hashtable_count(struct hashtable *h);
+
+
+/*****************************************************************************
+ * hashtable_destroy
+
+ * @name hashtable_destroy
+ * @param h the hashtable
+ * @param free_values whether to call 'free' on the remaining values
+ */
+
+void
+hashtable_destroy(struct hashtable *h, int free_values);
+
+#endif /* __HASHTABLE_CWC22_H__ */
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/hashtable_itr.c b/hashtable_itr.c
new file mode 100644
index 0000000..5dced84
--- /dev/null
+++ b/hashtable_itr.c
@@ -0,0 +1,188 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include "hashtable_itr.h"
+#include <stdlib.h> /* defines NULL */
+
+/*****************************************************************************/
+/* hashtable_iterator - iterator constructor */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h)
+{
+ unsigned int i, tablelength;
+ struct hashtable_itr *itr = (struct hashtable_itr *)
+ malloc(sizeof(struct hashtable_itr));
+ if (NULL == itr) return NULL;
+ itr->h = h;
+ itr->e = NULL;
+ itr->parent = NULL;
+ tablelength = h->tablelength;
+ itr->index = tablelength;
+ if (0 == h->entrycount) return itr;
+
+ for (i = 0; i < tablelength; i++)
+ {
+ if (NULL != h->table[i])
+ {
+ itr->e = h->table[i];
+ itr->index = i;
+ break;
+ }
+ }
+ return itr;
+}
+
+/*****************************************************************************/
+/* key - return the key of the (key,value) pair at the current position */
+/* value - return the value of the (key,value) pair at the current position */
+
+void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{ return i->e->k; }
+
+void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{ return i->e->v; }
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr)
+{
+ unsigned int j,tablelength;
+ struct entry **table;
+ struct entry *next;
+ if (NULL == itr->e) return 0; /* stupidity check */
+
+ next = itr->e->next;
+ if (NULL != next)
+ {
+ itr->parent = itr->e;
+ itr->e = next;
+ return -1;
+ }
+ tablelength = itr->h->tablelength;
+ itr->parent = NULL;
+ if (tablelength <= (j = ++(itr->index)))
+ {
+ itr->e = NULL;
+ return 0;
+ }
+ table = itr->h->table;
+ while (NULL == (next = table[j]))
+ {
+ if (++j >= tablelength)
+ {
+ itr->index = tablelength;
+ itr->e = NULL;
+ return 0;
+ }
+ }
+ itr->index = j;
+ itr->e = next;
+ return -1;
+}
+
+/*****************************************************************************/
+/* remove - remove the entry at the current iterator position
+ * and advance the iterator, if there is a successive
+ * element.
+ * If you want the value, read it before you remove:
+ * beware memory leaks if you don't.
+ * Returns zero if end of iteration. */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr)
+{
+ struct entry *remember_e, *remember_parent;
+ int ret;
+
+ /* Do the removal */
+ if (NULL == (itr->parent))
+ {
+ /* element is head of a chain */
+ itr->h->table[itr->index] = itr->e->next;
+ } else {
+ /* element is mid-chain */
+ itr->parent->next = itr->e->next;
+ }
+ /* itr->e is now outside the hashtable */
+ remember_e = itr->e;
+ itr->h->entrycount--;
+ freekey(remember_e->k);
+
+ /* Advance the iterator, correcting the parent */
+ remember_parent = itr->parent;
+ ret = hashtable_iterator_advance(itr);
+ if (itr->parent == remember_e) { itr->parent = remember_parent; }
+ free(remember_e);
+ return ret;
+}
+
+/*****************************************************************************/
+int /* returns zero if not found */
+hashtable_iterator_search(struct hashtable_itr *itr,
+ struct hashtable *h, void *k)
+{
+ struct entry *e, *parent;
+ unsigned int hashvalue, index;
+
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hashvalue);
+
+ e = h->table[index];
+ parent = NULL;
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+ {
+ itr->index = index;
+ itr->e = e;
+ itr->parent = parent;
+ itr->h = h;
+ return -1;
+ }
+ parent = e;
+ e = e->next;
+ }
+ return 0;
+}
+
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/hashtable_itr.h b/hashtable_itr.h
new file mode 100644
index 0000000..9523b14
--- /dev/null
+++ b/hashtable_itr.h
@@ -0,0 +1,122 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_ITR_CWC22__
+#define __HASHTABLE_ITR_CWC22__
+#include "hashtable.h"
+#include "hashtable_private.h" /* needed to enable inlining */
+
+/*****************************************************************************/
+/* This struct is only concrete here to allow the inlining of two of the
+ * accessor functions. */
+struct hashtable_itr
+{
+ struct hashtable *h;
+ struct entry *e;
+ struct entry *parent;
+ unsigned int index;
+};
+
+
+/*****************************************************************************/
+/* hashtable_iterator
+ */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h);
+
+/*****************************************************************************/
+/* hashtable_iterator_key
+ * - return the value of the (key,value) pair at the current position */
+
+#ifdef HAVE_EXTERN_INLINE
+extern inline void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+ return i->e->k;
+}
+#else
+void *
+hashtable_iterator_key(struct hashtable_itr *i);
+#endif
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+#ifdef HAVE_EXTERN_INLINE
+extern inline void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+ return i->e->v;
+}
+#else
+void *
+hashtable_iterator_value(struct hashtable_itr *i);
+#endif
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* remove - remove current element and advance the iterator to the next element
+ * NB: if you need the value to free it, read it before
+ * removing. ie: beware memory leaks!
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* search - overwrite the supplied iterator, to point to the entry
+ * matching the supplied key.
+ h points to the hashtable to be searched.
+ * returns zero if not found. */
+int
+hashtable_iterator_search(struct hashtable_itr *itr,
+ struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
+int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
+{ \
+ return (hashtable_iterator_search(i,h,k)); \
+}
+
+
+
+#endif /* __HASHTABLE_ITR_CWC22__*/
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/hashtable_private.h b/hashtable_private.h
new file mode 100644
index 0000000..a81afca
--- /dev/null
+++ b/hashtable_private.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_PRIVATE_CWC22_H__
+#define __HASHTABLE_PRIVATE_CWC22_H__
+
+#include "hashtable.h"
+
+/*****************************************************************************/
+struct entry
+{
+ void *k, *v;
+ unsigned int h;
+ struct entry *next;
+};
+
+struct hashtable {
+ unsigned int tablelength;
+ struct entry **table;
+ unsigned int entrycount;
+ unsigned int loadlimit;
+ unsigned int primeindex;
+ unsigned int (*hashfn) (void *k);
+ int (*eqfn) (void *k1, void *k2);
+};
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k);
+
+/*****************************************************************************/
+/* indexFor */
+static inline unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue) {
+ return (hashvalue % tablelength);
+}
+
+/* Only works if tablelength == 2^N */
+/*static inline unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue)
+{
+ return (hashvalue & (tablelength - 1u));
+}
+*/
+
+/*****************************************************************************/
+#define freekey(X) free(X)
+/*define freekey(X) ; */
+
+
+/*****************************************************************************/
+
+#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/hashutil.c b/hashutil.c
new file mode 100644
index 0000000..ddbd0da
--- /dev/null
+++ b/hashutil.c
@@ -0,0 +1,310 @@
+// Copyright (C) 2009-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+#include "hashutil.h"
+#include "macroskip.h"
+#include "murmurhashneutral2.h"
+
+unsigned
+hash_from_string(void *str)
+{
+ return murmurhashneutral2(str, strlen((const char *)str), 0);
+}
+
+unsigned
+hash_from_int(int i)
+{
+ return murmurhashneutral2(&i, sizeof(int), 0);
+}
+
+int
+strings_equal(void *str1, void *str2)
+{
+ return str_eq((const char *)str1, (const char *)str2);
+}
+
+int
+file_hashes_equal(struct file_hash *fh1, struct file_hash *fh2)
+{
+ return memcmp(fh1->hash, fh2->hash, 16) == 0
+ && fh1->size == fh2->size;
+}
+
+// Search for the strings "__DATE__" and "__TIME__" in str.
+//
+// Returns a bitmask with HASH_SOURCE_CODE_FOUND_DATE and
+// HASH_SOURCE_CODE_FOUND_TIME set appropriately.
+int
+check_for_temporal_macros(const char *str, size_t len)
+{
+ int result = 0;
+
+ // We're using the Boyer-Moore-Horspool algorithm, which searches starting
+ // from the *end* of the needle. Our needles are 8 characters long, so i
+ // starts at 7.
+ size_t i = 7;
+
+ while (i < len) {
+ // Check whether the substring ending at str[i] has the form "__...E__". On
+ // the assumption that 'E' is less common in source than '_', we check
+ // str[i-2] first.
+ if (str[i - 2] == 'E' &&
+ str[i - 0] == '_' &&
+ str[i - 7] == '_' &&
+ str[i - 1] == '_' &&
+ str[i - 6] == '_') {
+ // Check the remaining characters to see if the substring is "__DATE__"
+ // or "__TIME__".
+ if (str[i - 5] == 'D' && str[i - 4] == 'A' &&
+ str[i - 3] == 'T') {
+ result |= HASH_SOURCE_CODE_FOUND_DATE;
+ } else if (str[i - 5] == 'T' && str[i - 4] == 'I' &&
+ str[i - 3] == 'M') {
+ result |= HASH_SOURCE_CODE_FOUND_TIME;
+ }
+ }
+
+ // macro_skip tells us how far we can skip forward upon seeing str[i] at
+ // the end of a substring.
+ i += macro_skip[(uint8_t)str[i]];
+ }
+
+ return result;
+}
+
+// Hash a string. Returns a bitmask of HASH_SOURCE_CODE_* results.
+int
+hash_source_code_string(
+ struct conf *conf, struct mdfour *hash, const char *str, size_t len,
+ const char *path)
+{
+ int result = HASH_SOURCE_CODE_OK;
+
+ // Check for __DATE__ and __TIME__ if the sloppiness configuration tells us
+ // we should.
+ if (!(conf->sloppiness & SLOPPY_TIME_MACROS)) {
+ result |= check_for_temporal_macros(str, len);
+ }
+
+ // Hash the source string.
+ hash_buffer(hash, str, len);
+
+ if (result & HASH_SOURCE_CODE_FOUND_DATE) {
+ // Make sure that the hash sum changes if the (potential) expansion of
+ // __DATE__ changes.
+ time_t t = time(NULL);
+ struct tm *now = localtime(&t);
+ cc_log("Found __DATE__ in %s", path);
+ hash_delimiter(hash, "date");
+ hash_buffer(hash, &now->tm_year, sizeof(now->tm_year));
+ hash_buffer(hash, &now->tm_mon, sizeof(now->tm_mon));
+ hash_buffer(hash, &now->tm_mday, sizeof(now->tm_mday));
+ }
+ if (result & HASH_SOURCE_CODE_FOUND_TIME) {
+ // We don't know for sure that the program actually uses the __TIME__
+ // macro, but we have to assume it anyway and hash the time stamp. However,
+ // that's not very useful since the chance that we get a cache hit later
+ // the same second should be quite slim... So, just signal back to the
+ // caller that __TIME__ has been found so that the direct mode can be
+ // disabled.
+ cc_log("Found __TIME__ in %s", path);
+ }
+
+ return result;
+}
+
+// Hash a file ignoring comments. Returns a bitmask of HASH_SOURCE_CODE_*
+// results.
+int
+hash_source_code_file(struct conf *conf, struct mdfour *hash, const char *path)
+{
+ if (is_precompiled_header(path)) {
+ if (hash_file(hash, path)) {
+ return HASH_SOURCE_CODE_OK;
+ } else {
+ return HASH_SOURCE_CODE_ERROR;
+ }
+ } else {
+ char *data;
+ size_t size;
+ if (!read_file(path, 0, &data, &size)) {
+ return HASH_SOURCE_CODE_ERROR;
+ }
+ int result = hash_source_code_string(conf, hash, data, size, path);
+ free(data);
+ return result;
+ }
+}
+
+bool
+hash_command_output(struct mdfour *hash, const char *command,
+ const char *compiler)
+{
+#ifdef _WIN32
+ // Trim leading space.
+ while (isspace(*command)) {
+ command++;
+ }
+
+ // Add "echo" command.
+ bool cmd;
+ if (str_startswith(command, "echo")) {
+ command = format("cmd.exe /c \"%s\"", command);
+ cmd = true;
+ } else if (str_startswith(command,
+ "%compiler%") && str_eq(compiler, "echo")) {
+ command = format("cmd.exe /c \"%s%s\"", compiler, command + 10);
+ cmd = true;
+ } else {
+ command = x_strdup(command);
+ cmd = false;
+ }
+#endif
+
+ struct args *args = args_init_from_string(command);
+ for (int i = 0; i < args->argc; i++) {
+ if (str_eq(args->argv[i], "%compiler%")) {
+ args_set(args, i, compiler);
+ }
+ }
+ cc_log_argv("Executing compiler check command ", args->argv);
+
+#ifdef _WIN32
+ PROCESS_INFORMATION pi;
+ memset(&pi, 0x00, sizeof(pi));
+ STARTUPINFO si;
+ memset(&si, 0x00, sizeof(si));
+
+ char *path = find_executable(args->argv[0], NULL);
+ if (!path) {
+ path = args->argv[0];
+ }
+ char *sh = win32getshell(path);
+ if (sh) {
+ path = sh;
+ }
+
+ si.cb = sizeof(STARTUPINFO);
+
+ HANDLE pipe_out[2];
+ SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+ CreatePipe(&pipe_out[0], &pipe_out[1], &sa, 0);
+ SetHandleInformation(pipe_out[0], HANDLE_FLAG_INHERIT, 0);
+ si.hStdOutput = pipe_out[1];
+ si.hStdError = pipe_out[1];
+ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ si.dwFlags = STARTF_USESTDHANDLES;
+
+ char *win32args;
+ if (!cmd) {
+ win32args = win32argvtos(sh, args->argv);
+ } else {
+ win32args = (char *)command; // quoted
+ }
+ BOOL ret =
+ CreateProcess(path, win32args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
+ CloseHandle(pipe_out[1]);
+ args_free(args);
+ free(win32args);
+ if (cmd) {
+ free((char *)command); // Original argument was replaced above.
+ }
+ if (ret == 0) {
+ stats_update(STATS_COMPCHECK);
+ return false;
+ }
+ int fd = _open_osfhandle((intptr_t) pipe_out[0], O_BINARY);
+ bool ok = hash_fd(hash, fd);
+ if (!ok) {
+ cc_log("Error hashing compiler check command output: %s", strerror(errno));
+ stats_update(STATS_COMPCHECK);
+ }
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ DWORD exitcode;
+ GetExitCodeProcess(pi.hProcess, &exitcode);
+ CloseHandle(pipe_out[0]);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ if (exitcode != 0) {
+ cc_log("Compiler check command returned %d", (int) exitcode);
+ stats_update(STATS_COMPCHECK);
+ return false;
+ }
+ return ok;
+#else
+ int pipefd[2];
+ if (pipe(pipefd) == -1) {
+ fatal("pipe failed");
+ }
+
+ pid_t pid = fork();
+ if (pid == -1) {
+ fatal("fork failed");
+ }
+
+ if (pid == 0) {
+ // Child.
+ close(pipefd[0]);
+ close(0);
+ dup2(pipefd[1], 1);
+ dup2(pipefd[1], 2);
+ _exit(execvp(args->argv[0], args->argv));
+ return false; // Never reached.
+ } else {
+ // Parent.
+ args_free(args);
+ close(pipefd[1]);
+ bool ok = hash_fd(hash, pipefd[0]);
+ if (!ok) {
+ cc_log("Error hashing compiler check command output: %s", strerror(errno));
+ stats_update(STATS_COMPCHECK);
+ }
+ close(pipefd[0]);
+
+ int status;
+ if (waitpid(pid, &status, 0) != pid) {
+ cc_log("waitpid failed");
+ return false;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ cc_log("Compiler check command returned %d", WEXITSTATUS(status));
+ stats_update(STATS_COMPCHECK);
+ return false;
+ }
+ return ok;
+ }
+#endif
+}
+
+bool
+hash_multicommand_output(struct mdfour *hash, const char *commands,
+ const char *compiler)
+{
+ char *command_string = x_strdup(commands);
+ char *p = command_string;
+ char *command;
+ char *saveptr = NULL;
+ bool ok = true;
+ while ((command = strtok_r(p, ";", &saveptr))) {
+ if (!hash_command_output(hash, command, compiler)) {
+ ok = false;
+ }
+ p = NULL;
+ }
+ free(command_string);
+ return ok;
+}
diff --git a/hashutil.h b/hashutil.h
new file mode 100644
index 0000000..ae9abf1
--- /dev/null
+++ b/hashutil.h
@@ -0,0 +1,35 @@
+#ifndef HASHUTIL_H
+#define HASHUTIL_H
+
+#include "conf.h"
+#include "mdfour.h"
+#include <inttypes.h>
+
+struct file_hash
+{
+ uint8_t hash[16];
+ uint32_t size;
+};
+
+unsigned hash_from_string(void *str);
+unsigned hash_from_int(int i);
+int strings_equal(void *str1, void *str2);
+int file_hashes_equal(struct file_hash *fh1, struct file_hash *fh2);
+
+#define HASH_SOURCE_CODE_OK 0
+#define HASH_SOURCE_CODE_ERROR 1
+#define HASH_SOURCE_CODE_FOUND_DATE 2
+#define HASH_SOURCE_CODE_FOUND_TIME 4
+
+int check_for_temporal_macros(const char *str, size_t len);
+int hash_source_code_string(
+ struct conf *conf, struct mdfour *hash, const char *str, size_t len,
+ const char *path);
+int hash_source_code_file(
+ struct conf *conf, struct mdfour *hash, const char *path);
+bool hash_command_output(struct mdfour *hash, const char *command,
+ const char *compiler);
+bool hash_multicommand_output(struct mdfour *hash, const char *command,
+ const char *compiler);
+
+#endif
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..ba5e22a
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/language.c b/language.c
new file mode 100644
index 0000000..8d4321d
--- /dev/null
+++ b/language.c
@@ -0,0 +1,178 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+
+// Supported file extensions and corresponding languages (as in parameter to
+// the -x option).
+static const struct {
+ const char *extension;
+ const char *language;
+} extensions[] = {
+ {".c", "c"},
+ {".C", "c++"},
+ {".cc", "c++"},
+ {".CC", "c++"},
+ {".cp", "c++"},
+ {".CP", "c++"},
+ {".cpp", "c++"},
+ {".CPP", "c++"},
+ {".cxx", "c++"},
+ {".CXX", "c++"},
+ {".c++", "c++"},
+ {".C++", "c++"},
+ {".m", "objective-c"},
+ {".M", "objective-c++"},
+ {".mm", "objective-c++"},
+ {".sx", "assembler-with-cpp"},
+ {".S", "assembler-with-cpp"},
+ // Preprocessed:
+ {".i", "cpp-output"},
+ {".ii", "c++-cpp-output"},
+ {".mi", "objective-c-cpp-output"},
+ {".mii", "objective-c++-cpp-output"},
+ {".s", "assembler"},
+ // Header file (for precompilation):
+ {".h", "c-header"},
+ {".H", "c++-header"},
+ {".h++", "c++-header"},
+ {".H++", "c++-header"},
+ {".hh", "c++-header"},
+ {".HH", "c++-header"},
+ {".hp", "c++-header"},
+ {".HP", "c++-header"},
+ {".hpp", "c++-header"},
+ {".HPP", "c++-header"},
+ {".hxx", "c++-header"},
+ {".HXX", "c++-header"},
+ {".tcc", "c++-header"},
+ {".TCC", "c++-header"},
+ {".cu", "cuda"},
+ {".ic", "cuda-output"},
+ // Fixed form Fortran without preprocessing:
+ {".f", "f77"},
+ {".for", "f77"},
+ {".ftn", "f77"},
+ // Fixed form Fortran with traditional preprocessing:
+ {".F", "f77-cpp-input"},
+ {".FOR", "f77-cpp-input"},
+ {".fpp", "f77-cpp-input"},
+ {".FPP", "f77-cpp-input"},
+ {".FTN", "f77-cpp-input"},
+ // Free form Fortran without preprocessing:
+#if 0 // Could generate modules, ignore for now!
+ {".f90", "f95"},
+ {".f95", "f95"},
+ {".f03", "f95"},
+ {".f08", "f95"},
+#endif
+ // Free form Fortran with traditional preprocessing:
+#if 0 // Could generate modules, ignore for now!
+ {".F90", "f95-cpp-input"},
+ {".F95", "f95-cpp-input"},
+ {".F03", "f95-cpp-input"},
+ {".F08", "f95-cpp-input"},
+#endif
+ {NULL, NULL}
+};
+
+// Supported languages and corresponding preprocessed languages.
+static const struct {
+ const char *language;
+ const char *p_language;
+} languages[] = {
+ {"c", "cpp-output"},
+ {"cpp-output", "cpp-output"},
+ {"c-header", "cpp-output"},
+ {"c++", "c++-cpp-output"},
+ {"c++-cpp-output", "c++-cpp-output"},
+ {"c++-header", "c++-cpp-output"},
+ {"objective-c", "objective-c-cpp-output"},
+ {"objective-c-header", "objective-c-cpp-output"},
+ {"objc-cpp-output", "objective-c-cpp-output"},
+ {"objective-c-cpp-output", "objective-c-cpp-output"},
+ {"objective-c++", "objective-c++-cpp-output"},
+ {"objc++-cpp-output", "objective-c++-cpp-output"},
+ {"objective-c++-header", "objective-c++-cpp-output"},
+ {"objective-c++-cpp-output", "objective-c++-cpp-output"},
+ {"cuda", "cuda-output"},
+ {"assembler-with-cpp", "assembler"},
+ {"assembler", "assembler"},
+ {"f77-cpp-input", "f77"},
+ {"f77", "f77"},
+#if 0 // Could generate module files, ignore for now!
+ {"f95-cpp-input", "f95"},
+ {"f95", "f95"},
+#endif
+ {NULL, NULL}
+};
+
+// Guess the language of a file based on its extension. Returns NULL if the
+// extension is unknown.
+const char *
+language_for_file(const char *fname)
+{
+ const char *p = get_extension(fname);
+ for (int i = 0; extensions[i].extension; i++) {
+ if (str_eq(p, extensions[i].extension)) {
+ return extensions[i].language;
+ }
+ }
+ return NULL;
+}
+
+// Return the preprocessed language for a given language, or NULL if unknown.
+const char *
+p_language_for_language(const char *language)
+{
+ if (!language) {
+ return NULL;
+ }
+ for (int i = 0; languages[i].language; ++i) {
+ if (str_eq(language, languages[i].language)) {
+ return languages[i].p_language;
+ }
+ }
+ return NULL;
+}
+
+// Return the default file extension (including dot) for a language, or NULL if
+// unknown.
+const char *
+extension_for_language(const char *language)
+{
+ if (!language) {
+ return NULL;
+ }
+ for (int i = 0; extensions[i].extension; i++) {
+ if (str_eq(language, extensions[i].language)) {
+ return extensions[i].extension;
+ }
+ }
+ return NULL;
+}
+
+bool
+language_is_supported(const char *language)
+{
+ return p_language_for_language(language) != NULL;
+}
+
+bool
+language_is_preprocessed(const char *language)
+{
+ return str_eq(language, p_language_for_language(language));
+}
diff --git a/language.h b/language.h
new file mode 100644
index 0000000..ebfb8bb
--- /dev/null
+++ b/language.h
@@ -0,0 +1,12 @@
+#ifndef CCACHE_LANGUAGE_H
+#define CCACHE_LANGUAGE_H
+
+#include <stdbool.h>
+
+const char *language_for_file(const char *fname);
+const char *p_language_for_language(const char *language);
+const char *extension_for_language(const char *language);
+bool language_is_supported(const char *language);
+bool language_is_preprocessed(const char *language);
+
+#endif // CCACHE_LANGUAGE_H
diff --git a/lockfile.c b/lockfile.c
new file mode 100644
index 0000000..ce3dcf4
--- /dev/null
+++ b/lockfile.c
@@ -0,0 +1,214 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+
+// This function acquires a lockfile for the given path. Returns true if the
+// lock was acquired, otherwise false. If the lock has been considered stale
+// for the number of microseconds specified by staleness_limit, the function
+// will (if possible) break the lock and then try to acquire it again. The
+// staleness limit should be reasonably larger than the longest time the lock
+// can be expected to be held, and the updates of the locked path should
+// probably be made with an atomic rename(2) to avoid corruption in the rare
+// case that the lock is broken by another process.
+bool
+lockfile_acquire(const char *path, unsigned staleness_limit)
+{
+ char *lockfile = format("%s.lock", path);
+ char *my_content = NULL;
+ char *content = NULL;
+ char *initial_content = NULL;
+ const char *hostname = get_hostname();
+ bool acquired = false;
+ unsigned to_sleep = 1000; // Microseconds.
+ unsigned slept = 0; // Microseconds.
+
+ while (true) {
+ free(my_content);
+ my_content = format("%s:%d:%d", hostname, (int)getpid(), (int)time(NULL));
+
+#ifdef _WIN32
+ int fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0666);
+ if (fd == -1) {
+ int saved_errno = errno;
+ cc_log("lockfile_acquire: open WRONLY %s: %s", lockfile, strerror(errno));
+ if (saved_errno == ENOENT) {
+ // Directory doesn't exist?
+ if (create_parent_dirs(lockfile) == 0) {
+ // OK. Retry.
+ continue;
+ }
+ }
+ if (saved_errno != EEXIST) {
+ // Directory doesn't exist or isn't writable?
+ goto out;
+ }
+ // Someone else has the lock.
+ fd = open(lockfile, O_RDONLY|O_BINARY);
+ if (fd == -1) {
+ if (errno == ENOENT) {
+ // The file was removed after the open() call above, so retry
+ // acquiring it.
+ continue;
+ } else {
+ cc_log("lockfile_acquire: open RDONLY %s: %s",
+ lockfile, strerror(errno));
+ goto out;
+ }
+ }
+ free(content);
+ const size_t bufsize = 1024;
+ content = x_malloc(bufsize);
+ int len = read(fd, content, bufsize - 1);
+ if (len == -1) {
+ cc_log("lockfile_acquire: read %s: %s", lockfile, strerror(errno));
+ close(fd);
+ goto out;
+ }
+ close(fd);
+ content[len] = '\0';
+ } else {
+ // We got the lock.
+ if (write(fd, my_content, strlen(my_content)) == -1) {
+ cc_log("lockfile_acquire: write %s: %s", lockfile, strerror(errno));
+ close(fd);
+ x_unlink(lockfile);
+ goto out;
+ }
+ close(fd);
+ acquired = true;
+ goto out;
+ }
+#else
+ if (symlink(my_content, lockfile) == 0) {
+ // We got the lock.
+ acquired = true;
+ goto out;
+ }
+ int saved_errno = errno;
+ cc_log("lockfile_acquire: symlink %s: %s", lockfile, strerror(saved_errno));
+ if (saved_errno == ENOENT) {
+ // Directory doesn't exist?
+ if (create_parent_dirs(lockfile) == 0) {
+ // OK. Retry.
+ continue;
+ }
+ }
+ if (saved_errno == EPERM) {
+ // The file system does not support symbolic links. We have no choice but
+ // to grant the lock anyway.
+ acquired = true;
+ goto out;
+ }
+ if (saved_errno != EEXIST) {
+ // Directory doesn't exist or isn't writable?
+ goto out;
+ }
+ free(content);
+ content = x_readlink(lockfile);
+ // cppcheck-suppress nullPointer - false positive
+ if (!content) {
+ if (errno == ENOENT) {
+ // The symlink was removed after the symlink() call above, so retry
+ // acquiring it.
+ continue;
+ } else {
+ cc_log("lockfile_acquire: readlink %s: %s", lockfile, strerror(errno));
+ goto out;
+ }
+ }
+#endif
+
+ if (str_eq(content, my_content)) {
+ // Lost NFS reply?
+ cc_log("lockfile_acquire: symlink %s failed but we got the lock anyway",
+ lockfile);
+ acquired = true;
+ goto out;
+ }
+ // A possible improvement here would be to check if the process holding the
+ // lock is still alive and break the lock early if it isn't.
+ cc_log("lockfile_acquire: lock info for %s: %s", lockfile, content);
+ if (!initial_content) {
+ initial_content = x_strdup(content);
+ }
+ if (slept > staleness_limit) {
+ if (str_eq(content, initial_content)) {
+ // The lock seems to be stale -- break it.
+ cc_log("lockfile_acquire: breaking %s", lockfile);
+ // Try to acquire path.lock.lock:
+ if (lockfile_acquire(lockfile, staleness_limit)) {
+ lockfile_release(path); // Remove path.lock
+ lockfile_release(lockfile); // Remove path.lock.lock
+ to_sleep = 1000;
+ slept = 0;
+ continue;
+ }
+ }
+ cc_log("lockfile_acquire: gave up acquiring %s", lockfile);
+ goto out;
+ }
+ cc_log("lockfile_acquire: failed to acquire %s; sleeping %u microseconds",
+ lockfile, to_sleep);
+ usleep(to_sleep);
+ slept += to_sleep;
+ to_sleep *= 2;
+ }
+
+out:
+ if (acquired) {
+ cc_log("Acquired lock %s", lockfile);
+ } else {
+ cc_log("Failed to acquire lock %s", lockfile);
+ }
+ free(lockfile);
+ free(my_content);
+ free(initial_content);
+ free(content);
+ return acquired;
+}
+
+// Release the lockfile for the given path. Assumes that we are the legitimate
+// owner.
+void
+lockfile_release(const char *path)
+{
+ char *lockfile = format("%s.lock", path);
+ cc_log("Releasing lock %s", lockfile);
+ tmp_unlink(lockfile);
+ free(lockfile);
+}
+
+#ifdef TEST_LOCKFILE
+int
+main(int argc, char **argv)
+{
+ extern char *cache_logfile;
+ cache_logfile = "/dev/stdout";
+ if (argc == 4) {
+ unsigned staleness_limit = atoi(argv[1]);
+ if (str_eq(argv[2], "acquire")) {
+ return lockfile_acquire(argv[3], staleness_limit) == 0;
+ } else if (str_eq(argv[2], "release")) {
+ lockfile_release(argv[3]);
+ return 0;
+ }
+ }
+ fprintf(stderr,
+ "Usage: testlockfile <staleness_limit> <acquire|release> <path>\n");
+ return 1;
+}
+#endif
diff --git a/m4/feature_macros.m4 b/m4/feature_macros.m4
new file mode 100644
index 0000000..0243e9f
--- /dev/null
+++ b/m4/feature_macros.m4
@@ -0,0 +1,147 @@
+dnl ===========================================================================
+dnl Feature macro stuff borrowed from Python's configure.in
+dnl
+dnl For license information, see
+dnl <http://www.python.org/download/releases/2.6.2/license/>.
+dnl ===========================================================================
+
+# The later defininition of _XOPEN_SOURCE disables certain features
+# on Linux, so we need _GNU_SOURCE to re-enable them (makedev, tm_zone).
+AC_DEFINE(_GNU_SOURCE, 1, [Define on Linux to activate all library features])
+
+# The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables
+# certain features on NetBSD, so we need _NETBSD_SOURCE to re-enable
+# them.
+AC_DEFINE(_NETBSD_SOURCE, 1, [Define on NetBSD to activate all library features])
+
+# The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables
+# certain features on FreeBSD, so we need __BSD_VISIBLE to re-enable
+# them.
+AC_DEFINE(__BSD_VISIBLE, 1, [Define on FreeBSD to activate all library features])
+
+# The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables
+# u_int on Irix 5.3. Defining _BSD_TYPES brings it back.
+AC_DEFINE(_BSD_TYPES, 1, [Define on Irix to enable u_int])
+
+# The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables
+# certain features on Mac OS X, so we need _DARWIN_C_SOURCE to re-enable
+# them.
+AC_DEFINE(_DARWIN_C_SOURCE, 1, [Define on Darwin to activate all library features])
+
+define_xopen_source=yes
+
+ac_sys_system=`uname -s`
+if test "$ac_sys_system" = "AIX" -o "$ac_sys_system" = "Monterey64" \
+ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then
+ ac_sys_release=`uname -v`
+else
+ ac_sys_release=`uname -r`
+fi
+
+# Some systems cannot stand _XOPEN_SOURCE being defined at all; they
+# disable features if it is defined, without any means to access these
+# features as extensions. For these systems, we skip the definition of
+# _XOPEN_SOURCE. Before adding a system to the list to gain access to
+# some feature, make sure there is no alternative way to access this
+# feature. Also, when using wildcards, make sure you have verified the
+# need for not defining _XOPEN_SOURCE on all systems matching the
+# wildcard, and that the wildcard does not include future systems
+# (which may remove their limitations).
+dnl quadrigraphs "@<:@" and "@:>@" produce "[" and "]" in the output
+case $ac_sys_system/$ac_sys_release in
+ # On OpenBSD, select(2) is not available if _XOPEN_SOURCE is defined,
+ # even though select is a POSIX function. Reported by J. Ribbens.
+ # Reconfirmed for OpenBSD 3.3 by Zachary Hamm, for 3.4 by Jason Ish.
+ OpenBSD/2.* | OpenBSD/3.@<:@0123456789@:>@ | OpenBSD/4.@<:@0123@:>@)
+ define_xopen_source=no
+ # OpenBSD undoes our definition of __BSD_VISIBLE if _XOPEN_SOURCE is
+ # also defined. This can be overridden by defining _BSD_SOURCE
+ # As this has a different meaning on Linux, only define it on OpenBSD
+ AC_DEFINE(_BSD_SOURCE, 1, [Define on OpenBSD to activate all library features])
+ ;;
+ # Defining _XOPEN_SOURCE on NetBSD version prior to the introduction of
+ # _NETBSD_SOURCE disables certain features (eg. setgroups). Reported by
+ # Marc Recht
+ NetBSD/1.5 | NetBSD/1.5.* | NetBSD/1.6 | NetBSD/1.6.* | NetBSD/1.6@<:@A-S@:>@)
+ define_xopen_source=no;;
+ # On Solaris 2.6, sys/wait.h is inconsistent in the usage
+ # of union __?sigval. Reported by Stuart Bishop.
+ SunOS/5.6)
+ define_xopen_source=no;;
+ # On UnixWare 7, u_long is never defined with _XOPEN_SOURCE,
+ # but used in /usr/include/netinet/tcp.h. Reported by Tim Rice.
+ # Reconfirmed for 7.1.4 by Martin v. Loewis.
+ OpenUNIX/8.0.0| UnixWare/7.1.@<:@0-4@:>@)
+ define_xopen_source=no;;
+ # On OpenServer 5, u_short is never defined with _XOPEN_SOURCE,
+ # but used in struct sockaddr.sa_family. Reported by Tim Rice.
+ SCO_SV/3.2)
+ define_xopen_source=no;;
+ # On FreeBSD 4, the math functions C89 does not cover are never defined
+ # with _XOPEN_SOURCE and __BSD_VISIBLE does not re-enable them.
+ FreeBSD/4.*)
+ define_xopen_source=no;;
+ # On MacOS X 10.2, a bug in ncurses.h means that it craps out if
+ # _XOPEN_EXTENDED_SOURCE is defined. Apparently, this is fixed in 10.3, which
+ # identifies itself as Darwin/7.*
+ # On Mac OS X 10.4, defining _POSIX_C_SOURCE or _XOPEN_SOURCE
+ # disables platform specific features beyond repair.
+ # On Mac OS X 10.3, defining _POSIX_C_SOURCE or _XOPEN_SOURCE
+ # has no effect, don't bother defining them
+ Darwin/@<:@6789@:>@.*)
+ define_xopen_source=no;;
+ # On AIX 4 and 5.1, mbstate_t is defined only when _XOPEN_SOURCE == 500 but
+ # used in wcsnrtombs() and mbsnrtowcs() even if _XOPEN_SOURCE is not defined
+ # or has another value. By not (re)defining it, the defaults come in place.
+ AIX/4)
+ define_xopen_source=no;;
+ AIX/5|AIX/7)
+ if test `uname -r` -eq 1; then
+ define_xopen_source=no
+ fi
+ ;;
+ # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
+ # defining NI_NUMERICHOST.
+ QNX/6.3.2)
+ define_xopen_source=no
+ ;;
+
+esac
+
+if test $define_xopen_source = yes
+then
+ # On Solaris w/ g++ it appears that _XOPEN_SOURCE has to be
+ # defined precisely as g++ defines it
+ # Furthermore, on Solaris 10, XPG6 requires the use of a C99
+ # compiler
+ case $ac_sys_system/$ac_sys_release in
+ SunOS/5.8|SunOS/5.9|SunOS/5.10)
+ AC_DEFINE(_XOPEN_SOURCE, 500,
+ Define to the level of X/Open that your system supports)
+ ;;
+ *)
+ AC_DEFINE(_XOPEN_SOURCE, 600,
+ Define to the level of X/Open that your system supports)
+ ;;
+ esac
+
+ # On Tru64 Unix 4.0F, defining _XOPEN_SOURCE also requires
+ # definition of _XOPEN_SOURCE_EXTENDED and _POSIX_C_SOURCE, or else
+ # several APIs are not declared. Since this is also needed in some
+ # cases for HP-UX, we define it globally.
+ # except for Solaris 10, where it must not be defined,
+ # as it implies XPG4.2
+ case $ac_sys_system/$ac_sys_release in
+ SunOS/5.10|SunOS/5.11)
+ AC_DEFINE(__EXTENSIONS__, 1,
+ Define to activate Unix95-and-earlier features)
+ ;;
+ *)
+ AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1,
+ Define to activate Unix95-and-earlier features)
+ ;;
+ esac
+
+ AC_DEFINE(_POSIX_C_SOURCE, 200112L, Define to activate features from IEEE Stds 1003.1-2001)
+
+fi
diff --git a/m4/snprintf.m4 b/m4/snprintf.m4
new file mode 100644
index 0000000..7d3aa06
--- /dev/null
+++ b/m4/snprintf.m4
@@ -0,0 +1,224 @@
+# $Id: snprintf.m4,v 1.1.1.1 2008/01/06 03:24:00 holger Exp $
+
+# Copyright (c) 2008 Holger Weiss <holger@jhweiss.de>.
+#
+# This code may freely be used, modified and/or redistributed for any purpose.
+# It would be nice if additions and fixes to this file (including trivial code
+# cleanups) would be sent back in order to let me include them in the version
+# available at <http://www.jhweiss.de/software/snprintf.html>. However, this is
+# not a requirement for using or redistributing (possibly modified) versions of
+# this file, nor is leaving this notice intact mandatory.
+
+# HW_HEADER_STDARG_H
+# ------------------
+# Define HAVE_STDARG_H to 1 if <stdarg.h> is available.
+AC_DEFUN([HW_HEADER_STDARG_H],
+[
+ AC_PREREQ([2.60])dnl Older releases should work if AC_CHECK_HEADERS is used.
+ AC_CHECK_HEADERS_ONCE([stdarg.h])
+])# HW_HEADER_STDARG_H
+
+# HW_HEADER_VARARGS_H
+# -------------------
+# Define HAVE_VARARGS_H to 1 if <varargs.h> is available.
+AC_DEFUN([HW_HEADER_VARARGS_H],
+[
+ AC_PREREQ([2.60])dnl Older releases should work if AC_CHECK_HEADERS is used.
+ AC_CHECK_HEADERS_ONCE([varargs.h])
+])# HW_HEADER_VARARGS_H
+
+# HW_FUNC_VA_COPY
+# ---------------
+# Set $hw_cv_func_va_copy to "yes" or "no". Define HAVE_VA_COPY to 1 if
+# $hw_cv_func_va_copy is set to "yes". Note that it's "unspecified whether
+# va_copy and va_end are macros or identifiers declared with external linkage."
+# (C99: 7.15.1, 1) Therefore, the presence of va_copy(3) cannot simply "be
+# tested with #ifdef", as suggested by the Autoconf manual (5.5.1).
+AC_DEFUN([HW_FUNC_VA_COPY],
+[
+ AC_REQUIRE([HW_HEADER_STDARG_H])dnl Our check evaluates HAVE_STDARG_H.
+ AC_REQUIRE([HW_HEADER_VARARGS_H])dnl Our check evaluates HAVE_VARARGS_H.
+ AC_CACHE_CHECK([for va_copy],
+ [hw_cv_func_va_copy],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#if HAVE_STDARG_H
+ #include <stdarg.h>
+ #elif HAVE_VARARGS_H
+ #include <varargs.h>
+ #endif]],
+ [[va_list ap, aq; va_copy(aq, ap);]])],
+ [hw_cv_func_va_copy=yes],
+ [hw_cv_func_va_copy=no],
+ [hw_cv_func_va_copy=no])])
+ AS_IF([test "$hw_cv_func_va_copy" = yes],
+ [AC_DEFINE([HAVE_VA_COPY], [1],
+ [Define to 1 if you have the `va_copy' function or macro.])])
+])# HW_FUNC_VA_COPY
+
+# HW_FUNC___VA_COPY
+# -----------------
+# Set $hw_cv_func___va_copy to "yes" or "no". Define HAVE___VA_COPY to 1 if
+# $hw_cv_func___va_copy is set to "yes".
+AC_DEFUN([HW_FUNC___VA_COPY],
+[
+ AC_REQUIRE([HW_HEADER_STDARG_H])dnl Our check evaluates HAVE_STDARG_H.
+ AC_REQUIRE([HW_HEADER_VARARGS_H])dnl Our check evaluates HAVE_VARARGS_H.
+ AC_CACHE_CHECK([for __va_copy],
+ [hw_cv_func___va_copy],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#if HAVE_STDARG_H
+ #include <stdarg.h>
+ #elif HAVE_VARARGS_H
+ #include <varargs.h>
+ #endif]],
+ [[va_list ap, aq; __va_copy(aq, ap);]])],
+ [hw_cv_func___va_copy=yes],
+ [hw_cv_func___va_copy=no],
+ [hw_cv_func___va_copy=no])])
+ AS_IF([test "$hw_cv_func___va_copy" = yes],
+ [AC_DEFINE([HAVE___VA_COPY], [1],
+ [Define to 1 if you have the `__va_copy' function or macro.])])
+])# HW_FUNC___VA_COPY
+
+# HW_FUNC_VSNPRINTF
+# -----------------
+# Set $hw_cv_func_vsnprintf and $hw_cv_func_vsnprintf_c99 to "yes" or "no",
+# respectively. Define HAVE_VSNPRINTF to 1 only if $hw_cv_func_vsnprintf_c99
+# is set to "yes". Otherwise, define vsnprintf to rpl_vsnprintf and make sure
+# the replacement function will be built.
+AC_DEFUN([HW_FUNC_VSNPRINTF],
+[
+ AC_PREREQ([2.60])dnl 2.59 should work if some AC_TYPE_* macros are replaced.
+ AC_REQUIRE([HW_HEADER_STDARG_H])dnl Our check evaluates HAVE_STDARG_H.
+ AC_CHECK_FUNC([vsnprintf],
+ [hw_cv_func_vsnprintf=yes],
+ [hw_cv_func_vsnprintf=no])
+ AS_IF([test "$hw_cv_func_vsnprintf" = yes],
+ [AC_CACHE_CHECK([whether vsnprintf is C99 compliant],
+ [hw_cv_func_vsnprintf_c99],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#if HAVE_STDARG_H
+ #include <stdarg.h>
+ #endif
+ #include <stdio.h>
+ static int testprintf(char *buf, size_t size, const char *format, ...)
+ {
+ int result;
+ va_list ap;
+ va_start(ap, format);
+ result = vsnprintf(buf, size, format, ap);
+ va_end(ap);
+ return result;
+ }]],
+ [[char buf[43];
+ if (testprintf(buf, 4, "The answer is %27.2g.", 42.0) != 42 ||
+ testprintf(buf, 0, "No, it's %32zu.", (size_t)42) != 42 ||
+ buf[0] != 'T' || buf[3] != '\0')
+ return 1;]])],
+ [hw_cv_func_vsnprintf_c99=yes],
+ [hw_cv_func_vsnprintf_c99=no],
+ [hw_cv_func_vsnprintf_c99=no])])],
+ [hw_cv_func_snprintf_c99=no])
+ AS_IF([test "$hw_cv_func_vsnprintf_c99" = yes],
+ [AC_DEFINE([HAVE_VSNPRINTF], [1],
+ [Define to 1 if you have a C99 compliant `vsnprintf' function.])],
+ [AC_CHECK_HEADERS([inttypes.h locale.h stddef.h stdint.h])
+ AC_CHECK_MEMBERS([struct lconv.decimal_point, struct lconv.thousands_sep],
+ [], [], [#include <locale.h>])
+dnl ccache doesn't link correctly on HP-UX 11.00 when support for long double
+dnl is enabled.
+dnl AC_TYPE_LONG_DOUBLE
+ AC_TYPE_LONG_LONG_INT
+ AC_TYPE_UNSIGNED_LONG_LONG_INT
+ AC_TYPE_SIZE_T
+ AC_TYPE_INTMAX_T
+ AC_TYPE_UINTMAX_T
+ AC_TYPE_UINTPTR_T
+ AC_CHECK_TYPES([ptrdiff_t])
+ AC_CHECK_FUNCS([localeconv])
+ _HW_FUNC_XPRINTF_REPLACE])
+])# HW_FUNC_VSNPRINTF
+
+# HW_FUNC_SNPRINTF
+# ----------------
+# Set $hw_cv_func_snprintf and $hw_cv_func_snprintf_c99 to "yes" or "no",
+# respectively. Define HAVE_SNPRINTF to 1 only if $hw_cv_func_snprintf_c99
+# is set to "yes". Otherwise, define snprintf to rpl_snprintf and make sure
+# the replacement function will be built.
+AC_DEFUN([HW_FUNC_SNPRINTF],
+[
+ AC_REQUIRE([HW_FUNC_VSNPRINTF])dnl Our snprintf(3) calls vsnprintf(3).
+ AC_CHECK_FUNC([snprintf],
+ [hw_cv_func_snprintf=yes],
+ [hw_cv_func_snprintf=no])
+ AS_IF([test "$hw_cv_func_snprintf" = yes],
+ [AC_CACHE_CHECK([whether snprintf is C99 compliant],
+ [hw_cv_func_snprintf_c99],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[#include <stdio.h>]],
+ [[char buf[43];
+ if (snprintf(buf, 4, "The answer is %27.2g.", 42.0) != 42 ||
+ snprintf(buf, 0, "No, it's %32zu.", (size_t)42) != 42 ||
+ buf[0] != 'T' || buf[3] != '\0')
+ return 1;]])],
+ [hw_cv_func_snprintf_c99=yes],
+ [hw_cv_func_snprintf_c99=no],
+ [hw_cv_func_snprintf_c99=no])])],
+ [hw_cv_func_snprintf_c99=no])
+ AS_IF([test "$hw_cv_func_snprintf_c99" = yes],
+ [AC_DEFINE([HAVE_SNPRINTF], [1],
+ [Define to 1 if you have a C99 compliant `snprintf' function.])],
+ [_HW_FUNC_XPRINTF_REPLACE])
+])# HW_FUNC_SNPRINTF
+
+# HW_FUNC_VASPRINTF
+# -----------------
+# Set $hw_cv_func_vasprintf to "yes" or "no". Define HAVE_VASPRINTF to 1 if
+# $hw_cv_func_vasprintf is set to "yes". Otherwise, define vasprintf to
+# rpl_vasprintf and make sure the replacement function will be built.
+AC_DEFUN([HW_FUNC_VASPRINTF],
+[
+ AC_REQUIRE([HW_FUNC_VSNPRINTF])dnl Our vasprintf(3) calls vsnprintf(3).
+ AC_CHECK_FUNCS([vasprintf],
+ [hw_cv_func_vasprintf=yes],
+ [hw_cv_func_vasprintf=no])
+ AS_IF([test "$hw_cv_func_vasprintf" = no],
+ [AC_CHECK_HEADERS([stdlib.h])
+ HW_FUNC_VA_COPY
+ AS_IF([test "$hw_cv_func_va_copy" = no],
+ [HW_FUNC___VA_COPY])
+ _HW_FUNC_XPRINTF_REPLACE])
+])# HW_FUNC_VASPRINTF
+
+# HW_FUNC_ASPRINTF
+# ----------------
+# Set $hw_cv_func_asprintf to "yes" or "no". Define HAVE_ASPRINTF to 1 if
+# $hw_cv_func_asprintf is set to "yes". Otherwise, define asprintf to
+# rpl_asprintf and make sure the replacement function will be built.
+AC_DEFUN([HW_FUNC_ASPRINTF],
+[
+ AC_REQUIRE([HW_FUNC_VASPRINTF])dnl Our asprintf(3) calls vasprintf(3).
+ AC_CHECK_FUNCS([asprintf],
+ [hw_cv_func_asprintf=yes],
+ [hw_cv_func_asprintf=no])
+ AS_IF([test "$hw_cv_func_asprintf" = no],
+ [_HW_FUNC_XPRINTF_REPLACE])
+])# HW_FUNC_ASPRINTF
+
+# _HW_FUNC_XPRINTF_REPLACE
+# ------------------------
+# Arrange for building snprintf.c. Must be called if one or more of the
+# functions provided by snprintf.c are needed.
+AC_DEFUN([_HW_FUNC_XPRINTF_REPLACE],
+[
+ AS_IF([test "x$_hw_cv_func_xprintf_replace_done" != xyes],
+ [AC_C_CONST
+ HW_HEADER_STDARG_H
+ AC_LIBOBJ([snprintf])
+ _hw_cv_func_xprintf_replace_done=yes])
+])# _HW_FUNC_XPRINTF_REPLACE
+
+dnl vim: set joinspaces textwidth=80:
diff --git a/macroskip.h b/macroskip.h
new file mode 100644
index 0000000..75243fe
--- /dev/null
+++ b/macroskip.h
@@ -0,0 +1,61 @@
+#ifndef CCACHE_MACROSKIP_H
+#define CCACHE_MACROSKIP_H
+
+#include <stdint.h>
+
+// A Boyer-Moore-Horspool skip table used for searching for the strings
+// "__TIME__" and "__DATE__".
+//
+// macro_skip[c] = 8 for all c not in "__TIME__" and "__DATE__".
+//
+// The other characters map as follows:
+//
+// _ -> 1
+// A -> 4
+// D -> 5
+// E -> 2
+// I -> 4
+// M -> 3
+// T -> 3
+//
+//
+// This was generated with the following Python script:
+//
+// m = {'_': 1,
+// 'A': 4,
+// 'D': 5,
+// 'E': 2,
+// 'I': 4,
+// 'M': 3,
+// 'T': 3}
+//
+// for i in range(0, 256):
+// if chr(i) in m:
+// num = m[chr(i)]
+// else:
+// num = 8
+// print ("%d, " % num),
+//
+// if i % 16 == 15:
+// print ""
+
+static const uint32_t macro_skip[] = {
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 4, 8, 8, 5, 2, 8, 8, 8, 4, 8, 8, 8, 3, 8, 8,
+ 8, 8, 8, 8, 3, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+#endif
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..dda0b2e
--- /dev/null
+++ b/main.c
@@ -0,0 +1,26 @@
+// ccache -- a fast C/C++ compiler cache
+//
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+int
+ccache_main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[])
+{
+ return ccache_main(argc, argv);
+}
diff --git a/manifest.c b/manifest.c
new file mode 100644
index 0000000..7c019e1
--- /dev/null
+++ b/manifest.c
@@ -0,0 +1,780 @@
+// Copyright (C) 2009-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+#include "hashtable_itr.h"
+#include "hashutil.h"
+#include "manifest.h"
+#include "murmurhashneutral2.h"
+
+#include <zlib.h>
+
+// Sketchy specification of the manifest disk format:
+//
+// <magic> magic number (4 bytes)
+// <version> file format version (1 byte unsigned int)
+// <hash_size> size of the hash fields (in bytes) (1 byte unsigned int)
+// <reserved> reserved for future use (2 bytes)
+// ----------------------------------------------------------------------------
+// <n> number of include file paths (4 bytes unsigned int)
+// <path_0> path to include file (NUL-terminated string,
+// ... at most 1024 bytes)
+// <path_n-1>
+// ----------------------------------------------------------------------------
+// <n> number of include file hash entries (4 bytes unsigned int)
+// <index[0]> index of include file path (4 bytes unsigned int)
+// <hash[0]> hash of include file (<hash_size> bytes)
+// <size[0]> size of include file (4 bytes unsigned int)
+// <mtime[0]> mtime of include file (8 bytes signed int)
+// <ctime[0]> ctime of include file (8 bytes signed int)
+// ...
+// <index[n-1]>
+// <hash[n-1]>
+// <size[n-1]>
+// <mtime[n-1]>
+// <ctime[n-1]>
+// ----------------------------------------------------------------------------
+// <n> number of object name entries (4 bytes unsigned int)
+// <m[0]> number of include file hash indexes (4 bytes unsigned int)
+// <index[0][0]> include file hash index (4 bytes unsigned int)
+// ...
+// <index[0][m[0]-1]>
+// <hash[0]> hash part of object name (<hash_size> bytes)
+// <size[0]> size part of object name (4 bytes unsigned int)
+// ...
+// <m[n-1]> number of include file hash indexes
+// <index[n-1][0]> include file hash index
+// ...
+// <index[n-1][m[n-1]]>
+// <hash[n-1]>
+// <size[n-1]>
+
+static const uint32_t MAGIC = 0x63436d46U;
+static const uint32_t MAX_MANIFEST_ENTRIES = 100;
+static const uint32_t MAX_MANIFEST_FILE_INFO_ENTRIES = 10000;
+
+#define ccache_static_assert(e) \
+ do { enum { ccache_static_assert__ = 1/(e) }; } while (false)
+
+struct file_info {
+ // Index to n_files.
+ uint32_t index;
+ // Hash of referenced file.
+ uint8_t hash[16];
+ // Size of referenced file.
+ uint32_t size;
+ // mtime of referenced file.
+ int64_t mtime;
+ // ctime of referenced file.
+ int64_t ctime;
+};
+
+struct object {
+ // Number of entries in file_info_indexes.
+ uint32_t n_file_info_indexes;
+ // Indexes to file_infos.
+ uint32_t *file_info_indexes;
+ // Hash of the object itself.
+ struct file_hash hash;
+};
+
+struct manifest {
+ // Version of decoded file.
+ uint8_t version;
+
+ // Reserved for future use.
+ uint16_t reserved;
+
+ // Size of hash fields (in bytes).
+ uint8_t hash_size;
+
+ // Referenced include files.
+ uint32_t n_files;
+ char **files;
+
+ // Information about referenced include files.
+ uint32_t n_file_infos;
+ struct file_info *file_infos;
+
+ // Object names plus references to include file hashes.
+ uint32_t n_objects;
+ struct object *objects;
+};
+
+struct file_stats {
+ uint32_t size;
+ int64_t mtime;
+ int64_t ctime;
+};
+
+static unsigned int
+hash_from_file_info(void *key)
+{
+ ccache_static_assert(sizeof(struct file_info) == 40); // No padding.
+ return murmurhashneutral2(key, sizeof(struct file_info), 0);
+}
+
+static int
+file_infos_equal(void *key1, void *key2)
+{
+ struct file_info *fi1 = (struct file_info *)key1;
+ struct file_info *fi2 = (struct file_info *)key2;
+ return fi1->index == fi2->index
+ && memcmp(fi1->hash, fi2->hash, 16) == 0
+ && fi1->size == fi2->size
+ && fi1->mtime == fi2->mtime
+ && fi1->ctime == fi2->ctime;
+}
+
+static void
+free_manifest(struct manifest *mf)
+{
+ for (uint32_t i = 0; i < mf->n_files; i++) {
+ free(mf->files[i]);
+ }
+ free(mf->files);
+ free(mf->file_infos);
+ for (uint32_t i = 0; i < mf->n_objects; i++) {
+ free(mf->objects[i].file_info_indexes);
+ }
+ free(mf->objects);
+ free(mf);
+}
+
+#define READ_BYTE(var) \
+ do { \
+ int ch_ = gzgetc(f); \
+ if (ch_ == EOF) { \
+ goto error; \
+ } \
+ (var) = ch_ & 0xFF; \
+ } while (false)
+
+#define READ_INT(size, var) \
+ do { \
+ uint64_t u_ = 0; \
+ for (size_t i_ = 0; i_ < (size); i_++) { \
+ int ch_ = gzgetc(f); \
+ if (ch_ == EOF) { \
+ goto error; \
+ } \
+ u_ <<= 8; \
+ u_ |= ch_ & 0xFF; \
+ } \
+ (var) = u_; \
+ } while (false)
+
+#define READ_STR(var) \
+ do { \
+ char buf_[1024]; \
+ size_t i_; \
+ for (i_ = 0; i_ < sizeof(buf_); i_++) { \
+ int ch_ = gzgetc(f); \
+ if (ch_ == EOF) { \
+ goto error; \
+ } \
+ buf_[i_] = ch_; \
+ if (ch_ == '\0') { \
+ break; \
+ } \
+ } \
+ if (i_ == sizeof(buf_)) { \
+ goto error; \
+ } \
+ (var) = x_strdup(buf_); \
+ } while (false)
+
+#define READ_BYTES(n, var) \
+ do { \
+ for (size_t i_ = 0; i_ < (n); i_++) { \
+ int ch_ = gzgetc(f); \
+ if (ch_ == EOF) { \
+ goto error; \
+ } \
+ (var)[i_] = ch_; \
+ } \
+ } while (false)
+
+static struct manifest *
+create_empty_manifest(void)
+{
+ struct manifest *mf = x_malloc(sizeof(*mf));
+ mf->hash_size = 16;
+ mf->n_files = 0;
+ mf->files = NULL;
+ mf->n_file_infos = 0;
+ mf->file_infos = NULL;
+ mf->n_objects = 0;
+ mf->objects = NULL;
+
+ return mf;
+}
+
+static struct manifest *
+read_manifest(gzFile f)
+{
+ struct manifest *mf = create_empty_manifest();
+
+ uint32_t magic;
+ READ_INT(4, magic);
+ if (magic != MAGIC) {
+ cc_log("Manifest file has bad magic number %u", magic);
+ goto error;
+ }
+
+ READ_BYTE(mf->version);
+ if (mf->version != MANIFEST_VERSION) {
+ cc_log("Manifest file has unknown version %u", mf->version);
+ goto error;
+ }
+
+ READ_BYTE(mf->hash_size);
+ if (mf->hash_size != 16) {
+ // Temporary measure until we support different hash algorithms.
+ cc_log("Manifest file has unsupported hash size %u", mf->hash_size);
+ goto error;
+ }
+
+ READ_INT(2, mf->reserved);
+
+ READ_INT(4, mf->n_files);
+ mf->files = x_calloc(mf->n_files, sizeof(*mf->files));
+ for (uint32_t i = 0; i < mf->n_files; i++) {
+ READ_STR(mf->files[i]);
+ }
+
+ READ_INT(4, mf->n_file_infos);
+ mf->file_infos = x_calloc(mf->n_file_infos, sizeof(*mf->file_infos));
+ for (uint32_t i = 0; i < mf->n_file_infos; i++) {
+ READ_INT(4, mf->file_infos[i].index);
+ READ_BYTES(mf->hash_size, mf->file_infos[i].hash);
+ READ_INT(4, mf->file_infos[i].size);
+ READ_INT(8, mf->file_infos[i].mtime);
+ READ_INT(8, mf->file_infos[i].ctime);
+ }
+
+ READ_INT(4, mf->n_objects);
+ mf->objects = x_calloc(mf->n_objects, sizeof(*mf->objects));
+ for (uint32_t i = 0; i < mf->n_objects; i++) {
+ READ_INT(4, mf->objects[i].n_file_info_indexes);
+ mf->objects[i].file_info_indexes =
+ x_calloc(mf->objects[i].n_file_info_indexes,
+ sizeof(*mf->objects[i].file_info_indexes));
+ for (uint32_t j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
+ READ_INT(4, mf->objects[i].file_info_indexes[j]);
+ }
+ READ_BYTES(mf->hash_size, mf->objects[i].hash.hash);
+ READ_INT(4, mf->objects[i].hash.size);
+ }
+
+ return mf;
+
+error:
+ cc_log("Corrupt manifest file");
+ free_manifest(mf);
+ return NULL;
+}
+
+#define WRITE_INT(size, var) \
+ do { \
+ uint64_t u_ = (var); \
+ uint8_t ch_; \
+ size_t i_; \
+ for (i_ = 0; i_ < (size); i_++) { \
+ ch_ = (u_ >> (8 * ((size) - i_ - 1))); \
+ if (gzputc(f, ch_) == EOF) { \
+ goto error; \
+ } \
+ } \
+ } while (false)
+
+#define WRITE_STR(var) \
+ do { \
+ if (gzputs(f, var) == EOF || gzputc(f, '\0') == EOF) { \
+ goto error; \
+ } \
+ } while (false)
+
+#define WRITE_BYTES(n, var) \
+ do { \
+ size_t i_; \
+ for (i_ = 0; i_ < (n); i_++) { \
+ if (gzputc(f, (var)[i_]) == EOF) { \
+ goto error; \
+ } \
+ } \
+ } while (false)
+
+static int
+write_manifest(gzFile f, const struct manifest *mf)
+{
+ WRITE_INT(4, MAGIC);
+ WRITE_INT(1, MANIFEST_VERSION);
+ WRITE_INT(1, 16);
+ WRITE_INT(2, 0);
+
+ WRITE_INT(4, mf->n_files);
+ for (uint32_t i = 0; i < mf->n_files; i++) {
+ WRITE_STR(mf->files[i]);
+ }
+
+ WRITE_INT(4, mf->n_file_infos);
+ for (uint32_t i = 0; i < mf->n_file_infos; i++) {
+ WRITE_INT(4, mf->file_infos[i].index);
+ WRITE_BYTES(mf->hash_size, mf->file_infos[i].hash);
+ WRITE_INT(4, mf->file_infos[i].size);
+ WRITE_INT(8, mf->file_infos[i].mtime);
+ WRITE_INT(8, mf->file_infos[i].ctime);
+ }
+
+ WRITE_INT(4, mf->n_objects);
+ for (uint32_t i = 0; i < mf->n_objects; i++) {
+ WRITE_INT(4, mf->objects[i].n_file_info_indexes);
+ for (uint32_t j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
+ WRITE_INT(4, mf->objects[i].file_info_indexes[j]);
+ }
+ WRITE_BYTES(mf->hash_size, mf->objects[i].hash.hash);
+ WRITE_INT(4, mf->objects[i].hash.size);
+ }
+
+ return 1;
+
+error:
+ cc_log("Error writing to manifest file");
+ return 0;
+}
+
+static int
+verify_object(struct conf *conf, struct manifest *mf, struct object *obj,
+ struct hashtable *stated_files, struct hashtable *hashed_files)
+{
+ for (uint32_t i = 0; i < obj->n_file_info_indexes; i++) {
+ struct file_info *fi = &mf->file_infos[obj->file_info_indexes[i]];
+ char *path = mf->files[fi->index];
+ struct file_stats *st = hashtable_search(stated_files, path);
+ if (!st) {
+ struct stat file_stat;
+ if (x_stat(path, &file_stat) != 0) {
+ return 0;
+ }
+ st = x_malloc(sizeof(*st));
+ st->size = file_stat.st_size;
+ st->mtime = file_stat.st_mtime;
+ st->ctime = file_stat.st_ctime;
+ hashtable_insert(stated_files, x_strdup(path), st);
+ }
+
+ if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) {
+ // st->ctime is sometimes 0, so we can't check that both st->ctime and
+ // st->mtime are greater than time_of_compilation. But it's sufficient to
+ // check that either is.
+ if (fi->size == st->size
+ && fi->mtime == st->mtime
+ && fi->ctime == st->ctime
+ && MAX(st->mtime, st->ctime) >= time_of_compilation) {
+ cc_log("size/mtime/ctime hit for %s", path);
+ continue;
+ } else {
+ cc_log("size/mtime/ctime miss for %s", path);
+ }
+ }
+
+ struct file_hash *actual = hashtable_search(hashed_files, path);
+ if (!actual) {
+ struct mdfour hash;
+ hash_start(&hash);
+ int result = hash_source_code_file(conf, &hash, path);
+ if (result & HASH_SOURCE_CODE_ERROR) {
+ cc_log("Failed hashing %s", path);
+ return 0;
+ }
+ if (result & HASH_SOURCE_CODE_FOUND_TIME) {
+ return 0;
+ }
+ actual = x_malloc(sizeof(*actual));
+ hash_result_as_bytes(&hash, actual->hash);
+ actual->size = hash.totalN;
+ hashtable_insert(hashed_files, x_strdup(path), actual);
+ }
+ if (memcmp(fi->hash, actual->hash, mf->hash_size) != 0
+ || fi->size != actual->size) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static struct hashtable *
+create_string_index_map(char **strings, uint32_t len)
+{
+ struct hashtable *h =
+ create_hashtable(1000, hash_from_string, strings_equal);
+ for (uint32_t i = 0; i < len; i++) {
+ uint32_t *index = x_malloc(sizeof(*index));
+ *index = i;
+ hashtable_insert(h, x_strdup(strings[i]), index);
+ }
+ return h;
+}
+
+static struct hashtable *
+create_file_info_index_map(struct file_info *infos, uint32_t len)
+{
+ struct hashtable *h =
+ create_hashtable(1000, hash_from_file_info, file_infos_equal);
+ for (uint32_t i = 0; i < len; i++) {
+ struct file_info *fi = x_malloc(sizeof(*fi));
+ *fi = infos[i];
+ uint32_t *index = x_malloc(sizeof(*index));
+ *index = i;
+ hashtable_insert(h, fi, index);
+ }
+ return h;
+}
+
+static uint32_t
+get_include_file_index(struct manifest *mf, char *path,
+ struct hashtable *mf_files)
+{
+ uint32_t *index = hashtable_search(mf_files, path);
+ if (index) {
+ return *index;
+ }
+
+ uint32_t n = mf->n_files;
+ mf->files = x_realloc(mf->files, (n + 1) * sizeof(*mf->files));
+ mf->n_files++;
+ mf->files[n] = x_strdup(path);
+ return n;
+}
+
+static uint32_t
+get_file_hash_index(struct manifest *mf,
+ char *path,
+ struct file_hash *file_hash,
+ struct hashtable *mf_files,
+ struct hashtable *mf_file_infos)
+{
+ struct file_info fi;
+ fi.index = get_include_file_index(mf, path, mf_files);
+ memcpy(fi.hash, file_hash->hash, sizeof(fi.hash));
+ fi.size = file_hash->size;
+
+ // file_stat.st_{m,c}time has a resolution of 1 second, so we can cache the
+ // file's mtime and ctime only if they're at least one second older than
+ // time_of_compilation.
+ //
+ // st->ctime may be 0, so we have to check time_of_compilation against
+ // MAX(mtime, ctime).
+
+ struct stat file_stat;
+ if (stat(path, &file_stat) != -1
+ && time_of_compilation > MAX(file_stat.st_mtime, file_stat.st_ctime)) {
+ fi.mtime = file_stat.st_mtime;
+ fi.ctime = file_stat.st_ctime;
+ } else {
+ fi.mtime = -1;
+ fi.ctime = -1;
+ }
+
+ uint32_t *fi_index = hashtable_search(mf_file_infos, &fi);
+ if (fi_index) {
+ return *fi_index;
+ }
+
+ uint32_t n = mf->n_file_infos;
+ mf->file_infos = x_realloc(mf->file_infos, (n + 1) * sizeof(*mf->file_infos));
+ mf->n_file_infos++;
+ mf->file_infos[n] = fi;
+ return n;
+}
+
+static void
+add_file_info_indexes(uint32_t *indexes, uint32_t size,
+ struct manifest *mf, struct hashtable *included_files)
+{
+ if (size == 0) {
+ return;
+ }
+
+ // path --> index
+ struct hashtable *mf_files =
+ create_string_index_map(mf->files, mf->n_files);
+ // struct file_info --> index
+ struct hashtable *mf_file_infos =
+ create_file_info_index_map(mf->file_infos, mf->n_file_infos);
+ struct hashtable_itr *iter = hashtable_iterator(included_files);
+ uint32_t i = 0;
+ do {
+ char *path = hashtable_iterator_key(iter);
+ struct file_hash *file_hash = hashtable_iterator_value(iter);
+ indexes[i] = get_file_hash_index(mf, path, file_hash, mf_files,
+ mf_file_infos);
+ i++;
+ } while (hashtable_iterator_advance(iter));
+ assert(i == size);
+
+ hashtable_destroy(mf_file_infos, 1);
+ hashtable_destroy(mf_files, 1);
+}
+
+static void
+add_object_entry(struct manifest *mf,
+ struct file_hash *object_hash,
+ struct hashtable *included_files)
+{
+ uint32_t n_objs = mf->n_objects;
+ mf->objects = x_realloc(mf->objects, (n_objs + 1) * sizeof(*mf->objects));
+ mf->n_objects++;
+ struct object *obj = &mf->objects[n_objs];
+
+ uint32_t n_fii = hashtable_count(included_files);
+ obj->n_file_info_indexes = n_fii;
+ obj->file_info_indexes = x_malloc(n_fii * sizeof(*obj->file_info_indexes));
+ add_file_info_indexes(obj->file_info_indexes, n_fii, mf, included_files);
+ memcpy(obj->hash.hash, object_hash->hash, mf->hash_size);
+ obj->hash.size = object_hash->size;
+}
+
+// Try to get the object hash from a manifest file. Caller frees. Returns NULL
+// on failure.
+struct file_hash *
+manifest_get(struct conf *conf, const char *manifest_path)
+{
+ gzFile f = NULL;
+ struct manifest *mf = NULL;
+ struct hashtable *hashed_files = NULL; // path --> struct file_hash
+ struct hashtable *stated_files = NULL; // path --> struct file_stats
+ struct file_hash *fh = NULL;
+
+ int fd = open(manifest_path, O_RDONLY | O_BINARY);
+ if (fd == -1) {
+ // Cache miss.
+ cc_log("No such manifest file");
+ goto out;
+ }
+ f = gzdopen(fd, "rb");
+ if (!f) {
+ close(fd);
+ cc_log("Failed to gzdopen manifest file");
+ goto out;
+ }
+ mf = read_manifest(f);
+ if (!mf) {
+ cc_log("Error reading manifest file");
+ goto out;
+ }
+
+ hashed_files = create_hashtable(1000, hash_from_string, strings_equal);
+ stated_files = create_hashtable(1000, hash_from_string, strings_equal);
+
+ // Check newest object first since it's a bit more likely to match.
+ for (uint32_t i = mf->n_objects; i > 0; i--) {
+ if (verify_object(conf, mf, &mf->objects[i - 1],
+ stated_files, hashed_files)) {
+ fh = x_malloc(sizeof(*fh));
+ *fh = mf->objects[i - 1].hash;
+ goto out;
+ }
+ }
+
+out:
+ if (hashed_files) {
+ hashtable_destroy(hashed_files, 1);
+ }
+ if (stated_files) {
+ hashtable_destroy(stated_files, 1);
+ }
+ if (f) {
+ gzclose(f);
+ }
+ if (mf) {
+ free_manifest(mf);
+ }
+ return fh;
+}
+
+// Put the object name into a manifest file given a set of included files.
+// Returns true on success, otherwise false.
+bool
+manifest_put(const char *manifest_path, struct file_hash *object_hash,
+ struct hashtable *included_files)
+{
+ int ret = 0;
+ gzFile f2 = NULL;
+ struct manifest *mf = NULL;
+ char *tmp_file = NULL;
+
+ // We don't bother to acquire a lock when writing the manifest to disk. A
+ // race between two processes will only result in one lost entry, which is
+ // not a big deal, and it's also very unlikely.
+
+ int fd1 = open(manifest_path, O_RDONLY | O_BINARY);
+ if (fd1 == -1) {
+ // New file.
+ mf = create_empty_manifest();
+ } else {
+ gzFile f1 = gzdopen(fd1, "rb");
+ if (!f1) {
+ cc_log("Failed to gzdopen manifest file");
+ close(fd1);
+ goto out;
+ }
+ mf = read_manifest(f1);
+ gzclose(f1);
+ if (!mf) {
+ cc_log("Failed to read manifest file; deleting it");
+ x_unlink(manifest_path);
+ mf = create_empty_manifest();
+ }
+ }
+
+ if (mf->n_objects > MAX_MANIFEST_ENTRIES) {
+ // Normally, there shouldn't be many object entries in the manifest since
+ // new entries are added only if an include file has changed but not the
+ // source file, and you typically change source files more often than
+ // header files. However, it's certainly possible to imagine cases where
+ // the manifest will grow large (for instance, a generated header file that
+ // changes for every build), and this must be taken care of since
+ // processing an ever growing manifest eventually will take too much time.
+ // A good way of solving this would be to maintain the object entries in
+ // LRU order and discarding the old ones. An easy way is to throw away all
+ // entries when there are too many. Let's do that for now.
+ cc_log("More than %u entries in manifest file; discarding",
+ MAX_MANIFEST_ENTRIES);
+ free_manifest(mf);
+ mf = create_empty_manifest();
+ } else if (mf->n_file_infos > MAX_MANIFEST_FILE_INFO_ENTRIES) {
+ // Rarely, file_info entries can grow large in pathological cases where
+ // many included files change, but the main file does not. This also puts
+ // an upper bound on the number of file_info entries.
+ cc_log("More than %u file_info entries in manifest file; discarding",
+ MAX_MANIFEST_FILE_INFO_ENTRIES);
+ free_manifest(mf);
+ mf = create_empty_manifest();
+ }
+
+ tmp_file = format("%s.tmp", manifest_path);
+ int fd2 = create_tmp_fd(&tmp_file);
+ f2 = gzdopen(fd2, "wb");
+ if (!f2) {
+ cc_log("Failed to gzdopen %s", tmp_file);
+ goto out;
+ }
+
+ add_object_entry(mf, object_hash, included_files);
+ if (write_manifest(f2, mf)) {
+ gzclose(f2);
+ f2 = NULL;
+ if (x_rename(tmp_file, manifest_path) == 0) {
+ ret = 1;
+ } else {
+ cc_log("Failed to rename %s to %s", tmp_file, manifest_path);
+ goto out;
+ }
+ } else {
+ cc_log("Failed to write manifest file");
+ goto out;
+ }
+
+out:
+ if (mf) {
+ free_manifest(mf);
+ }
+ if (tmp_file) {
+ free(tmp_file);
+ }
+ if (f2) {
+ gzclose(f2);
+ }
+ return ret;
+}
+
+bool
+manifest_dump(const char *manifest_path, FILE *stream)
+{
+ struct manifest *mf = NULL;
+ gzFile f = NULL;
+ bool ret = false;
+
+ int fd = open(manifest_path, O_RDONLY | O_BINARY);
+ if (fd == -1) {
+ fprintf(stderr, "No such manifest file: %s\n", manifest_path);
+ goto out;
+ }
+ f = gzdopen(fd, "rb");
+ if (!f) {
+ fprintf(stderr, "Failed to dzopen manifest file\n");
+ close(fd);
+ goto out;
+ }
+ mf = read_manifest(f);
+ if (!mf) {
+ fprintf(stderr, "Error reading manifest file\n");
+ goto out;
+ }
+
+ fprintf(stream, "Magic: %c%c%c%c\n",
+ (MAGIC >> 24) & 0xFF,
+ (MAGIC >> 16) & 0xFF,
+ (MAGIC >> 8) & 0xFF,
+ MAGIC & 0xFF);
+ fprintf(stream, "Version: %u\n", mf->version);
+ fprintf(stream, "Hash size: %u\n", (unsigned)mf->hash_size);
+ fprintf(stream, "Reserved field: %u\n", (unsigned)mf->reserved);
+ fprintf(stream, "File paths (%u):\n", (unsigned)mf->n_files);
+ for (unsigned i = 0; i < mf->n_files; ++i) {
+ fprintf(stream, " %u: %s\n", i, mf->files[i]);
+ }
+ fprintf(stream, "File infos (%u):\n", (unsigned)mf->n_file_infos);
+ for (unsigned i = 0; i < mf->n_file_infos; ++i) {
+ char *hash;
+ fprintf(stream, " %u:\n", i);
+ fprintf(stream, " Path index: %u\n", mf->file_infos[i].index);
+ hash = format_hash_as_string(mf->file_infos[i].hash, -1);
+ fprintf(stream, " Hash: %s\n", hash);
+ free(hash);
+ fprintf(stream, " Size: %u\n", mf->file_infos[i].size);
+ fprintf(stream, " Mtime: %lld\n", (long long)mf->file_infos[i].mtime);
+ fprintf(stream, " Ctime: %lld\n", (long long)mf->file_infos[i].ctime);
+ }
+ fprintf(stream, "Results (%u):\n", (unsigned)mf->n_objects);
+ for (unsigned i = 0; i < mf->n_objects; ++i) {
+ char *hash;
+ fprintf(stream, " %u:\n", i);
+ fprintf(stream, " File info indexes:");
+ for (unsigned j = 0; j < mf->objects[i].n_file_info_indexes; ++j) {
+ fprintf(stream, " %u", mf->objects[i].file_info_indexes[j]);
+ }
+ fprintf(stream, "\n");
+ hash = format_hash_as_string(mf->objects[i].hash.hash, -1);
+ fprintf(stream, " Hash: %s\n", hash);
+ free(hash);
+ fprintf(stream, " Size: %u\n", (unsigned)mf->objects[i].hash.size);
+ }
+
+ ret = true;
+
+out:
+ if (mf) {
+ free_manifest(mf);
+ }
+ if (f) {
+ gzclose(f);
+ }
+ return ret;
+}
diff --git a/manifest.h b/manifest.h
new file mode 100644
index 0000000..e116c34
--- /dev/null
+++ b/manifest.h
@@ -0,0 +1,15 @@
+#ifndef MANIFEST_H
+#define MANIFEST_H
+
+#include "conf.h"
+#include "hashutil.h"
+#include "hashtable.h"
+
+#define MANIFEST_VERSION 1
+
+struct file_hash *manifest_get(struct conf *conf, const char *manifest_path);
+bool manifest_put(const char *manifest_path, struct file_hash *object_hash,
+ struct hashtable *included_files);
+bool manifest_dump(const char *manifest_path, FILE *stream);
+
+#endif
diff --git a/mdfour.c b/mdfour.c
new file mode 100644
index 0000000..36b55fe
--- /dev/null
+++ b/mdfour.c
@@ -0,0 +1,221 @@
+// Copyright (C) 1997-1998 Andrew Tridgell
+// Copyright (C) 2009-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+
+// NOTE: This code makes no attempt to be fast!
+
+static struct mdfour *m;
+
+#define MASK32 (0xffffffff)
+
+#define F(X, Y, Z) ((((X)&(Y)) | ((~(X))&(Z))))
+#define G(X, Y, Z) ((((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))))
+#define H(X, Y, Z) (((X)^(Y)^(Z)))
+#define lshift(x, s) (((((x)<<(s))&MASK32) | (((x)>>(32-(s)))&MASK32)))
+
+#define ROUND1(a, b, c, d, k, s) \
+ a = lshift((a + F(b, c, d) + M[k])&MASK32, s)
+#define ROUND2(a, b, c, d, k, s) \
+ a = lshift((a + G(b, c, d) + M[k] + 0x5A827999)&MASK32, s)
+#define ROUND3(a, b, c, d, k, s) \
+ a = lshift((a + H(b, c, d) + M[k] + 0x6ED9EBA1)&MASK32, s)
+
+// This applies md4 to 64 byte chunks.
+static void
+mdfour64(uint32_t *M)
+{
+ uint32_t AA, BB, CC, DD;
+ uint32_t A, B, C, D;
+
+ A = m->A;
+ B = m->B;
+ C = m->C;
+ D = m->D;
+ AA = A;
+ BB = B;
+ CC = C;
+ DD = D;
+
+ ROUND1(A, B, C, D, 0, 3); ROUND1(D, A, B, C, 1, 7);
+ ROUND1(C, D, A, B, 2, 11); ROUND1(B, C, D, A, 3, 19);
+ ROUND1(A, B, C, D, 4, 3); ROUND1(D, A, B, C, 5, 7);
+ ROUND1(C, D, A, B, 6, 11); ROUND1(B, C, D, A, 7, 19);
+ ROUND1(A, B, C, D, 8, 3); ROUND1(D, A, B, C, 9, 7);
+ ROUND1(C, D, A, B, 10, 11); ROUND1(B, C, D, A, 11, 19);
+ ROUND1(A, B, C, D, 12, 3); ROUND1(D, A, B, C, 13, 7);
+ ROUND1(C, D, A, B, 14, 11); ROUND1(B, C, D, A, 15, 19);
+
+
+ ROUND2(A, B, C, D, 0, 3); ROUND2(D, A, B, C, 4, 5);
+ ROUND2(C, D, A, B, 8, 9); ROUND2(B, C, D, A, 12, 13);
+ ROUND2(A, B, C, D, 1, 3); ROUND2(D, A, B, C, 5, 5);
+ ROUND2(C, D, A, B, 9, 9); ROUND2(B, C, D, A, 13, 13);
+ ROUND2(A, B, C, D, 2, 3); ROUND2(D, A, B, C, 6, 5);
+ ROUND2(C, D, A, B, 10, 9); ROUND2(B, C, D, A, 14, 13);
+ ROUND2(A, B, C, D, 3, 3); ROUND2(D, A, B, C, 7, 5);
+ ROUND2(C, D, A, B, 11, 9); ROUND2(B, C, D, A, 15, 13);
+
+ ROUND3(A, B, C, D, 0, 3); ROUND3(D, A, B, C, 8, 9);
+ ROUND3(C, D, A, B, 4, 11); ROUND3(B, C, D, A, 12, 15);
+ ROUND3(A, B, C, D, 2, 3); ROUND3(D, A, B, C, 10, 9);
+ ROUND3(C, D, A, B, 6, 11); ROUND3(B, C, D, A, 14, 15);
+ ROUND3(A, B, C, D, 1, 3); ROUND3(D, A, B, C, 9, 9);
+ ROUND3(C, D, A, B, 5, 11); ROUND3(B, C, D, A, 13, 15);
+ ROUND3(A, B, C, D, 3, 3); ROUND3(D, A, B, C, 11, 9);
+ ROUND3(C, D, A, B, 7, 11); ROUND3(B, C, D, A, 15, 15);
+
+ A += AA;
+ B += BB;
+ C += CC;
+ D += DD;
+
+ A &= MASK32;
+ B &= MASK32;
+ C &= MASK32;
+ D &= MASK32;
+
+ m->A = A;
+ m->B = B;
+ m->C = C;
+ m->D = D;
+}
+
+static void
+copy64(uint32_t *M, const unsigned char *in)
+{
+#ifdef WORDS_BIGENDIAN
+ for (int i = 0; i < 16; i++) {
+ M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
+ (in[i*4+1]<<8) | (in[i*4+0]<<0);
+ }
+#else
+ memcpy(M, in, 16*4);
+#endif
+}
+
+static void
+copy4(unsigned char *out, uint32_t x)
+{
+#ifdef WORDS_BIGENDIAN
+ out[0] = x&0xFF;
+ out[1] = (x>>8)&0xFF;
+ out[2] = (x>>16)&0xFF;
+ out[3] = (x>>24)&0xFF;
+#else
+ memcpy(out, &x, 4);
+#endif
+}
+
+void
+mdfour_begin(struct mdfour *md)
+{
+ md->A = 0x67452301;
+ md->B = 0xefcdab89;
+ md->C = 0x98badcfe;
+ md->D = 0x10325476;
+ md->totalN = 0;
+ md->tail_len = 0;
+ md->finalized = 0;
+}
+
+static
+void mdfour_tail(const unsigned char *in, size_t n)
+{
+ m->totalN += n;
+ uint32_t b = m->totalN * 8;
+ unsigned char buf[128] = { 0 };
+ uint32_t M[16];
+ if (n) {
+ memcpy(buf, in, n);
+ }
+ buf[n] = 0x80;
+
+ if (n <= 55) {
+ copy4(buf+56, b);
+ copy64(M, buf);
+ mdfour64(M);
+ } else {
+ copy4(buf+120, b);
+ copy64(M, buf);
+ mdfour64(M);
+ copy64(M, buf+64);
+ mdfour64(M);
+ }
+}
+
+void
+mdfour_update(struct mdfour *md, const unsigned char *in, size_t n)
+{
+#ifdef CCACHE_DEBUG_HASH
+ if (getenv("CCACHE_DEBUG_HASH")) {
+ FILE *f = fopen("ccache-debug-hash.bin", "a");
+ fwrite(in, 1, n, f);
+ fclose(f);
+ }
+#endif
+
+ m = md;
+
+ if (!in) {
+ if (!md->finalized) {
+ mdfour_tail(md->tail, md->tail_len);
+ md->finalized = 1;
+ }
+ return;
+ }
+
+ uint32_t M[16];
+ if (md->tail_len) {
+ size_t len = 64 - md->tail_len;
+ if (len > n) {
+ len = n;
+ }
+ memcpy(md->tail+md->tail_len, in, len);
+ md->tail_len += len;
+ n -= len;
+ in += len;
+ if (md->tail_len == 64) {
+ copy64(M, md->tail);
+ mdfour64(M);
+ m->totalN += 64;
+ md->tail_len = 0;
+ }
+ }
+
+ while (n >= 64) {
+ copy64(M, in);
+ mdfour64(M);
+ in += 64;
+ n -= 64;
+ m->totalN += 64;
+ }
+
+ if (n) {
+ memcpy(md->tail, in, n);
+ md->tail_len = n;
+ }
+}
+
+void
+mdfour_result(struct mdfour *md, unsigned char *out)
+{
+ copy4(out, md->A);
+ copy4(out+4, md->B);
+ copy4(out+8, md->C);
+ copy4(out+12, md->D);
+}
diff --git a/mdfour.h b/mdfour.h
new file mode 100644
index 0000000..c196a09
--- /dev/null
+++ b/mdfour.h
@@ -0,0 +1,19 @@
+#ifndef MDFOUR_H
+#define MDFOUR_H
+
+#include <stddef.h>
+#include <inttypes.h>
+
+struct mdfour {
+ uint32_t A, B, C, D;
+ size_t totalN;
+ unsigned char tail[64];
+ size_t tail_len;
+ int finalized;
+};
+
+void mdfour_begin(struct mdfour *md);
+void mdfour_update(struct mdfour *md, const unsigned char *in, size_t n);
+void mdfour_result(struct mdfour *md, unsigned char *out);
+
+#endif
diff --git a/murmurhashneutral2.c b/murmurhashneutral2.c
new file mode 100644
index 0000000..53319df
--- /dev/null
+++ b/murmurhashneutral2.c
@@ -0,0 +1,44 @@
+// MurmurHashNeutral2, by Austin Appleby. Released to the public domain. See
+// <http://murmurhash.googlepages.com>.
+
+#include "murmurhashneutral2.h"
+
+unsigned int
+murmurhashneutral2(const void *key, int len, unsigned int seed)
+{
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+ unsigned int h = seed ^ len;
+ const unsigned char *data = (const unsigned char *)key;
+
+ while (len >= 4) {
+ unsigned int k = data[0];
+ k |= ((unsigned int) data[1]) << 8;
+ k |= ((unsigned int) data[2]) << 16;
+ k |= ((unsigned int) data[3]) << 24;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ switch (len)
+ {
+ case 3: h ^= ((unsigned int) data[2]) << 16;
+ case 2: h ^= ((unsigned int) data[1]) << 8;
+ case 1: h ^= ((unsigned int) data[0]);
+ h *= m;
+ };
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
diff --git a/murmurhashneutral2.h b/murmurhashneutral2.h
new file mode 100644
index 0000000..fe056fd
--- /dev/null
+++ b/murmurhashneutral2.h
@@ -0,0 +1,6 @@
+#ifndef MURMURHASHNEUTRAL2_H
+#define MURMURHASHNEUTRAL2_H
+
+unsigned int murmurhashneutral2(const void *key, int len, unsigned int seed);
+
+#endif
diff --git a/snprintf.c b/snprintf.c
new file mode 100644
index 0000000..b935ee9
--- /dev/null
+++ b/snprintf.c
@@ -0,0 +1,2116 @@
+/* $Id: snprintf.c,v 1.9 2008/01/20 14:02:00 holger Exp $ */
+
+/*
+ * Copyright (c) 1995 Patrick Powell.
+ *
+ * This code is based on code written by Patrick Powell <papowell@astart.com>.
+ * It may be used for any purpose as long as this notice remains intact on all
+ * source code distributions.
+ */
+
+/*
+ * Copyright (c) 2008 Holger Weiss.
+ *
+ * This version of the code is maintained by Holger Weiss <holger@jhweiss.de>.
+ * My changes to the code may freely be used, modified and/or redistributed for
+ * any purpose. It would be nice if additions and fixes to this file (including
+ * trivial code cleanups) would be sent back in order to let me include them in
+ * the version available at <http://www.jhweiss.de/software/snprintf.html>.
+ * However, this is not a requirement for using or redistributing (possibly
+ * modified) versions of this file, nor is leaving this notice intact mandatory.
+ */
+
+/*
+ * History
+ *
+ * 2008-01-20 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.1:
+ *
+ * Fixed the detection of infinite floating point values on IRIX (and
+ * possibly other systems) and applied another few minor cleanups.
+ *
+ * 2008-01-06 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.0:
+ *
+ * Added a lot of new features, fixed many bugs, and incorporated various
+ * improvements done by Andrew Tridgell <tridge@samba.org>, Russ Allbery
+ * <rra@stanford.edu>, Hrvoje Niksic <hniksic@xemacs.org>, Damien Miller
+ * <djm@mindrot.org>, and others for the Samba, INN, Wget, and OpenSSH
+ * projects. The additions include: support the "e", "E", "g", "G", and
+ * "F" conversion specifiers (and use conversion style "f" or "F" for the
+ * still unsupported "a" and "A" specifiers); support the "hh", "ll", "j",
+ * "t", and "z" length modifiers; support the "#" flag and the (non-C99)
+ * "'" flag; use localeconv(3) (if available) to get both the current
+ * locale's decimal point character and the separator between groups of
+ * digits; fix the handling of various corner cases of field width and
+ * precision specifications; fix various floating point conversion bugs;
+ * handle infinite and NaN floating point values; don't attempt to write to
+ * the output buffer (which may be NULL) if a size of zero was specified;
+ * check for integer overflow of the field width, precision, and return
+ * values and during the floating point conversion; use the OUTCHAR() macro
+ * instead of a function for better performance; provide asprintf(3) and
+ * vasprintf(3) functions; add new test cases. The replacement functions
+ * have been renamed to use an "rpl_" prefix, the function calls in the
+ * main project (and in this file) must be redefined accordingly for each
+ * replacement function which is needed (by using Autoconf or other means).
+ * Various other minor improvements have been applied and the coding style
+ * was cleaned up for consistency.
+ *
+ * 2007-07-23 Holger Weiss <holger@jhweiss.de> for Mutt 1.5.13:
+ *
+ * C99 compliant snprintf(3) and vsnprintf(3) functions return the number
+ * of characters that would have been written to a sufficiently sized
+ * buffer (excluding the '\0'). The original code simply returned the
+ * length of the resulting output string, so that's been fixed.
+ *
+ * 1998-03-05 Michael Elkins <me@mutt.org> for Mutt 0.90.8:
+ *
+ * The original code assumed that both snprintf(3) and vsnprintf(3) were
+ * missing. Some systems only have snprintf(3) but not vsnprintf(3), so
+ * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ * 1998-01-27 Thomas Roessler <roessler@does-not-exist.org> for Mutt 0.89i:
+ *
+ * The PGP code was using unsigned hexadecimal formats. Unfortunately,
+ * unsigned formats simply didn't work.
+ *
+ * 1997-10-22 Brandon Long <blong@fiction.net> for Mutt 0.87.1:
+ *
+ * Ok, added some minimal floating point support, which means this probably
+ * requires libm on most operating systems. Don't yet support the exponent
+ * (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just
+ * wasn't being exercised in ways which showed it, so that's been fixed.
+ * Also, formatted the code to Mutt conventions, and removed dead code left
+ * over from the original. Also, there is now a builtin-test, run with:
+ * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf
+ *
+ * 2996-09-15 Brandon Long <blong@fiction.net> for Mutt 0.43:
+ *
+ * This was ugly. It is still ugly. I opted out of floating point
+ * numbers, but the formatter understands just about everything from the
+ * normal C string format, at least as far as I can tell from the Solaris
+ * 2.5 printf(3S) man page.
+ */
+
+/*
+ * ToDo
+ *
+ * - Add wide character support.
+ * - Add support for "%a" and "%A" conversions.
+ * - Create test routines which predefine the expected results. Our test cases
+ * usually expose bugs in system implementations rather than in ours :-)
+ */
+
+/*
+ * Usage
+ *
+ * 1) The following preprocessor macros should be defined to 1 if the feature or
+ * file in question is available on the target system (by using Autoconf or
+ * other means), though basic functionality should be available as long as
+ * HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly:
+ *
+ * HAVE_VSNPRINTF
+ * HAVE_SNPRINTF
+ * HAVE_VASPRINTF
+ * HAVE_ASPRINTF
+ * HAVE_STDARG_H
+ * HAVE_STDDEF_H
+ * HAVE_STDINT_H
+ * HAVE_STDLIB_H
+ * HAVE_INTTYPES_H
+ * HAVE_LOCALE_H
+ * HAVE_LOCALECONV
+ * HAVE_LCONV_DECIMAL_POINT
+ * HAVE_LCONV_THOUSANDS_SEP
+ * HAVE_LONG_DOUBLE
+ * HAVE_LONG_LONG_INT
+ * HAVE_UNSIGNED_LONG_LONG_INT
+ * HAVE_INTMAX_T
+ * HAVE_UINTMAX_T
+ * HAVE_UINTPTR_T
+ * HAVE_PTRDIFF_T
+ * HAVE_VA_COPY
+ * HAVE___VA_COPY
+ *
+ * 2) The calls to the functions which should be replaced must be redefined
+ * throughout the project files (by using Autoconf or other means):
+ *
+ * #define vsnprintf rpl_vsnprintf
+ * #define snprintf rpl_snprintf
+ * #define vasprintf rpl_vasprintf
+ * #define asprintf rpl_asprintf
+ *
+ * 3) The required replacement functions should be declared in some header file
+ * included throughout the project files:
+ *
+ * #if HAVE_CONFIG_H
+ * #include <config.h>
+ * #endif
+ * #if HAVE_STDARG_H
+ * #include <stdarg.h>
+ * #if !HAVE_VSNPRINTF
+ * int rpl_vsnprintf(char *, size_t, const char *, va_list);
+ * #endif
+ * #if !HAVE_SNPRINTF
+ * int rpl_snprintf(char *, size_t, const char *, ...);
+ * #endif
+ * #if !HAVE_VASPRINTF
+ * int rpl_vasprintf(char **, const char *, va_list);
+ * #endif
+ * #if !HAVE_ASPRINTF
+ * int rpl_asprintf(char **, const char *, ...);
+ * #endif
+ * #endif
+ *
+ * Autoconf macros for handling step 1 and step 2 are available at
+ * <http://www.jhweiss.de/software/snprintf.html>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if TEST_SNPRINTF
+#include <math.h> /* For pow(3), NAN, and INFINITY. */
+#include <string.h> /* For strcmp(3). */
+#if defined(__NetBSD__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NeXT__) || \
+ defined(__bsd__)
+#define OS_BSD 1
+#elif defined(sgi) || defined(__sgi)
+#ifndef __c99
+#define __c99 /* Force C99 mode to get <stdint.h> included on IRIX 6.5.30. */
+#endif /* !defined(__c99) */
+#define OS_IRIX 1
+#define OS_SYSV 1
+#elif defined(__svr4__)
+#define OS_SYSV 1
+#elif defined(__linux__)
+#define OS_LINUX 1
+#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */
+#if HAVE_CONFIG_H /* Undefine definitions possibly done in config.h. */
+#ifdef HAVE_SNPRINTF
+#undef HAVE_SNPRINTF
+#endif /* defined(HAVE_SNPRINTF) */
+#ifdef HAVE_VSNPRINTF
+#undef HAVE_VSNPRINTF
+#endif /* defined(HAVE_VSNPRINTF) */
+#ifdef HAVE_ASPRINTF
+#undef HAVE_ASPRINTF
+#endif /* defined(HAVE_ASPRINTF) */
+#ifdef HAVE_VASPRINTF
+#undef HAVE_VASPRINTF
+#endif /* defined(HAVE_VASPRINTF) */
+#ifdef snprintf
+#undef snprintf
+#endif /* defined(snprintf) */
+#ifdef vsnprintf
+#undef vsnprintf
+#endif /* defined(vsnprintf) */
+#ifdef asprintf
+#undef asprintf
+#endif /* defined(asprintf) */
+#ifdef vasprintf
+#undef vasprintf
+#endif /* defined(vasprintf) */
+#else /* By default, we assume a modern system for testing. */
+#ifndef HAVE_STDARG_H
+#define HAVE_STDARG_H 1
+#endif /* HAVE_STDARG_H */
+#ifndef HAVE_STDDEF_H
+#define HAVE_STDDEF_H 1
+#endif /* HAVE_STDDEF_H */
+#ifndef HAVE_STDINT_H
+#define HAVE_STDINT_H 1
+#endif /* HAVE_STDINT_H */
+#ifndef HAVE_STDLIB_H
+#define HAVE_STDLIB_H 1
+#endif /* HAVE_STDLIB_H */
+#ifndef HAVE_INTTYPES_H
+#define HAVE_INTTYPES_H 1
+#endif /* HAVE_INTTYPES_H */
+#ifndef HAVE_LOCALE_H
+#define HAVE_LOCALE_H 1
+#endif /* HAVE_LOCALE_H */
+#ifndef HAVE_LOCALECONV
+#define HAVE_LOCALECONV 1
+#endif /* !defined(HAVE_LOCALECONV) */
+#ifndef HAVE_LCONV_DECIMAL_POINT
+#define HAVE_LCONV_DECIMAL_POINT 1
+#endif /* HAVE_LCONV_DECIMAL_POINT */
+#ifndef HAVE_LCONV_THOUSANDS_SEP
+#define HAVE_LCONV_THOUSANDS_SEP 1
+#endif /* HAVE_LCONV_THOUSANDS_SEP */
+#ifndef HAVE_LONG_DOUBLE
+#define HAVE_LONG_DOUBLE 1
+#endif /* !defined(HAVE_LONG_DOUBLE) */
+#ifndef HAVE_LONG_LONG_INT
+#define HAVE_LONG_LONG_INT 1
+#endif /* !defined(HAVE_LONG_LONG_INT) */
+#ifndef HAVE_UNSIGNED_LONG_LONG_INT
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+#endif /* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */
+#ifndef HAVE_INTMAX_T
+#define HAVE_INTMAX_T 1
+#endif /* !defined(HAVE_INTMAX_T) */
+#ifndef HAVE_UINTMAX_T
+#define HAVE_UINTMAX_T 1
+#endif /* !defined(HAVE_UINTMAX_T) */
+#ifndef HAVE_UINTPTR_T
+#define HAVE_UINTPTR_T 1
+#endif /* !defined(HAVE_UINTPTR_T) */
+#ifndef HAVE_PTRDIFF_T
+#define HAVE_PTRDIFF_T 1
+#endif /* !defined(HAVE_PTRDIFF_T) */
+#ifndef HAVE_VA_COPY
+#define HAVE_VA_COPY 1
+#endif /* !defined(HAVE_VA_COPY) */
+#ifndef HAVE___VA_COPY
+#define HAVE___VA_COPY 1
+#endif /* !defined(HAVE___VA_COPY) */
+#endif /* HAVE_CONFIG_H */
+#define snprintf rpl_snprintf
+#define vsnprintf rpl_vsnprintf
+#define asprintf rpl_asprintf
+#define vasprintf rpl_vasprintf
+#endif /* TEST_SNPRINTF */
+
+#if !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || !HAVE_VASPRINTF
+#include <stdio.h> /* For NULL, size_t, vsnprintf(3), and vasprintf(3). */
+#ifdef VA_START
+#undef VA_START
+#endif /* defined(VA_START) */
+#ifdef VA_SHIFT
+#undef VA_SHIFT
+#endif /* defined(VA_SHIFT) */
+#if HAVE_STDARG_H
+#include <stdarg.h>
+#define VA_START(ap, last) va_start(ap, last)
+#define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */
+#else /* Assume <varargs.h> is available. */
+#include <varargs.h>
+#define VA_START(ap, last) va_start(ap) /* "last" is ignored. */
+#define VA_SHIFT(ap, value, type) value = va_arg(ap, type)
+#endif /* HAVE_STDARG_H */
+
+#if !HAVE_VSNPRINTF
+int rpl_vsnprintf(char *, size_t, const char *, va_list);
+#define vsnprintf rpl_vsnprintf
+#endif
+#if !HAVE_SNPRINTF
+int rpl_snprintf(char *, size_t, const char *, ...);
+#define snprintf rpl_snprintf
+#endif
+#if !HAVE_VASPRINTF
+int rpl_vasprintf(char **, const char *, va_list);
+#define vasprintf rpl_vasprintf
+#endif
+#if !HAVE_ASPRINTF
+int rpl_asprintf(char **, const char *, ...);
+#define asprintf rpl_asprintf
+#endif
+
+#if !HAVE_VASPRINTF
+#if HAVE_STDLIB_H
+#include <stdlib.h> /* For malloc(3). */
+#endif /* HAVE_STDLIB_H */
+#ifdef VA_COPY
+#undef VA_COPY
+#endif /* defined(VA_COPY) */
+#ifdef VA_END_COPY
+#undef VA_END_COPY
+#endif /* defined(VA_END_COPY) */
+#if HAVE_VA_COPY
+#define VA_COPY(dest, src) va_copy(dest, src)
+#define VA_END_COPY(ap) va_end(ap)
+#elif HAVE___VA_COPY
+#define VA_COPY(dest, src) __va_copy(dest, src)
+#define VA_END_COPY(ap) va_end(ap)
+#else
+#define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list))
+#define VA_END_COPY(ap) /* No-op. */
+#define NEED_MYMEMCPY 1
+static void *mymemcpy(void *, void *, size_t);
+#endif /* HAVE_VA_COPY */
+#endif /* !HAVE_VASPRINTF */
+
+#if !HAVE_VSNPRINTF
+#include <errno.h> /* For ERANGE and errno. */
+#include <limits.h> /* For *_MAX. */
+#if HAVE_INTTYPES_H
+#include <inttypes.h> /* For intmax_t (if not defined in <stdint.h>). */
+#endif /* HAVE_INTTYPES_H */
+#if HAVE_LOCALE_H
+#include <locale.h> /* For localeconv(3). */
+#endif /* HAVE_LOCALE_H */
+#if HAVE_STDDEF_H
+#include <stddef.h> /* For ptrdiff_t. */
+#endif /* HAVE_STDDEF_H */
+#if HAVE_STDINT_H
+#include <stdint.h> /* For intmax_t. */
+#endif /* HAVE_STDINT_H */
+
+/* Support for unsigned long long int. We may also need ULLONG_MAX. */
+#ifndef ULONG_MAX /* We may need ULONG_MAX as a fallback. */
+#ifdef UINT_MAX
+#define ULONG_MAX UINT_MAX
+#else
+#define ULONG_MAX INT_MAX
+#endif /* defined(UINT_MAX) */
+#endif /* !defined(ULONG_MAX) */
+#ifdef ULLONG
+#undef ULLONG
+#endif /* defined(ULLONG) */
+#if HAVE_UNSIGNED_LONG_LONG_INT
+#define ULLONG unsigned long long int
+#ifndef ULLONG_MAX
+#define ULLONG_MAX ULONG_MAX
+#endif /* !defined(ULLONG_MAX) */
+#else
+#define ULLONG unsigned long int
+#ifdef ULLONG_MAX
+#undef ULLONG_MAX
+#endif /* defined(ULLONG_MAX) */
+#define ULLONG_MAX ULONG_MAX
+#endif /* HAVE_LONG_LONG_INT */
+
+/* Support for uintmax_t. We also need UINTMAX_MAX. */
+#ifdef UINTMAX_T
+#undef UINTMAX_T
+#endif /* defined(UINTMAX_T) */
+#if HAVE_UINTMAX_T || defined(uintmax_t)
+#define UINTMAX_T uintmax_t
+#ifndef UINTMAX_MAX
+#define UINTMAX_MAX ULLONG_MAX
+#endif /* !defined(UINTMAX_MAX) */
+#else
+#define UINTMAX_T ULLONG
+#ifdef UINTMAX_MAX
+#undef UINTMAX_MAX
+#endif /* defined(UINTMAX_MAX) */
+#define UINTMAX_MAX ULLONG_MAX
+#endif /* HAVE_UINTMAX_T || defined(uintmax_t) */
+
+/* Support for long double. */
+#ifndef LDOUBLE
+#if HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif /* HAVE_LONG_DOUBLE */
+#endif /* !defined(LDOUBLE) */
+
+/* Support for long long int. */
+#ifndef LLONG
+#if HAVE_LONG_LONG_INT
+#define LLONG long long int
+#else
+#define LLONG long int
+#endif /* HAVE_LONG_LONG_INT */
+#endif /* !defined(LLONG) */
+
+/* Support for intmax_t. */
+#ifndef INTMAX_T
+#if HAVE_INTMAX_T || defined(intmax_t)
+#define INTMAX_T intmax_t
+#else
+#define INTMAX_T LLONG
+#endif /* HAVE_INTMAX_T || defined(intmax_t) */
+#endif /* !defined(INTMAX_T) */
+
+/* Support for uintptr_t. */
+#ifndef UINTPTR_T
+#if HAVE_UINTPTR_T || defined(uintptr_t)
+#define UINTPTR_T uintptr_t
+#else
+#define UINTPTR_T unsigned long int
+#endif /* HAVE_UINTPTR_T || defined(uintptr_t) */
+#endif /* !defined(UINTPTR_T) */
+
+/* Support for ptrdiff_t. */
+#ifndef PTRDIFF_T
+#if HAVE_PTRDIFF_T || defined(ptrdiff_t)
+#define PTRDIFF_T ptrdiff_t
+#else
+#define PTRDIFF_T long int
+#endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */
+#endif /* !defined(PTRDIFF_T) */
+
+/*
+ * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99:
+ * 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an
+ * unsigned type if necessary. This should work just fine in practice.
+ */
+#ifndef UPTRDIFF_T
+#define UPTRDIFF_T PTRDIFF_T
+#endif /* !defined(UPTRDIFF_T) */
+
+/*
+ * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7).
+ * However, we'll simply use size_t and convert it to a signed type if
+ * necessary. This should work just fine in practice.
+ */
+#ifndef SSIZE_T
+#define SSIZE_T size_t
+#endif /* !defined(SSIZE_T) */
+
+/* Either ERANGE or E2BIG should be available everywhere. */
+#ifndef ERANGE
+#define ERANGE E2BIG
+#endif /* !defined(ERANGE) */
+#ifndef EOVERFLOW
+#define EOVERFLOW ERANGE
+#endif /* !defined(EOVERFLOW) */
+
+/*
+ * Buffer size to hold the octal string representation of UINT128_MAX without
+ * nul-termination ("3777777777777777777777777777777777777777777").
+ */
+#ifdef MAX_CONVERT_LENGTH
+#undef MAX_CONVERT_LENGTH
+#endif /* defined(MAX_CONVERT_LENGTH) */
+#define MAX_CONVERT_LENGTH 43
+
+/* Format read states. */
+#define PRINT_S_DEFAULT 0
+#define PRINT_S_FLAGS 1
+#define PRINT_S_WIDTH 2
+#define PRINT_S_DOT 3
+#define PRINT_S_PRECISION 4
+#define PRINT_S_MOD 5
+#define PRINT_S_CONV 6
+
+/* Format flags. */
+#define PRINT_F_MINUS (1 << 0)
+#define PRINT_F_PLUS (1 << 1)
+#define PRINT_F_SPACE (1 << 2)
+#define PRINT_F_NUM (1 << 3)
+#define PRINT_F_ZERO (1 << 4)
+#define PRINT_F_QUOTE (1 << 5)
+#define PRINT_F_UP (1 << 6)
+#define PRINT_F_UNSIGNED (1 << 7)
+#define PRINT_F_TYPE_G (1 << 8)
+#define PRINT_F_TYPE_E (1 << 9)
+
+/* Conversion flags. */
+#define PRINT_C_CHAR 1
+#define PRINT_C_SHORT 2
+#define PRINT_C_LONG 3
+#define PRINT_C_LLONG 4
+#define PRINT_C_LDOUBLE 5
+#define PRINT_C_SIZE 6
+#define PRINT_C_PTRDIFF 7
+#define PRINT_C_INTMAX 8
+
+#ifndef MAX
+#define MAX(x, y) ((x >= y) ? x : y)
+#endif /* !defined(MAX) */
+#ifndef CHARTOINT
+#define CHARTOINT(ch) (ch - '0')
+#endif /* !defined(CHARTOINT) */
+#ifndef ISDIGIT
+#define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9')
+#endif /* !defined(ISDIGIT) */
+#ifndef ISNAN
+#define ISNAN(x) (x != x)
+#endif /* !defined(ISNAN) */
+#ifndef ISINF
+#define ISINF(x) (x != 0.0 && x + x == x)
+#endif /* !defined(ISINF) */
+
+#ifdef OUTCHAR
+#undef OUTCHAR
+#endif /* defined(OUTCHAR) */
+#define OUTCHAR(str, len, size, ch) \
+do { \
+ if (len + 1 < size) \
+ str[len] = ch; \
+ (len)++; \
+} while (/* CONSTCOND */ 0)
+
+static void fmtstr(char *, size_t *, size_t, const char *, int, int, int);
+static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int);
+static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *);
+static void printsep(char *, size_t *, size_t);
+static int getnumsep(int);
+static int getexponent(LDOUBLE);
+static int convert(UINTMAX_T, char *, size_t, int, int);
+static UINTMAX_T cast(LDOUBLE);
+static UINTMAX_T myround(LDOUBLE);
+static LDOUBLE mypow10(int);
+
+#ifndef __MINGW32__
+extern int errno;
+#endif
+
+int
+rpl_vsnprintf(char *str, size_t size, const char *format, va_list args)
+{
+ LDOUBLE fvalue;
+ INTMAX_T value;
+ unsigned char cvalue;
+ const char *strvalue;
+ INTMAX_T *intmaxptr;
+ PTRDIFF_T *ptrdiffptr;
+ SSIZE_T *sizeptr;
+ LLONG *llongptr;
+ long int *longptr;
+ int *intptr;
+ short int *shortptr;
+ signed char *charptr;
+ size_t len = 0;
+ int overflow = 0;
+ int base = 0;
+ int cflags = 0;
+ int flags = 0;
+ int width = 0;
+ int precision = -1;
+ int state = PRINT_S_DEFAULT;
+ char ch = *format++;
+
+ /*
+ * C99 says: "If `n' is zero, nothing is written, and `s' may be a null
+ * pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer
+ * even if a size larger than zero was specified. At least NetBSD's
+ * snprintf(3) does the same, as well as other versions of this file.
+ * (Though some of these versions will write to a non-NULL buffer even
+ * if a size of zero was specified, which violates the standard.)
+ */
+ if (str == NULL && size != 0)
+ size = 0;
+
+ while (ch != '\0')
+ switch (state) {
+ case PRINT_S_DEFAULT:
+ if (ch == '%')
+ state = PRINT_S_FLAGS;
+ else
+ OUTCHAR(str, len, size, ch);
+ ch = *format++;
+ break;
+ case PRINT_S_FLAGS:
+ switch (ch) {
+ case '-':
+ flags |= PRINT_F_MINUS;
+ ch = *format++;
+ break;
+ case '+':
+ flags |= PRINT_F_PLUS;
+ ch = *format++;
+ break;
+ case ' ':
+ flags |= PRINT_F_SPACE;
+ ch = *format++;
+ break;
+ case '#':
+ flags |= PRINT_F_NUM;
+ ch = *format++;
+ break;
+ case '0':
+ flags |= PRINT_F_ZERO;
+ ch = *format++;
+ break;
+ case '\'': /* SUSv2 flag (not in C99). */
+ flags |= PRINT_F_QUOTE;
+ ch = *format++;
+ break;
+ default:
+ state = PRINT_S_WIDTH;
+ break;
+ }
+ break;
+ case PRINT_S_WIDTH:
+ if (ISDIGIT(ch)) {
+ ch = CHARTOINT(ch);
+ if (width > (INT_MAX - ch) / 10) {
+ overflow = 1;
+ goto out;
+ }
+ width = 10 * width + ch;
+ ch = *format++;
+ } else if (ch == '*') {
+ /*
+ * C99 says: "A negative field width argument is
+ * taken as a `-' flag followed by a positive
+ * field width." (7.19.6.1, 5)
+ */
+ if ((width = va_arg(args, int)) < 0) {
+ flags |= PRINT_F_MINUS;
+ width = -width;
+ }
+ ch = *format++;
+ state = PRINT_S_DOT;
+ } else
+ state = PRINT_S_DOT;
+ break;
+ case PRINT_S_DOT:
+ if (ch == '.') {
+ state = PRINT_S_PRECISION;
+ ch = *format++;
+ } else
+ state = PRINT_S_MOD;
+ break;
+ case PRINT_S_PRECISION:
+ if (precision == -1)
+ precision = 0;
+ if (ISDIGIT(ch)) {
+ ch = CHARTOINT(ch);
+ if (precision > (INT_MAX - ch) / 10) {
+ overflow = 1;
+ goto out;
+ }
+ precision = 10 * precision + ch;
+ ch = *format++;
+ } else if (ch == '*') {
+ /*
+ * C99 says: "A negative precision argument is
+ * taken as if the precision were omitted."
+ * (7.19.6.1, 5)
+ */
+ if ((precision = va_arg(args, int)) < 0)
+ precision = -1;
+ ch = *format++;
+ state = PRINT_S_MOD;
+ } else
+ state = PRINT_S_MOD;
+ break;
+ case PRINT_S_MOD:
+ switch (ch) {
+ case 'h':
+ ch = *format++;
+ if (ch == 'h') { /* It's a char. */
+ ch = *format++;
+ cflags = PRINT_C_CHAR;
+ } else
+ cflags = PRINT_C_SHORT;
+ break;
+ case 'l':
+ ch = *format++;
+ if (ch == 'l') { /* It's a long long. */
+ ch = *format++;
+ cflags = PRINT_C_LLONG;
+ } else
+ cflags = PRINT_C_LONG;
+ break;
+ case 'L':
+ cflags = PRINT_C_LDOUBLE;
+ ch = *format++;
+ break;
+ case 'j':
+ cflags = PRINT_C_INTMAX;
+ ch = *format++;
+ break;
+ case 't':
+ cflags = PRINT_C_PTRDIFF;
+ ch = *format++;
+ break;
+ case 'z':
+ cflags = PRINT_C_SIZE;
+ ch = *format++;
+ break;
+ }
+ state = PRINT_S_CONV;
+ break;
+ case PRINT_S_CONV:
+ switch (ch) {
+ case 'd':
+ /* FALLTHROUGH */
+ case 'i':
+ switch (cflags) {
+ case PRINT_C_CHAR:
+ value = (signed char)va_arg(args, int);
+ break;
+ case PRINT_C_SHORT:
+ value = (short int)va_arg(args, int);
+ break;
+ case PRINT_C_LONG:
+ value = va_arg(args, long int);
+ break;
+ case PRINT_C_LLONG:
+ value = va_arg(args, LLONG);
+ break;
+ case PRINT_C_SIZE:
+ value = va_arg(args, SSIZE_T);
+ break;
+ case PRINT_C_INTMAX:
+ value = va_arg(args, INTMAX_T);
+ break;
+ case PRINT_C_PTRDIFF:
+ value = va_arg(args, PTRDIFF_T);
+ break;
+ default:
+ value = va_arg(args, int);
+ break;
+ }
+ fmtint(str, &len, size, value, 10, width,
+ precision, flags);
+ break;
+ case 'X':
+ flags |= PRINT_F_UP;
+ /* FALLTHROUGH */
+ case 'x':
+ base = 16;
+ /* FALLTHROUGH */
+ case 'o':
+ if (base == 0)
+ base = 8;
+ /* FALLTHROUGH */
+ case 'u':
+ if (base == 0)
+ base = 10;
+ flags |= PRINT_F_UNSIGNED;
+ switch (cflags) {
+ case PRINT_C_CHAR:
+ value = (unsigned char)va_arg(args,
+ unsigned int);
+ break;
+ case PRINT_C_SHORT:
+ value = (unsigned short int)va_arg(args,
+ unsigned int);
+ break;
+ case PRINT_C_LONG:
+ value = va_arg(args, unsigned long int);
+ break;
+ case PRINT_C_LLONG:
+ value = va_arg(args, ULLONG);
+ break;
+ case PRINT_C_SIZE:
+ value = va_arg(args, size_t);
+ break;
+ case PRINT_C_INTMAX:
+ value = va_arg(args, UINTMAX_T);
+ break;
+ case PRINT_C_PTRDIFF:
+ value = va_arg(args, UPTRDIFF_T);
+ break;
+ default:
+ value = va_arg(args, unsigned int);
+ break;
+ }
+ fmtint(str, &len, size, value, base, width,
+ precision, flags);
+ break;
+ case 'A':
+ /* Not yet supported, we'll use "%F". */
+ /* FALLTHROUGH */
+ case 'F':
+ flags |= PRINT_F_UP;
+ case 'a':
+ /* Not yet supported, we'll use "%f". */
+ /* FALLTHROUGH */
+ case 'f':
+ if (cflags == PRINT_C_LDOUBLE)
+ fvalue = va_arg(args, LDOUBLE);
+ else
+ fvalue = va_arg(args, double);
+ fmtflt(str, &len, size, fvalue, width,
+ precision, flags, &overflow);
+ if (overflow)
+ goto out;
+ break;
+ case 'E':
+ flags |= PRINT_F_UP;
+ /* FALLTHROUGH */
+ case 'e':
+ flags |= PRINT_F_TYPE_E;
+ if (cflags == PRINT_C_LDOUBLE)
+ fvalue = va_arg(args, LDOUBLE);
+ else
+ fvalue = va_arg(args, double);
+ fmtflt(str, &len, size, fvalue, width,
+ precision, flags, &overflow);
+ if (overflow)
+ goto out;
+ break;
+ case 'G':
+ flags |= PRINT_F_UP;
+ /* FALLTHROUGH */
+ case 'g':
+ flags |= PRINT_F_TYPE_G;
+ if (cflags == PRINT_C_LDOUBLE)
+ fvalue = va_arg(args, LDOUBLE);
+ else
+ fvalue = va_arg(args, double);
+ /*
+ * If the precision is zero, it is treated as
+ * one (cf. C99: 7.19.6.1, 8).
+ */
+ if (precision == 0)
+ precision = 1;
+ fmtflt(str, &len, size, fvalue, width,
+ precision, flags, &overflow);
+ if (overflow)
+ goto out;
+ break;
+ case 'c':
+ cvalue = va_arg(args, int);
+ OUTCHAR(str, len, size, cvalue);
+ break;
+ case 's':
+ strvalue = va_arg(args, char *);
+ fmtstr(str, &len, size, strvalue, width,
+ precision, flags);
+ break;
+ case 'p':
+ /*
+ * C99 says: "The value of the pointer is
+ * converted to a sequence of printing
+ * characters, in an implementation-defined
+ * manner." (C99: 7.19.6.1, 8)
+ */
+ if ((strvalue = va_arg(args, void *)) == NULL)
+ /*
+ * We use the glibc format. BSD prints
+ * "0x0", SysV "0".
+ */
+ fmtstr(str, &len, size, "(nil)", width,
+ -1, flags);
+ else {
+ /*
+ * We use the BSD/glibc format. SysV
+ * omits the "0x" prefix (which we emit
+ * using the PRINT_F_NUM flag).
+ */
+ flags |= PRINT_F_NUM;
+ flags |= PRINT_F_UNSIGNED;
+ fmtint(str, &len, size,
+ (UINTPTR_T)strvalue, 16, width,
+ precision, flags);
+ }
+ break;
+ case 'n':
+ switch (cflags) {
+ case PRINT_C_CHAR:
+ charptr = va_arg(args, signed char *);
+ *charptr = len;
+ break;
+ case PRINT_C_SHORT:
+ shortptr = va_arg(args, short int *);
+ *shortptr = len;
+ break;
+ case PRINT_C_LONG:
+ longptr = va_arg(args, long int *);
+ *longptr = len;
+ break;
+ case PRINT_C_LLONG:
+ llongptr = va_arg(args, LLONG *);
+ *llongptr = len;
+ break;
+ case PRINT_C_SIZE:
+ /*
+ * C99 says that with the "z" length
+ * modifier, "a following `n' conversion
+ * specifier applies to a pointer to a
+ * signed integer type corresponding to
+ * size_t argument." (7.19.6.1, 7)
+ */
+ sizeptr = va_arg(args, SSIZE_T *);
+ *sizeptr = len;
+ break;
+ case PRINT_C_INTMAX:
+ intmaxptr = va_arg(args, INTMAX_T *);
+ *intmaxptr = len;
+ break;
+ case PRINT_C_PTRDIFF:
+ ptrdiffptr = va_arg(args, PTRDIFF_T *);
+ *ptrdiffptr = len;
+ break;
+ default:
+ intptr = va_arg(args, int *);
+ *intptr = len;
+ break;
+ }
+ break;
+ case '%': /* Print a "%" character verbatim. */
+ OUTCHAR(str, len, size, ch);
+ break;
+ default: /* Skip other characters. */
+ break;
+ }
+ ch = *format++;
+ state = PRINT_S_DEFAULT;
+ base = cflags = flags = width = 0;
+ precision = -1;
+ break;
+ }
+out:
+ if (len < size)
+ str[len] = '\0';
+ else if (size > 0)
+ str[size - 1] = '\0';
+
+ if (overflow || len >= INT_MAX) {
+ errno = overflow ? EOVERFLOW : ERANGE;
+ return -1;
+ }
+ return (int)len;
+}
+
+static void
+fmtstr(char *str, size_t *len, size_t size, const char *value, int width,
+ int precision, int flags)
+{
+ int padlen, strln; /* Amount to pad. */
+ int noprecision = (precision == -1);
+
+ if (value == NULL) /* We're forgiving. */
+ value = "(null)";
+
+ /* If a precision was specified, don't read the string past it. */
+ for (strln = 0; value[strln] != '\0' &&
+ (noprecision || strln < precision); strln++)
+ continue;
+
+ if ((padlen = width - strln) < 0)
+ padlen = 0;
+ if (flags & PRINT_F_MINUS) /* Left justify. */
+ padlen = -padlen;
+
+ while (padlen > 0) { /* Leading spaces. */
+ OUTCHAR(str, *len, size, ' ');
+ padlen--;
+ }
+ while (*value != '\0' && (noprecision || precision-- > 0)) {
+ OUTCHAR(str, *len, size, *value);
+ value++;
+ }
+ while (padlen < 0) { /* Trailing spaces. */
+ OUTCHAR(str, *len, size, ' ');
+ padlen++;
+ }
+}
+
+static void
+fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width,
+ int precision, int flags)
+{
+ UINTMAX_T uvalue;
+ char iconvert[MAX_CONVERT_LENGTH];
+ char sign = 0;
+ char hexprefix = 0;
+ int spadlen = 0; /* Amount to space pad. */
+ int zpadlen = 0; /* Amount to zero pad. */
+ int pos;
+ int separators = (flags & PRINT_F_QUOTE);
+ int noprecision = (precision == -1);
+
+ if (flags & PRINT_F_UNSIGNED)
+ uvalue = value;
+ else {
+ uvalue = (value >= 0) ? value : -value;
+ if (value < 0)
+ sign = '-';
+ else if (flags & PRINT_F_PLUS) /* Do a sign. */
+ sign = '+';
+ else if (flags & PRINT_F_SPACE)
+ sign = ' ';
+ }
+
+ pos = convert(uvalue, iconvert, sizeof(iconvert), base,
+ flags & PRINT_F_UP);
+
+ if (flags & PRINT_F_NUM && uvalue != 0) {
+ /*
+ * C99 says: "The result is converted to an `alternative form'.
+ * For `o' conversion, it increases the precision, if and only
+ * if necessary, to force the first digit of the result to be a
+ * zero (if the value and precision are both 0, a single 0 is
+ * printed). For `x' (or `X') conversion, a nonzero result has
+ * `0x' (or `0X') prefixed to it." (7.19.6.1, 6)
+ */
+ switch (base) {
+ case 8:
+ if (precision <= pos)
+ precision = pos + 1;
+ break;
+ case 16:
+ hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x';
+ break;
+ }
+ }
+
+ if (separators) /* Get the number of group separators we'll print. */
+ separators = getnumsep(pos);
+
+ zpadlen = precision - pos - separators;
+ spadlen = width /* Minimum field width. */
+ - separators /* Number of separators. */
+ - MAX(precision, pos) /* Number of integer digits. */
+ - ((sign != 0) ? 1 : 0) /* Will we print a sign? */
+ - ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */
+
+ if (zpadlen < 0)
+ zpadlen = 0;
+ if (spadlen < 0)
+ spadlen = 0;
+
+ /*
+ * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
+ * ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a
+ * precision is specified, the `0' flag is ignored." (7.19.6.1, 6)
+ */
+ if (flags & PRINT_F_MINUS) /* Left justify. */
+ spadlen = -spadlen;
+ else if (flags & PRINT_F_ZERO && noprecision) {
+ zpadlen += spadlen;
+ spadlen = 0;
+ }
+ while (spadlen > 0) { /* Leading spaces. */
+ OUTCHAR(str, *len, size, ' ');
+ spadlen--;
+ }
+ if (sign != 0) /* Sign. */
+ OUTCHAR(str, *len, size, sign);
+ if (hexprefix != 0) { /* A "0x" or "0X" prefix. */
+ OUTCHAR(str, *len, size, '0');
+ OUTCHAR(str, *len, size, hexprefix);
+ }
+ while (zpadlen > 0) { /* Leading zeros. */
+ OUTCHAR(str, *len, size, '0');
+ zpadlen--;
+ }
+ while (pos > 0) { /* The actual digits. */
+ pos--;
+ OUTCHAR(str, *len, size, iconvert[pos]);
+ if (separators > 0 && pos > 0 && pos % 3 == 0)
+ printsep(str, len, size);
+ }
+ while (spadlen < 0) { /* Trailing spaces. */
+ OUTCHAR(str, *len, size, ' ');
+ spadlen++;
+ }
+}
+
+static void
+fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width,
+ int precision, int flags, int *overflow)
+{
+ LDOUBLE ufvalue;
+ UINTMAX_T intpart;
+ UINTMAX_T fracpart;
+ UINTMAX_T mask;
+ const char *infnan = NULL;
+ char iconvert[MAX_CONVERT_LENGTH];
+ char fconvert[MAX_CONVERT_LENGTH];
+ char econvert[4]; /* "e-12" (without nul-termination). */
+ char esign = 0;
+ char sign = 0;
+ int leadfraczeros = 0;
+ int exponent = 0;
+ int emitpoint = 0;
+ int omitzeros = 0;
+ int omitcount = 0;
+ int padlen = 0;
+ int epos = 0;
+ int fpos = 0;
+ int ipos = 0;
+ int separators = (flags & PRINT_F_QUOTE);
+ int estyle = (flags & PRINT_F_TYPE_E);
+#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
+ struct lconv *lc = localeconv();
+#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
+
+ /*
+ * AIX' man page says the default is 0, but C99 and at least Solaris'
+ * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX
+ * defaults to 6.
+ */
+ if (precision == -1)
+ precision = 6;
+
+ if (fvalue < 0.0)
+ sign = '-';
+ else if (flags & PRINT_F_PLUS) /* Do a sign. */
+ sign = '+';
+ else if (flags & PRINT_F_SPACE)
+ sign = ' ';
+
+ if (ISNAN(fvalue))
+ infnan = (flags & PRINT_F_UP) ? "NAN" : "nan";
+ else if (ISINF(fvalue))
+ infnan = (flags & PRINT_F_UP) ? "INF" : "inf";
+
+ if (infnan != NULL) {
+ if (sign != 0)
+ iconvert[ipos++] = sign;
+ while (*infnan != '\0')
+ iconvert[ipos++] = *infnan++;
+ fmtstr(str, len, size, iconvert, width, ipos, flags);
+ return;
+ }
+
+ /* "%e" (or "%E") or "%g" (or "%G") conversion. */
+ if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) {
+ if (flags & PRINT_F_TYPE_G) {
+ /*
+ * For "%g" (and "%G") conversions, the precision
+ * specifies the number of significant digits, which
+ * includes the digits in the integer part. The
+ * conversion will or will not be using "e-style" (like
+ * "%e" or "%E" conversions) depending on the precision
+ * and on the exponent. However, the exponent can be
+ * affected by rounding the converted value, so we'll
+ * leave this decision for later. Until then, we'll
+ * assume that we're going to do an "e-style" conversion
+ * (in order to get the exponent calculated). For
+ * "e-style", the precision must be decremented by one.
+ */
+ precision--;
+ /*
+ * For "%g" (and "%G") conversions, trailing zeros are
+ * removed from the fractional portion of the result
+ * unless the "#" flag was specified.
+ */
+ if (!(flags & PRINT_F_NUM))
+ omitzeros = 1;
+ }
+ exponent = getexponent(fvalue);
+ estyle = 1;
+ }
+
+again:
+ /*
+ * Sorry, we only support 9, 19, or 38 digits (that is, the number of
+ * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value
+ * minus one) past the decimal point due to our conversion method.
+ */
+ switch (sizeof(UINTMAX_T)) {
+ case 16:
+ if (precision > 38)
+ precision = 38;
+ break;
+ case 8:
+ if (precision > 19)
+ precision = 19;
+ break;
+ default:
+ if (precision > 9)
+ precision = 9;
+ break;
+ }
+
+ ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue;
+ if (estyle) /* We want exactly one integer digit. */
+ ufvalue /= mypow10(exponent);
+
+ if ((intpart = cast(ufvalue)) == UINTMAX_MAX) {
+ *overflow = 1;
+ return;
+ }
+
+ /*
+ * Factor of ten with the number of digits needed for the fractional
+ * part. For example, if the precision is 3, the mask will be 1000.
+ */
+ mask = mypow10(precision);
+ /*
+ * We "cheat" by converting the fractional part to integer by
+ * multiplying by a factor of ten.
+ */
+ if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) {
+ /*
+ * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000
+ * (because precision = 3). Now, myround(1000 * 0.99962) will
+ * return 1000. So, the integer part must be incremented by one
+ * and the fractional part must be set to zero.
+ */
+ intpart++;
+ fracpart = 0;
+ if (estyle && intpart == 10) {
+ /*
+ * The value was rounded up to ten, but we only want one
+ * integer digit if using "e-style". So, the integer
+ * part must be set to one and the exponent must be
+ * incremented by one.
+ */
+ intpart = 1;
+ exponent++;
+ }
+ }
+
+ /*
+ * Now that we know the real exponent, we can check whether or not to
+ * use "e-style" for "%g" (and "%G") conversions. If we don't need
+ * "e-style", the precision must be adjusted and the integer and
+ * fractional parts must be recalculated from the original value.
+ *
+ * C99 says: "Let P equal the precision if nonzero, 6 if the precision
+ * is omitted, or 1 if the precision is zero. Then, if a conversion
+ * with style `E' would have an exponent of X:
+ *
+ * - if P > X >= -4, the conversion is with style `f' (or `F') and
+ * precision P - (X + 1).
+ *
+ * - otherwise, the conversion is with style `e' (or `E') and precision
+ * P - 1." (7.19.6.1, 8)
+ *
+ * Note that we had decremented the precision by one.
+ */
+ if (flags & PRINT_F_TYPE_G && estyle &&
+ precision + 1 > exponent && exponent >= -4) {
+ precision -= exponent;
+ estyle = 0;
+ goto again;
+ }
+
+ if (estyle) {
+ if (exponent < 0) {
+ exponent = -exponent;
+ esign = '-';
+ } else
+ esign = '+';
+
+ /*
+ * Convert the exponent. The sizeof(econvert) is 4. So, the
+ * econvert buffer can hold e.g. "e+99" and "e-99". We don't
+ * support an exponent which contains more than two digits.
+ * Therefore, the following stores are safe.
+ */
+ epos = convert(exponent, econvert, 2, 10, 0);
+ /*
+ * C99 says: "The exponent always contains at least two digits,
+ * and only as many more digits as necessary to represent the
+ * exponent." (7.19.6.1, 8)
+ */
+ if (epos == 1)
+ econvert[epos++] = '0';
+ econvert[epos++] = esign;
+ econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e';
+ }
+
+ /* Convert the integer part and the fractional part. */
+ ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0);
+ if (fracpart != 0) /* convert() would return 1 if fracpart == 0. */
+ fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0);
+
+ leadfraczeros = precision - fpos;
+
+ if (omitzeros) {
+ if (fpos > 0) /* Omit trailing fractional part zeros. */
+ while (omitcount < fpos && fconvert[omitcount] == '0')
+ omitcount++;
+ else { /* The fractional part is zero, omit it completely. */
+ omitcount = precision;
+ leadfraczeros = 0;
+ }
+ precision -= omitcount;
+ }
+
+ /*
+ * Print a decimal point if either the fractional part is non-zero
+ * and/or the "#" flag was specified.
+ */
+ if (precision > 0 || flags & PRINT_F_NUM)
+ emitpoint = 1;
+ if (separators) /* Get the number of group separators we'll print. */
+ separators = getnumsep(ipos);
+
+ padlen = width /* Minimum field width. */
+ - ipos /* Number of integer digits. */
+ - epos /* Number of exponent characters. */
+ - precision /* Number of fractional digits. */
+ - separators /* Number of group separators. */
+ - (emitpoint ? 1 : 0) /* Will we print a decimal point? */
+ - ((sign != 0) ? 1 : 0); /* Will we print a sign character? */
+
+ if (padlen < 0)
+ padlen = 0;
+
+ /*
+ * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
+ * ignored." (7.19.6.1, 6)
+ */
+ if (flags & PRINT_F_MINUS) /* Left justifty. */
+ padlen = -padlen;
+ else if (flags & PRINT_F_ZERO && padlen > 0) {
+ if (sign != 0) { /* Sign. */
+ OUTCHAR(str, *len, size, sign);
+ sign = 0;
+ }
+ while (padlen > 0) { /* Leading zeros. */
+ OUTCHAR(str, *len, size, '0');
+ padlen--;
+ }
+ }
+ while (padlen > 0) { /* Leading spaces. */
+ OUTCHAR(str, *len, size, ' ');
+ padlen--;
+ }
+ if (sign != 0) /* Sign. */
+ OUTCHAR(str, *len, size, sign);
+ while (ipos > 0) { /* Integer part. */
+ ipos--;
+ OUTCHAR(str, *len, size, iconvert[ipos]);
+ if (separators > 0 && ipos > 0 && ipos % 3 == 0)
+ printsep(str, len, size);
+ }
+ if (emitpoint) { /* Decimal point. */
+#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
+ if (lc->decimal_point != NULL && *lc->decimal_point != '\0')
+ OUTCHAR(str, *len, size, *lc->decimal_point);
+ else /* We'll always print some decimal point character. */
+#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
+ OUTCHAR(str, *len, size, '.');
+ }
+ while (leadfraczeros > 0) { /* Leading fractional part zeros. */
+ OUTCHAR(str, *len, size, '0');
+ leadfraczeros--;
+ }
+ while (fpos > omitcount) { /* The remaining fractional part. */
+ fpos--;
+ OUTCHAR(str, *len, size, fconvert[fpos]);
+ }
+ while (epos > 0) { /* Exponent. */
+ epos--;
+ OUTCHAR(str, *len, size, econvert[epos]);
+ }
+ while (padlen < 0) { /* Trailing spaces. */
+ OUTCHAR(str, *len, size, ' ');
+ padlen++;
+ }
+}
+
+static void
+printsep(char *str, size_t *len, size_t size)
+{
+#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
+ struct lconv *lc = localeconv();
+ int i;
+
+ if (lc->thousands_sep != NULL)
+ for (i = 0; lc->thousands_sep[i] != '\0'; i++)
+ OUTCHAR(str, *len, size, lc->thousands_sep[i]);
+ else
+#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
+ OUTCHAR(str, *len, size, ',');
+}
+
+static int
+getnumsep(int digits)
+{
+ int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3;
+#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
+ int strln;
+ struct lconv *lc = localeconv();
+
+ /* We support an arbitrary separator length (including zero). */
+ if (lc->thousands_sep != NULL) {
+ for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++)
+ continue;
+ separators *= strln;
+ }
+#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
+ return separators;
+}
+
+static int
+getexponent(LDOUBLE value)
+{
+ LDOUBLE tmp = (value >= 0.0) ? value : -value;
+ int exponent = 0;
+
+ /*
+ * We check for 99 > exponent > -99 in order to work around possible
+ * endless loops which could happen (at least) in the second loop (at
+ * least) if we're called with an infinite value. However, we checked
+ * for infinity before calling this function using our ISINF() macro, so
+ * this might be somewhat paranoid.
+ */
+ while (tmp < 1.0 && tmp > 0.0 && --exponent > -99)
+ tmp *= 10;
+ while (tmp >= 10.0 && ++exponent < 99)
+ tmp /= 10;
+
+ return exponent;
+}
+
+static int
+convert(UINTMAX_T value, char *buf, size_t size, int base, int caps)
+{
+ const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef";
+ size_t pos = 0;
+
+ /* We return an unterminated buffer with the digits in reverse order. */
+ do {
+ buf[pos++] = digits[value % base];
+ value /= base;
+ } while (value != 0 && pos < size);
+
+ return (int)pos;
+}
+
+static UINTMAX_T
+cast(LDOUBLE value)
+{
+ UINTMAX_T result;
+
+ /*
+ * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be
+ * represented exactly as an LDOUBLE value (but is less than LDBL_MAX),
+ * it may be increased to the nearest higher representable value for the
+ * comparison (cf. C99: 6.3.1.4, 2). It might then equal the LDOUBLE
+ * value although converting the latter to UINTMAX_T would overflow.
+ */
+ if (value >= UINTMAX_MAX)
+ return UINTMAX_MAX;
+
+ result = value;
+ /*
+ * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to
+ * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates
+ * the standard). Sigh.
+ */
+ return (result <= value) ? result : result - 1;
+}
+
+static UINTMAX_T
+myround(LDOUBLE value)
+{
+ UINTMAX_T intpart = cast(value);
+
+ return ((value -= intpart) < 0.5) ? intpart : intpart + 1;
+}
+
+static LDOUBLE
+mypow10(int exponent)
+{
+ LDOUBLE result = 1;
+
+ while (exponent > 0) {
+ result *= 10;
+ exponent--;
+ }
+ while (exponent < 0) {
+ result /= 10;
+ exponent++;
+ }
+ return result;
+}
+#endif /* !HAVE_VSNPRINTF */
+
+#if !HAVE_VASPRINTF
+#if NEED_MYMEMCPY
+void *
+mymemcpy(void *dst, void *src, size_t len)
+{
+ const char *from = src;
+ char *to = dst;
+
+ /* No need for optimization, we use this only to replace va_copy(3). */
+ while (len-- > 0)
+ *to++ = *from++;
+ return dst;
+}
+#endif /* NEED_MYMEMCPY */
+
+int
+rpl_vasprintf(char **ret, const char *format, va_list ap)
+{
+ size_t size;
+ int len;
+ va_list aq;
+
+ VA_COPY(aq, ap);
+ len = vsnprintf(NULL, 0, format, aq);
+ VA_END_COPY(aq);
+ if (len < 0 || (*ret = malloc(size = len + 1)) == NULL)
+ return -1;
+ return vsnprintf(*ret, size, format, ap);
+}
+#endif /* !HAVE_VASPRINTF */
+
+#if !HAVE_SNPRINTF
+#if HAVE_STDARG_H
+int
+rpl_snprintf(char *str, size_t size, const char *format, ...)
+#else
+int
+rpl_snprintf(va_alist) va_dcl
+#endif /* HAVE_STDARG_H */
+{
+#if !HAVE_STDARG_H
+ char *str;
+ size_t size;
+ char *format;
+#endif /* HAVE_STDARG_H */
+ va_list ap;
+ int len;
+
+ VA_START(ap, format);
+ VA_SHIFT(ap, str, char *);
+ VA_SHIFT(ap, size, size_t);
+ VA_SHIFT(ap, format, const char *);
+ len = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return len;
+}
+#endif /* !HAVE_SNPRINTF */
+
+#if !HAVE_ASPRINTF
+#if HAVE_STDARG_H
+int
+rpl_asprintf(char **ret, const char *format, ...)
+#else
+int
+rpl_asprintf(va_alist) va_dcl
+#endif /* HAVE_STDARG_H */
+{
+#if !HAVE_STDARG_H
+ char **ret;
+ char *format;
+#endif /* HAVE_STDARG_H */
+ va_list ap;
+ int len;
+
+ VA_START(ap, format);
+ VA_SHIFT(ap, ret, char **);
+ VA_SHIFT(ap, format, const char *);
+ len = vasprintf(ret, format, ap);
+ va_end(ap);
+ return len;
+}
+#endif /* !HAVE_ASPRINTF */
+#else /* Dummy declaration to avoid empty translation unit warnings. */
+int main(void);
+#endif /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || [...] */
+
+#if TEST_SNPRINTF
+int
+main(void)
+{
+ const char *float_fmt[] = {
+ /* "%E" and "%e" formats. */
+#if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX
+ "%.16e",
+ "%22.16e",
+ "%022.16e",
+ "%-22.16e",
+ "%#+'022.16e",
+#endif /* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */
+ "foo|%#+0123.9E|bar",
+ "%-123.9e",
+ "%123.9e",
+ "%+23.9e",
+ "%+05.8e",
+ "%-05.8e",
+ "%05.8e",
+ "%+5.8e",
+ "%-5.8e",
+ "% 5.8e",
+ "%5.8e",
+ "%+4.9e",
+#if !OS_LINUX /* glibc sometimes gets these wrong. */
+ "%+#010.0e",
+ "%#10.1e",
+ "%10.5e",
+ "% 10.5e",
+ "%5.0e",
+ "%5.e",
+ "%#5.0e",
+ "%#5.e",
+ "%3.2e",
+ "%3.1e",
+ "%-1.5e",
+ "%1.5e",
+ "%01.3e",
+ "%1.e",
+ "%.1e",
+ "%#.0e",
+ "%+.0e",
+ "% .0e",
+ "%.0e",
+ "%#.e",
+ "%+.e",
+ "% .e",
+ "%.e",
+ "%4e",
+ "%e",
+ "%E",
+#endif /* !OS_LINUX */
+ /* "%F" and "%f" formats. */
+#if !OS_BSD && !OS_IRIX
+ "% '022f",
+ "%+'022f",
+ "%-'22f",
+ "%'22f",
+#if HAVE_LONG_LONG_INT
+ "%.16f",
+ "%22.16f",
+ "%022.16f",
+ "%-22.16f",
+ "%#+'022.16f",
+#endif /* HAVE_LONG_LONG_INT */
+#endif /* !OS_BSD && !OS_IRIX */
+ "foo|%#+0123.9F|bar",
+ "%-123.9f",
+ "%123.9f",
+ "%+23.9f",
+ "%+#010.0f",
+ "%#10.1f",
+ "%10.5f",
+ "% 10.5f",
+ "%+05.8f",
+ "%-05.8f",
+ "%05.8f",
+ "%+5.8f",
+ "%-5.8f",
+ "% 5.8f",
+ "%5.8f",
+ "%5.0f",
+ "%5.f",
+ "%#5.0f",
+ "%#5.f",
+ "%+4.9f",
+ "%3.2f",
+ "%3.1f",
+ "%-1.5f",
+ "%1.5f",
+ "%01.3f",
+ "%1.f",
+ "%.1f",
+ "%#.0f",
+ "%+.0f",
+ "% .0f",
+ "%.0f",
+ "%#.f",
+ "%+.f",
+ "% .f",
+ "%.f",
+ "%4f",
+ "%f",
+ "%F",
+ /* "%G" and "%g" formats. */
+#if !OS_BSD && !OS_IRIX && !OS_LINUX
+ "% '022g",
+ "%+'022g",
+ "%-'22g",
+ "%'22g",
+#if HAVE_LONG_LONG_INT
+ "%.16g",
+ "%22.16g",
+ "%022.16g",
+ "%-22.16g",
+ "%#+'022.16g",
+#endif /* HAVE_LONG_LONG_INT */
+#endif /* !OS_BSD && !OS_IRIX && !OS_LINUX */
+ "foo|%#+0123.9G|bar",
+ "%-123.9g",
+ "%123.9g",
+ "%+23.9g",
+ "%+05.8g",
+ "%-05.8g",
+ "%05.8g",
+ "%+5.8g",
+ "%-5.8g",
+ "% 5.8g",
+ "%5.8g",
+ "%+4.9g",
+#if !OS_LINUX /* glibc sometimes gets these wrong. */
+ "%+#010.0g",
+ "%#10.1g",
+ "%10.5g",
+ "% 10.5g",
+ "%5.0g",
+ "%5.g",
+ "%#5.0g",
+ "%#5.g",
+ "%3.2g",
+ "%3.1g",
+ "%-1.5g",
+ "%1.5g",
+ "%01.3g",
+ "%1.g",
+ "%.1g",
+ "%#.0g",
+ "%+.0g",
+ "% .0g",
+ "%.0g",
+ "%#.g",
+ "%+.g",
+ "% .g",
+ "%.g",
+ "%4g",
+ "%g",
+ "%G",
+#endif /* !OS_LINUX */
+ NULL
+ };
+ double float_val[] = {
+ -4.136,
+ -134.52,
+ -5.04030201,
+ -3410.01234,
+ -999999.999999,
+ -913450.29876,
+ -913450.2,
+ -91345.2,
+ -9134.2,
+ -913.2,
+ -91.2,
+ -9.2,
+ -9.9,
+ 4.136,
+ 134.52,
+ 5.04030201,
+ 3410.01234,
+ 999999.999999,
+ 913450.29876,
+ 913450.2,
+ 91345.2,
+ 9134.2,
+ 913.2,
+ 91.2,
+ 9.2,
+ 9.9,
+ 9.96,
+ 9.996,
+ 9.9996,
+ 9.99996,
+ 9.999996,
+ 9.9999996,
+ 9.99999996,
+ 0.99999996,
+ 0.99999999,
+ 0.09999999,
+ 0.00999999,
+ 0.00099999,
+ 0.00009999,
+ 0.00000999,
+ 0.00000099,
+ 0.00000009,
+ 0.00000001,
+ 0.0000001,
+ 0.000001,
+ 0.00001,
+ 0.0001,
+ 0.001,
+ 0.01,
+ 0.1,
+ 1.0,
+ 1.5,
+ -1.5,
+ -1.0,
+ -0.1,
+#if !OS_BSD /* BSD sometimes gets these wrong. */
+#ifdef INFINITY
+ INFINITY,
+ -INFINITY,
+#endif /* defined(INFINITY) */
+#ifdef NAN
+ NAN,
+#endif /* defined(NAN) */
+#endif /* !OS_BSD */
+ 0
+ };
+ const char *long_fmt[] = {
+ "foo|%0123ld|bar",
+#if !OS_IRIX
+ "% '0123ld",
+ "%+'0123ld",
+ "%-'123ld",
+ "%'123ld",
+#endif /* !OS_IRiX */
+ "%123.9ld",
+ "% 123.9ld",
+ "%+123.9ld",
+ "%-123.9ld",
+ "%0123ld",
+ "% 0123ld",
+ "%+0123ld",
+ "%-0123ld",
+ "%10.5ld",
+ "% 10.5ld",
+ "%+10.5ld",
+ "%-10.5ld",
+ "%010ld",
+ "% 010ld",
+ "%+010ld",
+ "%-010ld",
+ "%4.2ld",
+ "% 4.2ld",
+ "%+4.2ld",
+ "%-4.2ld",
+ "%04ld",
+ "% 04ld",
+ "%+04ld",
+ "%-04ld",
+ "%5.5ld",
+ "%+22.33ld",
+ "%01.3ld",
+ "%1.5ld",
+ "%-1.5ld",
+ "%44ld",
+ "%4ld",
+ "%4.0ld",
+ "%4.ld",
+ "%.44ld",
+ "%.4ld",
+ "%.0ld",
+ "%.ld",
+ "%ld",
+ NULL
+ };
+ long int long_val[] = {
+#ifdef LONG_MAX
+ LONG_MAX,
+#endif /* LONG_MAX */
+#ifdef LONG_MIN
+ LONG_MIN,
+#endif /* LONG_MIN */
+ -91340,
+ 91340,
+ 341,
+ 134,
+ 0203,
+ -1,
+ 1,
+ 0
+ };
+ const char *ulong_fmt[] = {
+ /* "%u" formats. */
+ "foo|%0123lu|bar",
+#if !OS_IRIX
+ "% '0123lu",
+ "%+'0123lu",
+ "%-'123lu",
+ "%'123lu",
+#endif /* !OS_IRiX */
+ "%123.9lu",
+ "% 123.9lu",
+ "%+123.9lu",
+ "%-123.9lu",
+ "%0123lu",
+ "% 0123lu",
+ "%+0123lu",
+ "%-0123lu",
+ "%5.5lu",
+ "%+22.33lu",
+ "%01.3lu",
+ "%1.5lu",
+ "%-1.5lu",
+ "%44lu",
+ "%lu",
+ /* "%o" formats. */
+ "foo|%#0123lo|bar",
+ "%#123.9lo",
+ "%# 123.9lo",
+ "%#+123.9lo",
+ "%#-123.9lo",
+ "%#0123lo",
+ "%# 0123lo",
+ "%#+0123lo",
+ "%#-0123lo",
+ "%#5.5lo",
+ "%#+22.33lo",
+ "%#01.3lo",
+ "%#1.5lo",
+ "%#-1.5lo",
+ "%#44lo",
+ "%#lo",
+ "%123.9lo",
+ "% 123.9lo",
+ "%+123.9lo",
+ "%-123.9lo",
+ "%0123lo",
+ "% 0123lo",
+ "%+0123lo",
+ "%-0123lo",
+ "%5.5lo",
+ "%+22.33lo",
+ "%01.3lo",
+ "%1.5lo",
+ "%-1.5lo",
+ "%44lo",
+ "%lo",
+ /* "%X" and "%x" formats. */
+ "foo|%#0123lX|bar",
+ "%#123.9lx",
+ "%# 123.9lx",
+ "%#+123.9lx",
+ "%#-123.9lx",
+ "%#0123lx",
+ "%# 0123lx",
+ "%#+0123lx",
+ "%#-0123lx",
+ "%#5.5lx",
+ "%#+22.33lx",
+ "%#01.3lx",
+ "%#1.5lx",
+ "%#-1.5lx",
+ "%#44lx",
+ "%#lx",
+ "%#lX",
+ "%123.9lx",
+ "% 123.9lx",
+ "%+123.9lx",
+ "%-123.9lx",
+ "%0123lx",
+ "% 0123lx",
+ "%+0123lx",
+ "%-0123lx",
+ "%5.5lx",
+ "%+22.33lx",
+ "%01.3lx",
+ "%1.5lx",
+ "%-1.5lx",
+ "%44lx",
+ "%lx",
+ "%lX",
+ NULL
+ };
+ unsigned long int ulong_val[] = {
+#ifdef ULONG_MAX
+ ULONG_MAX,
+#endif /* ULONG_MAX */
+ 91340,
+ 341,
+ 134,
+ 0203,
+ 1,
+ 0
+ };
+ const char *llong_fmt[] = {
+ "foo|%0123lld|bar",
+ "%123.9lld",
+ "% 123.9lld",
+ "%+123.9lld",
+ "%-123.9lld",
+ "%0123lld",
+ "% 0123lld",
+ "%+0123lld",
+ "%-0123lld",
+ "%5.5lld",
+ "%+22.33lld",
+ "%01.3lld",
+ "%1.5lld",
+ "%-1.5lld",
+ "%44lld",
+ "%lld",
+ NULL
+ };
+ LLONG llong_val[] = {
+#ifdef LLONG_MAX
+ LLONG_MAX,
+#endif /* LLONG_MAX */
+#ifdef LLONG_MIN
+ LLONG_MIN,
+#endif /* LLONG_MIN */
+ -91340,
+ 91340,
+ 341,
+ 134,
+ 0203,
+ -1,
+ 1,
+ 0
+ };
+ const char *string_fmt[] = {
+ "foo|%10.10s|bar",
+ "%-10.10s",
+ "%10.10s",
+ "%10.5s",
+ "%5.10s",
+ "%10.1s",
+ "%1.10s",
+ "%10.0s",
+ "%0.10s",
+ "%-42.5s",
+ "%2.s",
+ "%.10s",
+ "%.1s",
+ "%.0s",
+ "%.s",
+ "%4s",
+ "%s",
+ NULL
+ };
+ const char *string_val[] = {
+ "Hello",
+ "Hello, world!",
+ "Sound check: One, two, three.",
+ "This string is a little longer than the other strings.",
+ "1",
+ "",
+ NULL
+ };
+#if !OS_SYSV /* SysV uses a different format than we do. */
+ const char *pointer_fmt[] = {
+ "foo|%p|bar",
+ "%42p",
+ "%p",
+ NULL
+ };
+ const char *pointer_val[] = {
+ *pointer_fmt,
+ *string_fmt,
+ *string_val,
+ NULL
+ };
+#endif /* !OS_SYSV */
+ char buf1[1024], buf2[1024];
+ double value, digits = 9.123456789012345678901234567890123456789;
+ int i, j, r1, r2, failed = 0, num = 0;
+
+/*
+ * Use -DTEST_NILS in order to also test the conversion of nil values. Might
+ * segfault on systems which don't support converting a NULL pointer with "%s"
+ * and lets some test cases fail against BSD and glibc due to bugs in their
+ * implementations.
+ */
+#ifndef TEST_NILS
+#define TEST_NILS 0
+#elif TEST_NILS
+#undef TEST_NILS
+#define TEST_NILS 1
+#endif /* !defined(TEST_NILS) */
+#ifdef TEST
+#undef TEST
+#endif /* defined(TEST) */
+#define TEST(fmt, val) \
+do { \
+ for (i = 0; fmt[i] != NULL; i++) \
+ for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) { \
+ r1 = sprintf(buf1, fmt[i], val[j]); \
+ r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]); \
+ if (strcmp(buf1, buf2) != 0 || r1 != r2) { \
+ (void)printf("Results don't match, " \
+ "format string: %s\n" \
+ "\t sprintf(3): [%s] (%d)\n" \
+ "\tsnprintf(3): [%s] (%d)\n", \
+ fmt[i], buf1, r1, buf2, r2); \
+ failed++; \
+ } \
+ num++; \
+ } \
+} while (/* CONSTCOND */ 0)
+
+#if HAVE_LOCALE_H
+ (void)setlocale(LC_ALL, "");
+#endif /* HAVE_LOCALE_H */
+
+ (void)puts("Testing our snprintf(3) against your system's sprintf(3).");
+ TEST(float_fmt, float_val);
+ TEST(long_fmt, long_val);
+ TEST(ulong_fmt, ulong_val);
+ TEST(llong_fmt, llong_val);
+ TEST(string_fmt, string_val);
+#if !OS_SYSV /* SysV uses a different format than we do. */
+ TEST(pointer_fmt, pointer_val);
+#endif /* !OS_SYSV */
+ (void)printf("Result: %d out of %d tests failed.\n", failed, num);
+
+ (void)fputs("Checking how many digits we support: ", stdout);
+ for (i = 0; i < 100; i++) {
+ value = pow(10, i) * digits;
+ (void)sprintf(buf1, "%.1f", value);
+ (void)snprintf(buf2, sizeof(buf2), "%.1f", value);
+ if (strcmp(buf1, buf2) != 0) {
+ (void)printf("apparently %d.\n", i);
+ break;
+ }
+ }
+ return (failed == 0) ? 0 : 1;
+}
+#endif /* TEST_SNPRINTF */
+
+/* vim: set joinspaces textwidth=80: */
diff --git a/stats.c b/stats.c
new file mode 100644
index 0000000..5d9fc73
--- /dev/null
+++ b/stats.c
@@ -0,0 +1,562 @@
+// Copyright (C) 2002-2004 Andrew Tridgell
+// Copyright (C) 2009-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// Routines to handle the stats files. The stats file is stored one per cache
+// subdirectory to make this more scalable.
+
+#include "ccache.h"
+#include "hashutil.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern char *stats_file;
+extern struct conf *conf;
+extern unsigned lock_staleness_limit;
+extern char *primary_config_path;
+extern char *secondary_config_path;
+
+static struct counters *counter_updates;
+
+#define FLAG_NOZERO 1 // don't zero with the -z option
+#define FLAG_ALWAYS 2 // always show, even if zero
+#define FLAG_NEVER 4 // never show
+
+static void display_size_times_1024(uint64_t size);
+
+// Statistics fields in display order.
+static struct {
+ enum stats stat;
+ char *message;
+ void (*fn)(uint64_t);
+ unsigned flags;
+} stats_info[] = {
+ {
+ STATS_CACHEHIT_DIR,
+ "cache hit (direct)",
+ NULL,
+ FLAG_ALWAYS
+ },
+ {
+ STATS_CACHEHIT_CPP,
+ "cache hit (preprocessed)",
+ NULL,
+ FLAG_ALWAYS
+ },
+ {
+ STATS_TOCACHE,
+ "cache miss",
+ NULL,
+ FLAG_ALWAYS
+ },
+ {
+ STATS_LINK,
+ "called for link",
+ NULL,
+ 0
+ },
+ {
+ STATS_PREPROCESSING,
+ "called for preprocessing",
+ NULL,
+ 0
+ },
+ {
+ STATS_MULTIPLE,
+ "multiple source files",
+ NULL,
+ 0
+ },
+ {
+ STATS_STDOUT,
+ "compiler produced stdout",
+ NULL,
+ 0
+ },
+ {
+ STATS_NOOUTPUT,
+ "compiler produced no output",
+ NULL,
+ 0
+ },
+ {
+ STATS_EMPTYOUTPUT,
+ "compiler produced empty output",
+ NULL,
+ 0
+ },
+ {
+ STATS_STATUS,
+ "compile failed",
+ NULL,
+ 0
+ },
+ {
+ STATS_ERROR,
+ "ccache internal error",
+ NULL,
+ 0
+ },
+ {
+ STATS_PREPROCESSOR,
+ "preprocessor error",
+ NULL,
+ 0
+ },
+ {
+ STATS_CANTUSEPCH,
+ "can't use precompiled header",
+ NULL,
+ 0
+ },
+ {
+ STATS_COMPILER,
+ "couldn't find the compiler",
+ NULL,
+ 0
+ },
+ {
+ STATS_MISSING,
+ "cache file missing",
+ NULL,
+ 0
+ },
+ {
+ STATS_ARGS,
+ "bad compiler arguments",
+ NULL,
+ 0
+ },
+ {
+ STATS_SOURCELANG,
+ "unsupported source language",
+ NULL,
+ 0
+ },
+ {
+ STATS_COMPCHECK,
+ "compiler check failed",
+ NULL,
+ 0
+ },
+ {
+ STATS_CONFTEST,
+ "autoconf compile/link",
+ NULL,
+ 0
+ },
+ {
+ STATS_UNSUPPORTED_OPTION,
+ "unsupported compiler option",
+ NULL,
+ 0
+ },
+ {
+ STATS_UNSUPPORTED_DIRECTIVE,
+ "unsupported code directive",
+ NULL,
+ 0
+ },
+ {
+ STATS_OUTSTDOUT,
+ "output to stdout",
+ NULL,
+ 0
+ },
+ {
+ STATS_DEVICE,
+ "output to a non-regular file",
+ NULL,
+ 0
+ },
+ {
+ STATS_NOINPUT,
+ "no input file",
+ NULL,
+ 0
+ },
+ {
+ STATS_BADEXTRAFILE,
+ "error hashing extra file",
+ NULL,
+ 0
+ },
+ {
+ STATS_NUMCLEANUPS,
+ "cleanups performed",
+ NULL,
+ FLAG_ALWAYS
+ },
+ {
+ STATS_NUMFILES,
+ "files in cache",
+ NULL,
+ FLAG_NOZERO|FLAG_ALWAYS
+ },
+ {
+ STATS_TOTALSIZE,
+ "cache size",
+ display_size_times_1024,
+ FLAG_NOZERO|FLAG_ALWAYS
+ },
+ {
+ STATS_OBSOLETE_MAXFILES,
+ "OBSOLETE",
+ NULL,
+ FLAG_NOZERO|FLAG_NEVER
+ },
+ {
+ STATS_OBSOLETE_MAXSIZE,
+ "OBSOLETE",
+ NULL,
+ FLAG_NOZERO|FLAG_NEVER
+ },
+ {
+ STATS_NONE,
+ NULL,
+ NULL,
+ 0
+ }
+};
+
+static void
+display_size(uint64_t size)
+{
+ char *s = format_human_readable_size(size);
+ printf("%11s", s);
+ free(s);
+}
+
+static void
+display_size_times_1024(uint64_t size)
+{
+ display_size(size * 1024);
+}
+
+// Parse a stats file from a buffer, adding to the counters.
+static void
+parse_stats(struct counters *counters, const char *buf)
+{
+ size_t i = 0;
+ const char *p = buf;
+ while (true) {
+ char *p2;
+ long val = strtol(p, &p2, 10);
+ if (p2 == p) {
+ break;
+ }
+ if (counters->size < i + 1) {
+ counters_resize(counters, i + 1);
+ }
+ counters->data[i] += val;
+ i++;
+ p = p2;
+ }
+}
+
+// Write out a stats file.
+void
+stats_write(const char *path, struct counters *counters)
+{
+ char *tmp_file = format("%s.tmp", path);
+ FILE *f = create_tmp_file(&tmp_file, "wb");
+ for (size_t i = 0; i < counters->size; i++) {
+ if (fprintf(f, "%u\n", counters->data[i]) < 0) {
+ fatal("Failed to write to %s", tmp_file);
+ }
+ }
+ fclose(f);
+ x_rename(tmp_file, path);
+ free(tmp_file);
+}
+
+static void
+init_counter_updates(void)
+{
+ if (!counter_updates) {
+ counter_updates = counters_init(STATS_END);
+ }
+}
+
+// Record that a number of bytes and files have been added to the cache. Size
+// is in bytes.
+void
+stats_update_size(uint64_t size, unsigned files)
+{
+ init_counter_updates();
+ counter_updates->data[STATS_NUMFILES] += files;
+ counter_updates->data[STATS_TOTALSIZE] += size / 1024;
+}
+
+// Read in the stats from one directory and add to the counters.
+void
+stats_read(const char *sfile, struct counters *counters)
+{
+ char *data = read_text_file(sfile, 1024);
+ if (data) {
+ parse_stats(counters, data);
+ }
+ free(data);
+}
+
+// Write counter updates in counter_updates to disk.
+void
+stats_flush(void)
+{
+ assert(conf);
+
+ if (!conf->stats) {
+ return;
+ }
+
+ if (!counter_updates) {
+ return;
+ }
+
+ bool should_flush = false;
+ for (int i = 0; i < STATS_END; ++i) {
+ if (counter_updates->data[i] > 0) {
+ should_flush = true;
+ break;
+ }
+ }
+ if (!should_flush) {
+ return;
+ }
+
+ if (!stats_file) {
+ char *stats_dir;
+
+ // A NULL stats_file means that we didn't get past calculate_object_hash(),
+ // so we just choose one of stats files in the 16 subdirectories.
+ stats_dir = format("%s/%x", conf->cache_dir, hash_from_int(getpid()) % 16);
+ stats_file = format("%s/stats", stats_dir);
+ free(stats_dir);
+ }
+
+ if (!lockfile_acquire(stats_file, lock_staleness_limit)) {
+ return;
+ }
+
+ struct counters *counters = counters_init(STATS_END);
+ stats_read(stats_file, counters);
+ for (int i = 0; i < STATS_END; ++i) {
+ counters->data[i] += counter_updates->data[i];
+ }
+ stats_write(stats_file, counters);
+ lockfile_release(stats_file);
+
+ if (!str_eq(conf->log_file, "")) {
+ for (int i = 0; i < STATS_END; ++i) {
+ if (counter_updates->data[stats_info[i].stat] != 0
+ && !(stats_info[i].flags & FLAG_NOZERO)) {
+ cc_log("Result: %s", stats_info[i].message);
+ }
+ }
+ }
+
+ bool need_cleanup = false;
+ if (conf->max_files != 0
+ && counters->data[STATS_NUMFILES] > conf->max_files / 16) {
+ need_cleanup = true;
+ }
+ if (conf->max_size != 0
+ && counters->data[STATS_TOTALSIZE] > conf->max_size / 1024 / 16) {
+ need_cleanup = true;
+ }
+
+ if (need_cleanup) {
+ char *p = dirname(stats_file);
+ cleanup_dir(conf, p);
+ free(p);
+ }
+
+ counters_free(counters);
+}
+
+// Update a normal stat.
+void
+stats_update(enum stats stat)
+{
+ assert(stat > STATS_NONE && stat < STATS_END);
+ init_counter_updates();
+ counter_updates->data[stat]++;
+}
+
+// Get the pending update of a counter value.
+unsigned
+stats_get_pending(enum stats stat)
+{
+ init_counter_updates();
+ return counter_updates->data[stat];
+}
+
+// Sum and display the total stats for all cache dirs.
+void
+stats_summary(struct conf *conf)
+{
+ struct counters *counters = counters_init(STATS_END);
+
+ assert(conf);
+
+ // Add up the stats in each directory.
+ for (int dir = -1; dir <= 0xF; dir++) {
+ char *fname;
+
+ if (dir == -1) {
+ fname = format("%s/stats", conf->cache_dir);
+ } else {
+ fname = format("%s/%1x/stats", conf->cache_dir, dir);
+ }
+
+ stats_read(fname, counters);
+ free(fname);
+ }
+
+ printf("cache directory %s\n", conf->cache_dir);
+ printf("primary config %s\n",
+ primary_config_path ? primary_config_path : "");
+ printf("secondary config (readonly) %s\n",
+ secondary_config_path ? secondary_config_path : "");
+
+ // ...and display them.
+ for (int i = 0; stats_info[i].message; i++) {
+ enum stats stat = stats_info[i].stat;
+
+ if (stats_info[i].flags & FLAG_NEVER) {
+ continue;
+ }
+ if (counters->data[stat] == 0 && !(stats_info[i].flags & FLAG_ALWAYS)) {
+ continue;
+ }
+
+ printf("%-31s ", stats_info[i].message);
+ if (stats_info[i].fn) {
+ stats_info[i].fn(counters->data[stat]);
+ printf("\n");
+ } else {
+ printf("%8u\n", counters->data[stat]);
+ }
+
+ if (stat == STATS_TOCACHE) {
+ unsigned direct = counters->data[STATS_CACHEHIT_DIR];
+ unsigned preprocessed = counters->data[STATS_CACHEHIT_CPP];
+ unsigned hit = direct + preprocessed;
+ unsigned miss = counters->data[STATS_TOCACHE];
+ unsigned total = hit + miss;
+ double percent = total > 0 ? (100.0f * hit) / total : 0.0f;
+ printf("cache hit rate %6.2f %%\n", percent);
+ }
+ }
+
+ if (conf->max_files != 0) {
+ printf("max files %8u\n", conf->max_files);
+ }
+ if (conf->max_size != 0) {
+ printf("max cache size ");
+ display_size(conf->max_size);
+ printf("\n");
+ }
+
+ counters_free(counters);
+}
+
+// Zero all the stats structures.
+void
+stats_zero(void)
+{
+ assert(conf);
+
+ char *fname = format("%s/stats", conf->cache_dir);
+ x_unlink(fname);
+ free(fname);
+
+ for (int dir = 0; dir <= 0xF; dir++) {
+ struct counters *counters = counters_init(STATS_END);
+ struct stat st;
+ fname = format("%s/%1x/stats", conf->cache_dir, dir);
+ if (stat(fname, &st) != 0) {
+ // No point in trying to reset the stats file if it doesn't exist.
+ free(fname);
+ continue;
+ }
+ if (lockfile_acquire(fname, lock_staleness_limit)) {
+ stats_read(fname, counters);
+ for (unsigned i = 0; stats_info[i].message; i++) {
+ if (!(stats_info[i].flags & FLAG_NOZERO)) {
+ counters->data[stats_info[i].stat] = 0;
+ }
+ }
+ stats_write(fname, counters);
+ lockfile_release(fname);
+ }
+ counters_free(counters);
+ free(fname);
+ }
+}
+
+// Get the per-directory limits.
+void
+stats_get_obsolete_limits(const char *dir, unsigned *maxfiles,
+ uint64_t *maxsize)
+{
+ struct counters *counters = counters_init(STATS_END);
+ char *sname = format("%s/stats", dir);
+ stats_read(sname, counters);
+ *maxfiles = counters->data[STATS_OBSOLETE_MAXFILES];
+ *maxsize = (uint64_t)counters->data[STATS_OBSOLETE_MAXSIZE] * 1024;
+ free(sname);
+ counters_free(counters);
+}
+
+// Set the per-directory sizes.
+void
+stats_set_sizes(const char *dir, unsigned num_files, uint64_t total_size)
+{
+ struct counters *counters = counters_init(STATS_END);
+ char *statsfile = format("%s/stats", dir);
+ if (lockfile_acquire(statsfile, lock_staleness_limit)) {
+ stats_read(statsfile, counters);
+ counters->data[STATS_NUMFILES] = num_files;
+ counters->data[STATS_TOTALSIZE] = total_size / 1024;
+ stats_write(statsfile, counters);
+ lockfile_release(statsfile);
+ }
+ free(statsfile);
+ counters_free(counters);
+}
+
+// Count directory cleanup run.
+void
+stats_add_cleanup(const char *dir, unsigned count)
+{
+ struct counters *counters = counters_init(STATS_END);
+ char *statsfile = format("%s/stats", dir);
+ if (lockfile_acquire(statsfile, lock_staleness_limit)) {
+ stats_read(statsfile, counters);
+ counters->data[STATS_NUMCLEANUPS] += count;
+ stats_write(statsfile, counters);
+ lockfile_release(statsfile);
+ }
+ free(statsfile);
+ counters_free(counters);
+}
diff --git a/system.h b/system.h
new file mode 100644
index 0000000..0de03da
--- /dev/null
+++ b/system.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef CCACHE_SYSTEM_H
+#define CCACHE_SYSTEM_H
+
+#include "config.h"
+
+#include <sys/file.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+
+extern char **environ;
+
+#ifndef ESTALE
+#define ESTALE -1
+#endif
+
+#if !HAVE_VSNPRINTF
+ int rpl_vsnprintf(char *, size_t, const char *, va_list);
+ #define vsnprintf rpl_vsnprintf
+#endif
+#if !HAVE_SNPRINTF
+ int rpl_snprintf(char *, size_t, const char *, ...);
+ #define snprintf rpl_snprintf
+#endif
+#if !HAVE_VASPRINTF
+ int rpl_vasprintf(char **, const char *, va_list);
+ #define vasprintf rpl_vasprintf
+#endif
+#if !HAVE_ASPRINTF
+ int rpl_asprintf(char **, const char *, ...);
+ #define asprintf rpl_asprintf
+#endif
+
+#endif // CCACHE_SYSTEM_H
diff --git a/test.sh b/test.sh
new file mode 100755
index 0000000..b4c95b1
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,3468 @@
+#!/bin/sh
+#
+# A simple test suite for ccache.
+#
+# Copyright (C) 2002-2007 Andrew Tridgell
+# Copyright (C) 2009-2017 Joel Rosdahl
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+green() {
+ printf "\033[1;32m$*\033[0;0m\n"
+}
+
+red() {
+ printf "\033[1;31m$*\033[0;0m\n"
+}
+
+bold() {
+ printf "\033[1;37m$*\033[0;0m\n"
+}
+
+test_failed() {
+ echo
+ red FAILED
+ echo
+ echo "Test suite: $(bold $CURRENT_SUITE)"
+ echo "Test case: $(bold $CURRENT_TEST)"
+ echo "Failure reason: $(red $1)"
+ echo
+ echo "ccache -s:"
+ $CCACHE -s
+ echo
+ echo "Test data and log file have been left in $TESTDIR"
+ exit 1
+}
+
+generate_code() {
+ local nlines=$1
+ local outfile=$2
+
+ rm -f $outfile
+ for i in $(seq $nlines); do
+ echo "int foo_$i(int x) { return x; }" >>$outfile
+ done
+}
+
+remove_cache() {
+ if [ -d $CCACHE_DIR ]; then
+ chmod -R +w $CCACHE_DIR
+ rm -rf $CCACHE_DIR
+ fi
+}
+
+clear_cache() {
+ $CCACHE -Cz >/dev/null
+}
+
+sed_in_place() {
+ local expr=$1
+ shift
+
+ for file in $*; do
+ sed "$expr" $file >$file.sed
+ mv $file.sed $file
+ done
+}
+
+backdate() {
+ touch -t 199901010000 "$@"
+}
+
+expect_stat() {
+ local stat="$1"
+ local expected_value="$2"
+ local value="$(echo $($CCACHE -s | fgrep "$stat" | cut -c34-))"
+
+ if [ "$expected_value" != "$value" ]; then
+ test_failed "Expected \"$stat\" to be $expected_value, actual $value"
+ fi
+}
+
+expect_equal_files() {
+ if [ ! -e "$1" ]; then
+ test_failed "compare_files: $1 missing"
+ fi
+ if [ ! -e "$2" ]; then
+ test_failed "compare_files: $2 missing"
+ fi
+ if ! cmp -s "$1" "$2"; then
+ test_failed "compare_files:: $1 and $2 differ"
+ fi
+}
+
+expect_equal_object_files() {
+ if $HOST_OS_LINUX && $COMPILER_TYPE_CLANG; then
+ if ! which eu-elfcmp >/dev/null 2>&1; then
+ test_failed "Please install elfutils to get eu-elfcmp"
+ fi
+ eu-elfcmp -q "$1" "$2"
+ else
+ cmp -s "$1" "$2"
+ fi
+ if [ $? -ne 0 ]; then
+ test_failed "Objects differ: $1 != $2"
+ fi
+}
+
+expect_file_content() {
+ local file="$1"
+ local content="$2"
+
+ if [ ! -f "$file" ]; then
+ test_failed "$file not found"
+ fi
+ if [ "$(cat $file)" != "$content" ]; then
+ test_failed "Bad content of $file.\nExpected: $content\nActual: $(cat $file)"
+ fi
+}
+
+expect_file_count() {
+ local expected=$1
+ local pattern=$2
+ local dir=$3
+ local actual=`find $dir -name "$pattern" | wc -l`
+ if [ $actual -ne $expected ]; then
+ test_failed "Found $actual (expected $expected) $pattern files in $dir"
+ fi
+}
+
+run_suite() {
+ local name=$1
+
+ CURRENT_SUITE=$name
+ UNCACHED_COMPILE=uncached_compile
+
+ cd $ABS_TESTDIR
+ rm -rf $ABS_TESTDIR/fixture
+
+ if type SUITE_${name}_PROBE >/dev/null 2>&1; then
+ mkdir $ABS_TESTDIR/probe
+ cd $ABS_TESTDIR/probe
+ local skip_reason="$(SUITE_${name}_PROBE)"
+ cd $ABS_TESTDIR
+ rm -rf $ABS_TESTDIR/probe
+ if [ -n "$skip_reason" ]; then
+ echo "Skipped test suite $name [$skip_reason]"
+ return
+ fi
+ fi
+
+ printf "Running test suite %s" "$(bold $name)"
+ SUITE_$name
+ echo
+}
+
+uncached_compile() {
+ # $COMPILER could be a masquerading system ccache, so make sure it's
+ # disabled:
+ CCACHE_DISABLE=1 $COMPILER "$@"
+}
+
+TEST() {
+ CURRENT_TEST=$1
+
+ unset CCACHE_BASEDIR
+ unset CCACHE_CC
+ unset CCACHE_COMMENTS
+ unset CCACHE_COMPILERCHECK
+ unset CCACHE_COMPRESS
+ unset CCACHE_CPP2
+ unset CCACHE_DIR
+ unset CCACHE_DISABLE
+ unset CCACHE_EXTENSION
+ unset CCACHE_EXTRAFILES
+ unset CCACHE_HARDLINK
+ unset CCACHE_IGNOREHEADERS
+ unset CCACHE_LIMIT_MULTIPLE
+ unset CCACHE_LOGFILE
+ unset CCACHE_NLEVELS
+ unset CCACHE_NOCPP2
+ unset CCACHE_NOHASHDIR
+ unset CCACHE_NOSTATS
+ unset CCACHE_PATH
+ unset CCACHE_PREFIX
+ unset CCACHE_PREFIX_CPP
+ unset CCACHE_READONLY
+ unset CCACHE_READONLY_DIRECT
+ unset CCACHE_RECACHE
+ unset CCACHE_SLOPPINESS
+ unset CCACHE_TEMPDIR
+ unset CCACHE_UMASK
+ unset CCACHE_UNIFY
+ unset GCC_COLORS
+
+ export CCACHE_CONFIGPATH=$ABS_TESTDIR/ccache.conf
+ export CCACHE_DETECT_SHEBANG=1
+ export CCACHE_DIR=$ABS_TESTDIR/.ccache
+ export CCACHE_LOGFILE=$ABS_TESTDIR/ccache.log
+ export CCACHE_NODIRECT=1
+
+ # Many tests backdate files, which updates their ctimes. In those tests, we
+ # must ignore ctimes. Might as well do so everywhere.
+ DEFAULT_SLOPPINESS=include_file_ctime
+ export CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS"
+
+ CCACHE_COMPILE="$CCACHE $COMPILER"
+
+ if $VERBOSE; then
+ printf "\n %s" $CURRENT_TEST
+ else
+ printf .
+ fi
+
+ cd /
+ remove_cache
+ rm -rf $ABS_TESTDIR/run
+ mkdir $ABS_TESTDIR/run
+ cd $ABS_TESTDIR/run
+ if type SUITE_${name}_SETUP >/dev/null 2>&1; then
+ SUITE_${name}_SETUP
+ fi
+}
+
+# =============================================================================
+
+base_tests() {
+ # -------------------------------------------------------------------------
+ TEST "Base case"
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+
+ # -------------------------------------------------------------------------
+ TEST "Debug option"
+
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c -g
+ expect_equal_object_files reference_test1.o reference_test1.o
+
+ # -------------------------------------------------------------------------
+ TEST "Output option"
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c test1.c -o foo.o
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+ expect_equal_object_files reference_test1.o foo.o
+
+ # -------------------------------------------------------------------------
+ TEST "Called for link"
+
+ $CCACHE_COMPILE test1.c -o test 2>/dev/null
+ expect_stat 'called for link' 1
+
+ $CCACHE_COMPILE -c test1.c
+ $CCACHE_COMPILE test1.o -o test 2>/dev/null
+ expect_stat 'called for link' 2
+
+ # -------------------------------------------------------------------------
+ TEST "No input file"
+
+ $CCACHE_COMPILE -c foo.c 2>/dev/null
+ expect_stat 'no input file' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Called for preprocessing"
+
+ $CCACHE_COMPILE -E -c test1.c >/dev/null 2>&1
+ expect_stat 'called for preprocessing' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Multiple source files"
+
+ touch test2.c
+ $CCACHE_COMPILE -c test1.c test2.c
+ expect_stat 'multiple source files' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Couldn't find the compiler"
+
+ $CCACHE blahblah -c test1.c 2>/dev/null
+ expect_stat "couldn't find the compiler" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Bad compiler arguments"
+
+ $CCACHE_COMPILE -c test1.c -I 2>/dev/null
+ expect_stat 'bad compiler arguments' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Unsupported source language"
+
+ ln -f test1.c test1.ccc
+ $CCACHE_COMPILE -c test1.ccc 2>/dev/null
+ expect_stat 'unsupported source language' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Unsupported compiler option"
+
+ $CCACHE_COMPILE -M foo -c test1.c >/dev/null 2>&1
+ expect_stat 'unsupported compiler option' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Compiler produced stdout"
+
+ $CCACHE echo foo -c test1.c >/dev/null
+ expect_stat 'compiler produced stdout' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Output to a non-regular file"
+
+ mkdir testd
+ $CCACHE_COMPILE -o testd -c test1.c >/dev/null 2>&1
+ rmdir testd >/dev/null 2>&1
+ expect_stat 'output to a non-regular file' 1
+
+ # -------------------------------------------------------------------------
+ TEST "No input file"
+
+ $CCACHE_COMPILE -c -O2 2>/dev/null
+ expect_stat 'no input file' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_DISABLE"
+
+ CCACHE_DISABLE=1 $CCACHE_COMPILE -c test1.c 2>/dev/null
+ if [ -d $CCACHE_DIR ]; then
+ test_failed "$CCACHE_DIR created despite CCACHE_DISABLE being set"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMMENTS"
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+
+ mv test1.c test1-saved.c
+ echo '// initial comment' >test1.c
+ cat test1-saved.c >>test1.c
+ CCACHE_COMMENTS=1 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ echo '// different comment' >test1.c
+ cat test1-saved.c >>test1.c
+ CCACHE_COMMENTS=1 $CCACHE_COMPILE -c test1.c
+ mv test1-saved.c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+ expect_equal_object_files reference_test1.o test1.o
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_NOSTATS"
+
+ CCACHE_NOSTATS=1 $CCACHE_COMPILE -c test1.c -O -O
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_RECACHE"
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_RECACHE=1 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+ expect_equal_object_files reference_test1.o test1.o
+
+ # CCACHE_RECACHE replaces the object file, so the statistics counter will
+ # be off-by-one until next cleanup.
+ expect_stat 'files in cache' 2
+ $CCACHE -c >/dev/null
+ expect_stat 'files in cache' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Directory is hashed if using -g"
+
+ mkdir dir1 dir2
+ cp test1.c dir1
+ cp test1.c dir2
+
+ cd dir1
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ cd ../dir2
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+ $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Directory is not hashed if not using -g"
+
+ mkdir dir1 dir2
+ cp test1.c dir1
+ cp test1.c dir2
+
+ cd dir1
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ cd ../dir2
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_NOHASHDIR"
+
+ mkdir dir1 dir2
+ cp test1.c dir1
+ cp test1.c dir2
+
+ cd dir1
+ CCACHE_NOHASHDIR=1 $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ CCACHE_NOHASHDIR=1 $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ cd ../dir2
+ CCACHE_NOHASHDIR=1 $CCACHE_COMPILE -c test1.c -g
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_UNIFY"
+
+ echo '// a silly comment' >>test1.c
+ CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo '// another silly comment' >>test1.c
+ CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+ expect_equal_object_files reference_test1.o test1.o
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_NLEVELS"
+
+ CCACHE_NLEVELS=4 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+
+ CCACHE_NLEVELS=4 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+
+ # Directories in $CCACHE_DIR:
+ # - .
+ # - tmp
+ # - a
+ # - a/b
+ # - a/b/c
+ # - a/b/c/d
+ actual_dirs=$(find $CCACHE_DIR -type d | wc -l)
+ expected_dirs=6
+ if [ $actual_dirs -ne $expected_dirs ]; then
+ test_failed "Expected $expected_dirs directories, found $actual_dirs"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_EXTRAFILES"
+
+ echo a >a
+ echo b >b
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ echo b2 >b
+
+ CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 3
+
+ CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 3
+ expect_stat 'cache miss' 3
+
+ CCACHE_EXTRAFILES="doesntexist" $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 3
+ expect_stat 'cache miss' 3
+ expect_stat 'error hashing extra file' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_PREFIX"
+
+ cat <<'EOF' >prefix-a
+#!/bin/sh
+echo a >>prefix.result
+exec "$@"
+EOF
+ cat <<'EOF' >prefix-b
+#!/bin/sh
+echo b >>prefix.result
+exec "$@"
+EOF
+ chmod +x prefix-a prefix-b
+ cat <<'EOF' >file.c
+int foo;
+EOF
+ PATH=.:$PATH CCACHE_PREFIX="prefix-a prefix-b" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_file_content prefix.result "a
+b"
+
+ PATH=.:$PATH CCACHE_PREFIX="prefix-a prefix-b" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_file_content prefix.result "a
+b"
+
+ rm -f prefix.result
+ PATH=.:$PATH CCACHE_PREFIX_CPP="prefix-a prefix-b" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+ expect_file_content prefix.result "a
+b"
+
+ # -------------------------------------------------------------------------
+ TEST "Files in cache"
+
+ for i in $(seq 32); do
+ generate_code $i test$i.c
+ $CCACHE_COMPILE -c test$i.c
+ done
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 32
+ expect_stat 'files in cache' 32
+
+ # -------------------------------------------------------------------------
+ TEST "Called for preprocessing"
+
+ $CCACHE_COMPILE -c test1.c -E >test1.i
+ expect_stat 'called for preprocessing' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Direct .i compile"
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $UNCACHED_COMPILE -c test1.c -E >test1.i
+ $CCACHE_COMPILE -c test1.i
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-x c"
+
+ ln -f test1.c test1.ccc
+
+ $CCACHE_COMPILE -x c -c test1.ccc
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -x c -c test1.ccc
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-xc"
+
+ ln -f test1.c test1.ccc
+
+ $CCACHE_COMPILE -xc -c test1.ccc
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -xc -c test1.ccc
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-x none"
+
+ $CCACHE_COMPILE -x assembler -x none -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -x assembler -x none -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-x unknown"
+
+ $CCACHE_COMPILE -x unknown -c test1.c 2>/dev/null
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported source language' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-D not hashed"
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -DNOT_AFFECTING=1 -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-S"
+
+ $CCACHE_COMPILE -S test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -S test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c test1.s
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ $CCACHE_COMPILE -c test1.s
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_PATH"
+
+ override_path=`pwd`/override_path
+ mkdir $override_path
+ cat >$override_path/cc <<EOF
+#!/bin/sh
+touch override_path_compiler_executed
+EOF
+ chmod +x $override_path/cc
+ CCACHE_PATH=$override_path $CCACHE cc -c test1.c
+ if [ ! -f override_path_compiler_executed ]; then
+ test_failed "CCACHE_PATH had no effect"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=mtime"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+# A comment
+EOF
+ chmod +x compiler.sh
+ backdate compiler.sh
+ CCACHE_COMPILERCHECK=mtime $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ sed_in_place 's/comment/yoghurt/' compiler.sh # Don't change the size
+ chmod +x compiler.sh
+ backdate compiler.sh # Don't change the timestamp
+
+ CCACHE_COMPILERCHECK=mtime $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ touch compiler.sh
+ CCACHE_COMPILERCHECK=mtime $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=content"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
+
+ CCACHE_COMPILERCHECK=content $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_COMPILERCHECK=content $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ echo "# Compiler upgrade" >>compiler.sh
+
+ CCACHE_COMPILERCHECK=content $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=none"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
+
+ CCACHE_COMPILERCHECK=none $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_COMPILERCHECK=none $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ echo "# Compiler upgrade" >>compiler.sh
+ CCACHE_COMPILERCHECK=none $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=string"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
+
+ CCACHE_COMPILERCHECK=string:foo $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_COMPILERCHECK=string:foo $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ CCACHE_COMPILERCHECK=string:bar $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ CCACHE_COMPILERCHECK=string:bar $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=command"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
+
+ CCACHE_COMPILERCHECK='echo %compiler%' $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo "# Compiler upgrade" >>compiler.sh
+ CCACHE_COMPILERCHECK="echo ./compiler.sh" $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ cat <<EOF >foobar.sh
+#!/bin/sh
+echo foo
+echo bar
+EOF
+ chmod +x foobar.sh
+ CCACHE_COMPILERCHECK='./foobar.sh' $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ CCACHE_COMPILERCHECK='echo foo; echo bar' $CCACHE ./compiler.sh -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_COMPILERCHECK=unknown_command"
+
+ cat >compiler.sh <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+exec $COMPILER "\$@"
+EOF
+ chmod +x compiler.sh
+
+ CCACHE_COMPILERCHECK="unknown_command" $CCACHE ./compiler.sh -c test1.c 2>/dev/null
+ if [ "$?" -eq 0 ]; then
+ test_failed "Expected failure running unknown_command to verify compiler but was success"
+ fi
+ expect_stat 'compiler check failed' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_RECACHE should remove previous .stderr"
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ num=`find $CCACHE_DIR -name '*.stderr' | wc -l`
+ if [ $num -ne 0 ]; then
+ test_failed "$num stderr files found, expected 0 (#1)"
+ fi
+
+ obj_file=`find $CCACHE_DIR -name '*.o'`
+ stderr_file=`echo $obj_file | sed 's/..$/.stderr/'`
+ echo "Warning: foo" >$stderr_file
+ CCACHE_RECACHE=1 $CCACHE_COMPILE -c test1.c
+ num=`find $CCACHE_DIR -name '*.stderr' | wc -l`
+ if [ $num -ne 0 ]; then
+ test_failed "$num stderr files found, expected 0 (#2)"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "No object file"
+
+ cat <<'EOF' >test_no_obj.c
+int test_no_obj;
+EOF
+ cat <<'EOF' >prefix-remove.sh
+#!/bin/sh
+"$@"
+[ x$2 = x-fcolor-diagnostics ] && shift
+[ x$2 = x-fdiagnostics-color ] && shift
+[ x$2 = x-std=gnu99 ] && shift
+[ x$3 = x-o ] && rm $4
+EOF
+ chmod +x prefix-remove.sh
+ CCACHE_PREFIX=`pwd`/prefix-remove.sh $CCACHE_COMPILE -c test_no_obj.c
+ expect_stat 'compiler produced no output' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Empty object file"
+
+ cat <<'EOF' >test_empty_obj.c
+int test_empty_obj;
+EOF
+ cat <<'EOF' >prefix-empty.sh
+#!/bin/sh
+"$@"
+[ x$2 = x-fcolor-diagnostics ] && shift
+[ x$2 = x-fdiagnostics-color ] && shift
+[ x$2 = x-std=gnu99 ] && shift
+[ x$3 = x-o ] && cp /dev/null $4
+EOF
+ chmod +x prefix-empty.sh
+ CCACHE_PREFIX=`pwd`/prefix-empty.sh $CCACHE_COMPILE -c test_empty_obj.c
+ expect_stat 'compiler produced empty output' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Caching stderr"
+
+ cat <<EOF >stderr.c
+int stderr(void)
+{
+ // Trigger warning by having no return statement.
+}
+EOF
+ $CCACHE_COMPILE -Wall -W -c stderr.c 2>/dev/null
+ num=`find $CCACHE_DIR -name '*.stderr' | wc -l`
+ if [ $num -ne 1 ]; then
+ test_failed "$num stderr files found, expected 1"
+ fi
+ expect_stat 'files in cache' 2
+
+ # -------------------------------------------------------------------------
+ TEST "--zero-stats"
+
+ $CCACHE_COMPILE -c test1.c
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+
+ $CCACHE -z >/dev/null
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'files in cache' 1
+
+ # -------------------------------------------------------------------------
+ TEST "--clear"
+
+ $CCACHE_COMPILE -c test1.c
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+
+ $CCACHE -C >/dev/null
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 0
+
+ # -------------------------------------------------------------------------
+ TEST "-P"
+
+ # Check that -P disables ccache. (-P removes preprocessor information in
+ # such a way that the object file from compiling the preprocessed file will
+ # not be equal to the object file produced when compiling without ccache.)
+
+ $CCACHE_COMPILE -c -P test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported compiler option' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-P"
+
+ # Check that -Wp,-P disables ccache. (-P removes preprocessor information
+ # in such a way that the object file from compiling the preprocessed file
+ # will not be equal to the object file produced when compiling without
+ # ccache.)
+
+ $CCACHE_COMPILE -c -Wp,-P test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported compiler option' 1
+
+ $CCACHE_COMPILE -c -Wp,-P,-DFOO test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported compiler option' 2
+
+ $CCACHE_COMPILE -c -Wp,-DFOO,-P test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported compiler option' 3
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-D"
+
+ $CCACHE_COMPILE -c -Wp,-DFOO test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c -DFOO test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Buggy GCC 6 cpp"
+
+ cat >buggy-cpp <<EOF
+#!/bin/sh
+export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+if echo "\$*" | grep -- -D >/dev/null; then
+ $COMPILER "\$@"
+else
+ # Mistreat the preprocessor output in the same way as GCC 6 does.
+ $COMPILER "\$@" |
+ sed -e '/^# 1 "<command-line>"\$/ a\\
+# 31 "<command-line>"' \\
+ -e 's/^# 1 "<command-line>" 2\$/# 32 "<command-line>" 2/'
+fi
+exit 0
+EOF
+ cat <<'EOF' >file.c
+int foo;
+EOF
+ chmod +x buggy-cpp
+
+ $CCACHE ./buggy-cpp -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE ./buggy-cpp -DNOT_AFFECTING=1 -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Symlink to source directory"
+
+ mkdir dir
+ cd dir
+ mkdir -p d1/d2
+ echo '#define A "OK"' >d1/h.h
+ cat <<EOF >d1/d2/c.c
+#include <stdio.h>
+#include "../h.h"
+int main() { printf("%s\n", A); }
+EOF
+ echo '#define A "BUG"' >h.h
+ ln -s d1/d2 d3
+
+ CCACHE_BASEDIR=/ $CCACHE_COMPILE -c $PWD/d3/c.c
+ $UNCACHED_COMPILE c.o -o c
+ if [ "$(./c)" != OK ]; then
+ test_failed "Incorrect header file used"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "Symlink to source file"
+
+ mkdir dir
+ cd dir
+ mkdir d
+ echo '#define A "BUG"' >d/h.h
+ cat <<EOF >d/c.c
+#include <stdio.h>
+#include "h.h"
+int main() { printf("%s\n", A); }
+EOF
+ echo '#define A "OK"' >h.h
+ ln -s d/c.c c.c
+
+ CCACHE_BASEDIR=/ $CCACHE_COMPILE -c $PWD/c.c
+ $UNCACHED_COMPILE c.o -o c
+ if [ "$(./c)" != OK ]; then
+ test_failed "Incorrect header file used"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST ".incbin"
+
+ cat <<EOF >incbin.c
+char x[] = ".incbin";
+EOF
+
+ $CCACHE_COMPILE -c incbin.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'unsupported code directive' 1
+}
+
+# =============================================================================
+
+SUITE_base_SETUP() {
+ generate_code 1 test1.c
+}
+
+SUITE_base() {
+ base_tests
+}
+
+# =============================================================================
+
+SUITE_nocpp2_SETUP() {
+ export CCACHE_NOCPP2=1
+ generate_code 1 test1.c
+}
+
+SUITE_nocpp2() {
+ base_tests
+}
+
+# =============================================================================
+
+SUITE_multi_arch_PROBE() {
+ if ! $HOST_OS_APPLE; then
+ echo "multiple -arch options not supported on $(uname -s)"
+ return
+ fi
+}
+
+SUITE_multi_arch_SETUP() {
+ generate_code 1 test1.c
+ unset CCACHE_NODIRECT
+}
+
+SUITE_multi_arch() {
+ # -------------------------------------------------------------------------
+ TEST "cache hit, direct mode"
+
+ # Different arches shouldn't affect each other
+ $CCACHE_COMPILE -arch i386 -c test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -arch x86_64 -c test1.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache miss' 2
+
+ $CCACHE_COMPILE -arch i386 -c test1.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache miss' 2
+
+ # Multiple arches should be cached too
+ $CCACHE_COMPILE -arch i386 -arch x86_64 -c test1.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache miss' 3
+
+ $CCACHE_COMPILE -arch i386 -arch x86_64 -c test1.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache miss' 3
+
+ # -------------------------------------------------------------------------
+ TEST "cache hit, preprocessor mode"
+
+ export CCACHE_NODIRECT=1
+
+ $CCACHE_COMPILE -arch i386 -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -arch x86_64 -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ $CCACHE_COMPILE -arch i386 -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ # Multiple arches should be cached too
+ $CCACHE_COMPILE -arch i386 -arch x86_64 -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 3
+
+ $CCACHE_COMPILE -arch i386 -arch x86_64 -c test1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 3
+}
+
+# =============================================================================
+
+SUITE_serialize_diagnostics_PROBE() {
+ touch test.c
+ if ! $UNCACHED_COMPILE -c --serialize-diagnostics \
+ test1.dia test.c 2>/dev/null; then
+ echo "--serialize-diagnostics not supported by compiler"
+ fi
+}
+
+SUITE_serialize_diagnostics_SETUP() {
+ generate_code 1 test1.c
+}
+
+SUITE_serialize_diagnostics() {
+ # -------------------------------------------------------------------------
+ TEST "Compile OK"
+
+ $UNCACHED_COMPILE -c --serialize-diagnostics expected.dia test1.c
+
+ $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ expect_equal_files expected.dia test.dia
+
+ rm test.dia
+
+ $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ expect_equal_files expected.dia test.dia
+
+ # -------------------------------------------------------------------------
+ TEST "Compile failed"
+
+ echo "bad source" >error.c
+ if $UNCACHED_COMPILE -c --serialize-diagnostics expected.dia error.c 2>expected.stderr; then
+ test_failed "Expected an error compiling error.c"
+ fi
+
+ $CCACHE_COMPILE -c --serialize-diagnostics test.dia error.c 2>test.stderr
+ expect_stat 'compile failed' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat 'files in cache' 0
+ expect_equal_files expected.dia test.dia
+ expect_equal_files expected.stderr test.stderr
+
+ # -------------------------------------------------------------------------
+ TEST "--serialize-diagnostics + CCACHE_BASEDIR"
+
+ mkdir -p dir1/src dir1/include
+ cat <<EOF >dir1/src/test.c
+#include <stdarg.h>
+#include <test.h>
+EOF
+ cat <<EOF >dir1/include/test.h
+int test;
+EOF
+ cp -r dir1 dir2
+ backdate dir1/include/test.h dir2/include/test.h
+
+ cat <<EOF >stderr.h
+int stderr(void)
+{
+ // Trigger warning by having no return statement.
+}
+EOF
+
+ unset CCACHE_NODIRECT
+
+ cd dir1
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -w -MD -MF `pwd`/test.d -I`pwd`/include --serialize-diagnostics `pwd`/test.dia -c src/test.c -o `pwd`/test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 4
+
+ cd ../dir2
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -w -MD -MF `pwd`/test.d -I`pwd`/include --serialize-diagnostics `pwd`/test.dia -c src/test.c -o `pwd`/test.o
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 4
+}
+
+# =============================================================================
+
+SUITE_debug_prefix_map_PROBE() {
+ if ! $COMPILER_TYPE_GCC || $COMPILER_USES_MINGW; then
+ echo "-fdebug-prefix-map not supported by compiler"
+ fi
+}
+
+SUITE_debug_prefix_map_SETUP() {
+ unset CCACHE_NODIRECT
+
+ mkdir -p dir1/src dir1/include
+ cat <<EOF >dir1/src/test.c
+#include <stdarg.h>
+#include <test.h>
+EOF
+ cat <<EOF >dir1/include/test.h
+int test;
+EOF
+ cp -r dir1 dir2
+ backdate dir1/include/test.h dir2/include/test.h
+}
+
+SUITE_debug_prefix_map() {
+ # -------------------------------------------------------------------------
+ TEST "Mapping of debug info CWD"
+
+ cd dir1
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -I`pwd`/include -g -fdebug-prefix-map=`pwd`=dir -c `pwd`/src/test.c -o `pwd`/test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ if grep -E "[^=]`pwd`[^=]" test.o >/dev/null 2>&1; then
+ test_failed "Source dir (`pwd`) found in test.o"
+ fi
+
+ cd ../dir2
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -I`pwd`/include -g -fdebug-prefix-map=`pwd`=dir -c `pwd`/src/test.c -o `pwd`/test.o
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ if grep -E "[^=]`pwd`[^=]" test.o >/dev/null 2>&1; then
+ test_failed "Source dir (`pwd`) found in test.o"
+ fi
+}
+
+# =============================================================================
+
+SUITE_masquerading_PROBE() {
+ local compiler_binary=$(echo $COMPILER | cut -d' ' -f1)
+ if [ "$(dirname $compiler_binary)" != . ]; then
+ echo "compiler ($compiler_binary) not taken from PATH"
+ fi
+}
+
+SUITE_masquerading_SETUP() {
+ local compiler_binary=$(echo $COMPILER | cut -d' ' -f1)
+ local compiler_args=$(echo $COMPILER | cut -s -d' ' -f2-)
+
+ ln -s "$CCACHE" $compiler_binary
+ CCACHE_COMPILE="./$compiler_binary $compiler_args"
+ generate_code 1 test1.c
+}
+
+SUITE_masquerading() {
+ # -------------------------------------------------------------------------
+ TEST "Masquerading via symlink"
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+}
+
+# =============================================================================
+
+SUITE_hardlink_PROBE() {
+ touch file1
+ if ! ln file1 file2 >/dev/null 2>&1; then
+ echo "file system doesn't support hardlinks"
+ fi
+}
+
+SUITE_hardlink() {
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_HARDLINK"
+
+ generate_code 1 test1.c
+
+ $UNCACHED_COMPILE -c -o reference_test1.o test1.c
+
+ $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+
+ CCACHE_HARDLINK=1 $CCACHE_COMPILE -c test1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 1
+ expect_equal_object_files reference_test1.o test1.o
+
+ local obj_in_cache=$(find $CCACHE_DIR -name '*.o')
+ if [ ! $obj_in_cache -ef test1.o ]; then
+ test_failed "Object file not hard-linked to cached object file"
+ fi
+}
+
+# =============================================================================
+
+SUITE_direct_SETUP() {
+ unset CCACHE_NODIRECT
+
+ cat <<EOF >test.c
+// test.c
+#include "test1.h"
+#include "test2.h"
+EOF
+ cat <<EOF >test1.h
+#include "test3.h"
+int test1;
+EOF
+ cat <<EOF >test2.h
+int test2;
+EOF
+ cat <<EOF >test3.h
+int test3;
+EOF
+ backdate test1.h test2.h test3.h
+
+ $UNCACHED_COMPILE -c -Wp,-MD,expected.d test.c
+ $UNCACHED_COMPILE -c -Wp,-MMD,expected_mmd.d test.c
+ rm test.o
+}
+
+SUITE_direct() {
+ # -------------------------------------------------------------------------
+ TEST "Base case"
+
+ $UNCACHED_COMPILE -c -o reference_test.o test.c
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2 # .o + .manifest
+ expect_equal_object_files reference_test.o test.o
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_stat 'files in cache' 2
+ expect_equal_object_files reference_test.o test.o
+
+ # -------------------------------------------------------------------------
+ TEST "Corrupt manifest file"
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ manifest_file=`find $CCACHE_DIR -name '*.manifest'`
+ rm $manifest_file
+ touch $manifest_file
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_NODIRECT"
+
+ CCACHE_NODIRECT=1 $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Modified include file"
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo "int test3_2;" >>test3.h
+ backdate test3.h
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Removed but previously compiled header file"
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ rm test3.h
+ cat <<EOF >test1.h
+// No more include of test3.h
+int test1;
+EOF
+ backdate test1.h
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Calculation of dependency file names"
+
+ mkdir test.dir
+ for ext in .obj "" . .foo.bar; do
+ dep_file=test.dir/`echo test$ext | sed 's/\.[^.]*\$//'`.d
+ $CCACHE_COMPILE -MD -c test.c -o test.dir/test$ext
+ rm -f $dep_file
+ $CCACHE_COMPILE -MD -c test.c -o test.dir/test$ext
+ if [ ! -f $dep_file ]; then
+ test_failed "$dep_file missing"
+ fi
+ done
+ expect_stat 'files in cache' 12
+
+ # -------------------------------------------------------------------------
+ TEST "-MMD for different source files"
+
+ mkdir a b
+ touch a/source.c b/source.c
+ backdate a/source.h b/source.h
+ $CCACHE_COMPILE -MMD -c a/source.c
+ expect_file_content source.d "source.o: a/source.c"
+
+ $CCACHE_COMPILE -MMD -c b/source.c
+ expect_file_content source.d "source.o: b/source.c"
+
+ $CCACHE_COMPILE -MMD -c a/source.c
+ expect_file_content source.d "source.o: a/source.c"
+
+ # -------------------------------------------------------------------------
+ TEST "-MMD for different include file paths"
+
+ mkdir a b
+ touch a/source.h b/source.h
+ backdate a/source.h b/source.h
+ echo '#include <source.h>' >source.c
+ $CCACHE_COMPILE -MMD -Ia -c source.c
+ expect_file_content source.d "source.o: source.c a/source.h"
+
+ $CCACHE_COMPILE -MMD -Ib -c source.c
+ expect_file_content source.d "source.o: source.c b/source.h"
+
+ $CCACHE_COMPILE -MMD -Ia -c source.c
+ expect_file_content source.d "source.o: source.c a/source.h"
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-MD"
+
+ $CCACHE_COMPILE -c -Wp,-MD,other.d test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected.d
+
+ $UNCACHED_COMPILE -c -Wp,-MD,other.d test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
+
+ rm -f other.d
+ $CCACHE_COMPILE -c -Wp,-MD,other.d test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ $CCACHE_COMPILE -c -Wp,-MD,different_name.d test.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files different_name.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-MMD"
+
+ $CCACHE_COMPILE -c -Wp,-MMD,other.d test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected_mmd.d
+
+ $UNCACHED_COMPILE -c -Wp,-MMD,other.d test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
+
+ rm -f other.d
+ $CCACHE_COMPILE -c -Wp,-MMD,other.d test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected_mmd.d
+ expect_equal_object_files reference_test.o test.o
+
+ $CCACHE_COMPILE -c -Wp,-MMD,different_name.d test.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files different_name.d expected_mmd.d
+ expect_equal_object_files reference_test.o test.o
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp,-D"
+
+ $CCACHE_COMPILE -c -Wp,-DFOO test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c -DFOO test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "-Wp, with multiple arguments"
+
+ # ccache could try to parse and make sense of -Wp, with multiple arguments,
+ # but it currently doesn't, so we have to disable direct mode.
+
+ touch source.c
+
+ $CCACHE_COMPILE -c -Wp,-MMD,source.d,-MT,source.o source.c 2>/dev/null
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_file_content source.d "source.o: source.c"
+
+ $CCACHE_COMPILE -c -Wp,-MMD,source.d,-MT,source.o source.c 2>/dev/null
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_file_content source.d "source.o: source.c"
+
+ # -------------------------------------------------------------------------
+ TEST "-MMD for different source files"
+
+ mkdir a b
+ touch a/source.c b/source.c
+ $CCACHE_COMPILE -MMD -c a/source.c
+ expect_file_content source.d "source.o: a/source.c"
+
+ $CCACHE_COMPILE -MMD -c b/source.c
+ expect_file_content source.d "source.o: b/source.c"
+
+ $CCACHE_COMPILE -MMD -c a/source.c
+ expect_file_content source.d "source.o: a/source.c"
+
+ # -------------------------------------------------------------------------
+ TEST "Multiple object entries in manifest"
+
+ for i in 0 1 2 3 4; do
+ echo "int test1_$i;" >>test1.h
+ backdate test1.h
+ $CCACHE_COMPILE -c test.c
+ $CCACHE_COMPILE -c test.c
+ done
+ expect_stat 'cache hit (direct)' 5
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 5
+
+ # -------------------------------------------------------------------------
+ TEST "-MD"
+
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+
+ $UNCACHED_COMPILE -c -MD test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
+
+ rm -f test.d
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ # -------------------------------------------------------------------------
+ TEST "-ftest-coverage"
+
+ cat <<EOF >code.c
+int test() { return 0; }
+EOF
+
+ $CCACHE_COMPILE -c -fprofile-arcs -ftest-coverage code.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ test -r code.gcno || test_failed "code.gcno missing"
+
+ rm code.gcno
+
+ $CCACHE_COMPILE -c -fprofile-arcs -ftest-coverage code.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ test -r code.gcno || test_failed "code.gcno missing"
+
+ # -------------------------------------------------------------------------
+ TEST "Direct mode on cache created by ccache without direct mode support"
+
+ CCACHE_NODIRECT=1 $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ $UNCACHED_COMPILE -c -MD test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
+
+ rm -f test.d
+
+ CCACHE_NODIRECT=1 $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ rm -f test.d
+
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ rm -f test.d
+
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ # -------------------------------------------------------------------------
+ TEST "-MF"
+
+ $CCACHE_COMPILE -c -MD -MF other.d test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected.d
+ $UNCACHED_COMPILE -c -MD -MF other.d test.c -o reference_test.o
+ expect_equal_object_files reference_test.o test.o
+
+ rm -f other.d
+
+ $CCACHE_COMPILE -c -MD -MF other.d test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files other.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ $CCACHE_COMPILE -c -MD -MF different_name.d test.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files different_name.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ rm -f different_name.d
+
+ $CCACHE_COMPILE -c -MD -MFthird_name.d test.c
+ expect_stat 'cache hit (direct)' 3
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files third_name.d expected.d
+ expect_equal_object_files reference_test.o test.o
+
+ rm -f third_name.d
+
+ # -------------------------------------------------------------------------
+ TEST "Missing .d file"
+
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+
+ find $CCACHE_DIR -name '*.d' -delete
+
+ $CCACHE_COMPILE -c -MD test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_equal_files test.d expected.d
+
+ # -------------------------------------------------------------------------
+ TEST "stderr from both preprocessor and compiler"
+
+ cat <<EOF >cpp-warning.c
+#if FOO
+// Trigger preprocessor warning about extra token after #endif.
+#endif FOO
+int stderr(void)
+{
+ // Trigger compiler warning by having no return statement.
+}
+EOF
+ $CCACHE_COMPILE -Wall -W -c cpp-warning.c 2>stderr-orig.txt
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 $CCACHE_COMPILE -Wall -W -c cpp-warning.c 2>stderr-cpp.txt
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_file_content stderr-cpp.txt "`cat stderr-orig.txt`"
+
+ $CCACHE_COMPILE -Wall -W -c cpp-warning.c 2>stderr-mf.txt
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+ expect_file_content stderr-mf.txt "`cat stderr-orig.txt`"
+
+ # -------------------------------------------------------------------------
+ TEST "Empty source file"
+
+ touch empty.c
+
+ $CCACHE_COMPILE -c empty.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c empty.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Empty include file"
+
+ touch empty.h
+ cat <<EOF >include_empty.c
+#include "empty.h"
+EOF
+ backdate empty.h
+ $CCACHE_COMPILE -c include_empty.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ $CCACHE_COMPILE -c include_empty.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__FILE__ in source file disables direct mode"
+
+ cat <<EOF >file.c
+#define file __FILE__
+int test;
+EOF
+
+ $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c `pwd`/file.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "__FILE__ in include file disables direct mode"
+
+ cat <<EOF >file.h
+#define file __FILE__
+int test;
+EOF
+ backdate file.h
+ cat <<EOF >file_h.c
+#include "file.h"
+EOF
+
+ $CCACHE_COMPILE -c file_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c file_h.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ mv file_h.c file2_h.c
+
+ $CCACHE_COMPILE -c `pwd`/file2_h.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "__FILE__ in source file ignored if sloppy"
+
+ cat <<EOF >file.c
+#define file __FILE__
+int test;
+EOF
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c file.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c `pwd`/file.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__FILE__ in include file ignored if sloppy"
+
+ cat <<EOF >file.h
+#define file __FILE__
+int test;
+EOF
+ backdate file.h
+ cat <<EOF >file_h.c
+#include "file.h"
+EOF
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c file_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c file_h.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ mv file_h.c file2_h.c
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS file_macro" $CCACHE_COMPILE -c `pwd`/file2_h.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__TIME__ in source file disables direct mode"
+
+ cat <<EOF >time.c
+#define time __TIME__
+int test;
+EOF
+
+ $CCACHE_COMPILE -c time.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c time.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__TIME__ in include file disables direct mode"
+
+ cat <<EOF >time.h
+#define time __TIME__
+int test;
+EOF
+ backdate time.h
+
+ cat <<EOF >time_h.c
+#include "time.h"
+EOF
+
+ $CCACHE_COMPILE -c time_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c time_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__TIME__ in source file ignored if sloppy"
+
+ cat <<EOF >time.c
+#define time __TIME__
+int test;
+EOF
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE -c time.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE -c time.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "__TIME__ in include file ignored if sloppy"
+
+ cat <<EOF >time.h
+#define time __TIME__
+int test;
+EOF
+ backdate time.h
+ cat <<EOF >time_h.c
+#include "time.h"
+EOF
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE -c time_h.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE -c time_h.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Too new include file disables direct mode"
+
+ cat <<EOF >new.c
+#include "new.h"
+EOF
+ cat <<EOF >new.h
+int test;
+EOF
+ touch -t 203801010000 new.h
+
+ $CCACHE_COMPILE -c new.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c new.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "New include file ignored if sloppy"
+
+ cat <<EOF >new.c
+#include "new.h"
+EOF
+ cat <<EOF >new.h
+int test;
+EOF
+ touch -t 203801010000 new.h
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c new.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c new.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ # Check that environment variables that affect the preprocessor are taken
+ # into account.
+ TEST "CPATH included in hash"
+
+ rm -rf subdir1 subdir2
+ mkdir subdir1 subdir2
+ cat <<EOF >subdir1/foo.h
+int foo;
+EOF
+ cat <<EOF >subdir2/foo.h
+int foo;
+EOF
+ cat <<EOF >foo.c
+#include <foo.h>
+EOF
+ backdate subdir1/foo.h subdir2/foo.h
+
+ CPATH=subdir1 $CCACHE_COMPILE -c foo.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CPATH=subdir1 $CCACHE_COMPILE -c foo.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CPATH=subdir2 $CCACHE_COMPILE -c foo.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2 # subdir2 is part of the preprocessor output
+
+ CPATH=subdir2 $CCACHE_COMPILE -c foo.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Comment in strings"
+
+ echo 'char *comment = " /* \\\\u" "foo" " */";' >comment.c
+
+ $CCACHE_COMPILE -c comment.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c comment.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo 'char *comment = " /* \\\\u" "goo" " */";' >comment.c
+
+ $CCACHE_COMPILE -c comment.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "#line directives with troublesome files"
+
+ cat <<EOF >strange.c
+int foo;
+EOF
+ for x in stdout tty sda hda; do
+ if [ -b /dev/$x ] || [ -c /dev/$x ]; then
+ echo "#line 1 \"/dev/$x\"" >>strange.c
+ fi
+ done
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c strange.c
+
+ manifest=`find $CCACHE_DIR -name '*.manifest'`
+ if [ -n "$manifest" ]; then
+ data="`$CCACHE --dump-manifest $manifest | egrep '/dev/(stdout|tty|sda|hda'`"
+ if [ -n "$data" ]; then
+ test_failed "$manifest contained troublesome file(s): $data"
+ fi
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "--dump-manifest"
+
+ $CCACHE_COMPILE test.c -c -o test.o
+
+ manifest=`find $CCACHE_DIR -name '*.manifest'`
+ $CCACHE --dump-manifest $manifest >manifest.dump
+
+ if grep 'Hash: d4de2f956b4a386c6660990a7a1ab13f' manifest.dump >/dev/null 2>&1 && \
+ grep 'Hash: e94ceb9f1b196c387d098a5f1f4fe862' manifest.dump >/dev/null 2>&1 && \
+ grep 'Hash: ba753bebf9b5eb99524bb7447095e2e6' manifest.dump >/dev/null 2>&1; then
+ : OK
+ else
+ test_failed "Unexpected output of --dump-manifest"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "Argument-less -B and -L"
+
+ cat <<EOF >test.c
+#include <stdio.h>
+int main(void)
+{
+#ifdef FOO
+ puts("FOO");
+#endif
+ return 0;
+}
+EOF
+
+ $CCACHE_COMPILE -B -L -DFOO -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -B -L -DBAR -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_IGNOREHEADERS"
+
+ cat <<EOF >ignore.h
+// We don't want this header in the manifest.
+EOF
+ backdate ignore.h
+ cat <<EOF >ignore.c
+#include "ignore.h"
+int foo;
+EOF
+
+ CCACHE_IGNOREHEADERS="ignore.h" $CCACHE_COMPILE -c ignore.c
+ manifest=`find $CCACHE_DIR -name '*.manifest'`
+ data="`$CCACHE --dump-manifest $manifest | grep ignore.h`"
+ if [ -n "$data" ]; then
+ test_failed "$manifest contained ignored header: $data"
+ fi
+}
+
+# =============================================================================
+
+SUITE_basedir_SETUP() {
+ unset CCACHE_NODIRECT
+
+ mkdir -p dir1/src dir1/include
+ cat <<EOF >dir1/src/test.c
+#include <stdarg.h>
+#include <test.h>
+EOF
+ cat <<EOF >dir1/include/test.h
+int test;
+EOF
+ cp -r dir1 dir2
+ backdate dir1/include/test.h dir2/include/test.h
+}
+
+SUITE_basedir() {
+ # -------------------------------------------------------------------------
+ TEST "Enabled CCACHE_BASEDIR"
+
+ cd dir1
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ cd ../dir2
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Disabled (default) CCACHE_BASEDIR"
+
+ cd dir1
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # CCACHE_BASEDIR="" is the default:
+ $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Path normalization"
+
+ cd dir1
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # Rewriting triggered by CCACHE_BASEDIR should handle paths with multiple
+ # slashes correctly:
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -I`pwd`//include -c `pwd`//src/test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Rewriting in stderr"
+
+ cat <<EOF >stderr.h
+int stderr(void)
+{
+ // Trigger warning by having no return statement.
+}
+EOF
+ backdate stderr.h
+ cat <<EOF >stderr.c
+#include <stderr.h>
+EOF
+
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -Wall -W -I`pwd` -c `pwd`/stderr.c -o `pwd`/stderr.o 2>stderr.txt
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ if grep `pwd` stderr.txt >/dev/null 2>&1; then
+ test_failed "Base dir (`pwd`) found in stderr:\n`cat stderr.txt`"
+ fi
+
+ CCACHE_BASEDIR=`pwd` $CCACHE_COMPILE -Wall -W -I`pwd` -c `pwd`/stderr.c -o `pwd`/stderr.o 2>stderr.txt
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ if grep `pwd` stderr.txt >/dev/null 2>&1; then
+ test_failed "Base dir (`pwd`) found in stderr:\n`cat stderr.txt`"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "-MF/-MQ/-MT with absolute paths"
+
+ for option in MF "MF " MQ "MQ " MT "MT "; do
+ clear_cache
+ cd dir1
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ cd ..
+
+ cd dir2
+ CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ cd ..
+ done
+
+ # -------------------------------------------------------------------------
+ # When BASEDIR is set to /, check that -MF, -MQ and -MT arguments with
+ # absolute paths are rewritten to relative and that the dependency file
+ # only contains relative paths.
+ TEST "-MF/-MQ/-MT with absolute paths and BASEDIR set to /"
+
+ for option in MF "MF " MQ "MQ " MT "MT "; do
+ clear_cache
+ cd dir1
+ CCACHE_BASEDIR="/" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ # Check that there is no absolute path in the dependency file:
+ while read line; do
+ for file in $line; do
+ case $file in /*)
+ test_failed "Absolute file path '$file' found in dependency file '`pwd`/test.d'"
+ esac
+ done
+ done <test.d
+ cd ..
+
+ cd dir2
+ CCACHE_BASEDIR="/" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ cd ..
+ done
+}
+
+# =============================================================================
+
+SUITE_compression_SETUP() {
+ generate_code 1 test.c
+}
+
+SUITE_compression() {
+ # -------------------------------------------------------------------------
+ TEST "Hash sum equal for compressed and uncompressed files"
+
+ CCACHE_COMPRESS=1 $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_COMPRESS=1 $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 1
+}
+
+# =============================================================================
+
+SUITE_readonly_SETUP() {
+ generate_code 1 test.c
+ generate_code 2 test2.c
+}
+
+SUITE_readonly() {
+ # -------------------------------------------------------------------------
+ TEST "Cache hit"
+
+ # Cache a compilation.
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm test.o
+
+ # Make the cache read-only.
+ chmod -R a-w $CCACHE_DIR
+
+ # Check that read-only mode finds the cached result.
+ CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp CCACHE_PREFIX=false $CCACHE_COMPILE -c test.c
+ status1=$?
+
+ # Check that fallback to the real compiler works for a cache miss.
+ CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE_COMPILE -c test2.c
+ status2=$?
+
+ # Leave test dir a nice state after test failure.
+ chmod -R +w $CCACHE_DIR
+
+ if [ $status1 -ne 0 ]; then
+ test_failed "Failure when compiling test.c read-only"
+ fi
+ if [ $status2 -ne 0 ]; then
+ test_failed "Failure when compiling test2.c read-only"
+ fi
+ if [ ! -f test.o ]; then
+ test_failed "test.o missing"
+ fi
+ if [ ! -f test2.o ]; then
+ test_failed "test2.o missing"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "Cache miss"
+
+ # Check that read-only mode doesn't try to store new results.
+ CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE_COMPILE -c test.c
+ if [ $? -ne 0 ]; then
+ test_failed "Failure when compiling test2.c read-only"
+ fi
+ if [ -d $CCACHE_DIR ]; then
+ test_failed "ccache dir was created"
+ fi
+
+ # -------------------------------------------------------------------------
+ # Check that read-only mode and direct mode work together.
+ TEST "Cache hit, direct"
+
+ # Cache a compilation.
+ $CCACHE_COMPILE -c test.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm test.o
+
+ # Make the cache read-only.
+ chmod -R a-w $CCACHE_DIR
+
+ # Direct mode should work:
+ files_before=`find $CCACHE_DIR -type f | wc -l`
+ CCACHE_DIRECT=1 CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE_COMPILE -c test.c
+ files_after=`find $CCACHE_DIR -type f | wc -l`
+
+ # Leave test dir a nice state after test failure.
+ chmod -R +w $CCACHE_DIR
+
+ if [ $? -ne 0 ]; then
+ test_failed "Failure when compiling test.c read-only"
+ fi
+ if [ $files_after -ne $files_before ]; then
+ test_failed "Read-only mode + direct mode stored files in the cache"
+ fi
+}
+
+# =============================================================================
+
+SUITE_readonly_direct_SETUP() {
+ unset CCACHE_NODIRECT
+
+ generate_code 1 test.c
+}
+
+SUITE_readonly_direct() {
+ # -------------------------------------------------------------------------
+ TEST "Direct hit"
+
+ $CCACHE_COMPILE -c test.c -o test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_READONLY_DIRECT=1 $CCACHE_COMPILE -c test.c -o test.o
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Direct miss doesn't lead to preprocessed hit"
+
+ $CCACHE_COMPILE -c test.c -o test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_READONLY_DIRECT=1 $CCACHE_COMPILE -DFOO -c test.c -o test.o
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+}
+
+# =============================================================================
+
+prepare_cleanup_test_dir() {
+ local dir=$1
+
+ rm -rf $dir
+ mkdir -p $dir
+ for i in $(seq 0 9); do
+ printf '%4017s' '' | tr ' ' 'A' >$dir/result$i-4017.o
+ touch $dir/result$i-4017.stderr
+ touch $dir/result$i-4017.d
+ if [ $i -gt 5 ]; then
+ backdate $dir/result$i-4017.stderr
+ fi
+ done
+ # NUMFILES: 30, TOTALSIZE: 40 KiB, MAXFILES: 0, MAXSIZE: 0
+ echo "0 0 0 0 0 0 0 0 0 0 0 30 40 0 0" >$dir/stats
+}
+
+SUITE_cleanup() {
+ # -------------------------------------------------------------------------
+ TEST "Clear cache"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
+ $CCACHE -C >/dev/null
+ expect_file_count 0 '*.o' $CCACHE_DIR
+ expect_file_count 0 '*.d' $CCACHE_DIR
+ expect_file_count 0 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 0
+ expect_stat 'cleanups performed' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Forced cache cleanup, no limits"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
+ $CCACHE -F 0 -M 0 >/dev/null
+ $CCACHE -c >/dev/null
+ expect_file_count 10 '*.o' $CCACHE_DIR
+ expect_file_count 10 '*.d' $CCACHE_DIR
+ expect_file_count 10 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 30
+ expect_stat 'cleanups performed' 0
+
+ # -------------------------------------------------------------------------
+ TEST "Forced cache cleanup, file limit"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
+ # (9/10) * 30 * 16 = 432
+ $CCACHE -F 432 -M 0 >/dev/null
+ $CCACHE -c >/dev/null
+ # floor(0.8 * 9) = 7
+ expect_file_count 7 '*.o' $CCACHE_DIR
+ expect_file_count 7 '*.d' $CCACHE_DIR
+ expect_file_count 7 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 21
+ expect_stat 'cleanups performed' 1
+ for i in 0 1 2 3 4 5 9; do
+ file=$CCACHE_DIR/a/result$i-4017.o
+ if [ ! -f $file ]; then
+ test_failed "File $file removed when it shouldn't"
+ fi
+ done
+ for i in 6 7 8; do
+ file=$CCACHE_DIR/a/result$i-4017.o
+ if [ -f $file ]; then
+ test_failed "File $file not removed when it should"
+ fi
+ done
+
+ # -------------------------------------------------------------------------
+ TEST "Forced cache cleanup, size limit"
+
+ # NOTE: This test is known to fail on filesystems that have unusual block
+ # sizes, including ecryptfs. The workaround is to place the test directory
+ # elsewhere:
+ #
+ # cd /tmp
+ # CCACHE=$DIR/ccache $DIR/test.sh
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
+ # (4/10) * 10 * 4 * 16 = 256
+ $CCACHE -F 0 -M 256K >/dev/null
+ $CCACHE -c >/dev/null
+ # floor(0.8 * 4) = 3
+ expect_file_count 3 '*.o' $CCACHE_DIR
+ expect_file_count 3 '*.d' $CCACHE_DIR
+ expect_file_count 3 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 9
+ expect_stat 'cleanups performed' 1
+ for i in 3 4 5; do
+ file=$CCACHE_DIR/a/result$i-4017.o
+ if [ ! -f $file ]; then
+ test_failed "File $file removed when it shouldn't"
+ fi
+ done
+ for i in 0 1 2 6 7 8 9; do
+ file=$CCACHE_DIR/a/result$i-4017.o
+ if [ -f $file ]; then
+ test_failed "File $file not removed when it should"
+ fi
+ done
+
+ # -------------------------------------------------------------------------
+ TEST "Automatic cache cleanup"
+
+ for x in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
+ prepare_cleanup_test_dir $CCACHE_DIR/$x
+ done
+
+ # (9/10) * 30 * 16 = 432
+ $CCACHE -F 432 -M 0 >/dev/null
+ expect_file_count 160 '*.o' $CCACHE_DIR
+ expect_file_count 160 '*.d' $CCACHE_DIR
+ expect_file_count 160 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 480
+
+ touch empty.c
+ $CCACHE_COMPILE -c empty.c -o empty.o
+ # floor(0.8 * 9) = 7
+ expect_file_count 157 '*.o' $CCACHE_DIR
+ expect_file_count 156 '*.d' $CCACHE_DIR
+ expect_file_count 156 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 469
+ expect_stat 'cleanups performed' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Cleanup of sibling files"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
+ # (9/10) * 30 * 16 = 432
+ $CCACHE -F 432 -M 0 >/dev/null
+ backdate $CCACHE_DIR/a/result2-4017.stderr
+ $CCACHE -c >/dev/null
+ # floor(0.8 * 9) = 7
+ expect_file_count 7 '*.o' $CCACHE_DIR
+ expect_file_count 7 '*.d' $CCACHE_DIR
+ expect_file_count 7 '*.stderr' $CCACHE_DIR
+ expect_stat 'files in cache' 21
+ for i in 0 1 3 4 5 8 9; do
+ file=$CCACHE_DIR/a/result$i-4017.o
+ if [ ! -f $file ]; then
+ test_failed "File $file removed when it shouldn't"
+ fi
+ done
+ for i in 2 6 7; do
+ file=$CCACHE_DIR/a/result$i-4017.o
+ if [ -f $file ]; then
+ test_failed "File $file not removed when it should"
+ fi
+ done
+
+ # -------------------------------------------------------------------------
+ TEST "No cleanup of new unknown file"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
+ touch $CCACHE_DIR/a/abcd.unknown
+ $CCACHE -F 0 -M 0 -c >/dev/null # update counters
+ expect_stat 'files in cache' 31
+ # (9/10) * 30 * 16 = 432
+ $CCACHE -F 432 -M 0 >/dev/null
+ $CCACHE -c >/dev/null
+ if [ ! -f $CCACHE_DIR/a/abcd.unknown ]; then
+ test_failed "$CCACHE_DIR/a/abcd.unknown removed"
+ fi
+ expect_stat 'files in cache' 19
+
+ # -------------------------------------------------------------------------
+ TEST "Cleanup of old unknown file"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+ # (9/10) * 30 * 16 = 432
+ $CCACHE -F 432 -M 0 >/dev/null
+ touch $CCACHE_DIR/a/abcd.unknown
+ backdate $CCACHE_DIR/a/abcd.unknown
+ $CCACHE -c >/dev/null
+ if [ -f $CCACHE_DIR/a/abcd.unknown ]; then
+ test_failed "$CCACHE_DIR/a/abcd.unknown not removed"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "Cleanup of tmp file"
+
+ mkdir -p $CCACHE_DIR/a
+ touch $CCACHE_DIR/a/abcd.tmp.efgh
+ $CCACHE -c >/dev/null # update counters
+ expect_stat 'files in cache' 1
+ backdate $CCACHE_DIR/a/abcd.tmp.efgh
+ $CCACHE -c >/dev/null
+ if [ -f $CCACHE_DIR/a/abcd.tmp.efgh ]; then
+ test_failed "$CCACHE_DIR/a/abcd.tmp.unknown not removed"
+ fi
+ expect_stat 'files in cache' 0
+
+ # -------------------------------------------------------------------------
+ TEST "No cleanup of .nfs* files"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
+ touch $CCACHE_DIR/a/.nfs0123456789
+ $CCACHE -F 0 -M 0 >/dev/null
+ $CCACHE -c >/dev/null
+ expect_file_count 1 '.nfs*' $CCACHE_DIR
+ expect_stat 'files in cache' 30
+
+ # -------------------------------------------------------------------------
+ TEST "CCACHE_LIMIT_MULTIPLE"
+
+ prepare_cleanup_test_dir $CCACHE_DIR/a
+
+ # (1/1) * 30 * 16 = 480
+ $CCACHE -F 480 >/dev/null
+ CCACHE_LIMIT_MULTIPLE=0.5 $CCACHE -c >/dev/null
+ expect_stat 'files in cache' 15
+}
+
+# =============================================================================
+
+SUITE_pch_PROBE() {
+ touch pch.h
+ if ! $UNCACHED_COMPILE $SYSROOT -fpch-preprocess pch.h 2>/dev/null \
+ || [ ! -f pch.h.gch ]; then
+ echo "compiler ($($COMPILER --version | head -1)) doesn't support precompiled headers"
+ fi
+}
+
+SUITE_pch_SETUP() {
+ unset CCACHE_NODIRECT
+
+ cat <<EOF >pch.c
+#include "pch.h"
+int main()
+{
+ void *p = NULL;
+ return 0;
+}
+EOF
+ cat <<EOF >pch.h
+#include <stdlib.h>
+EOF
+ backdate pch.h
+ cat <<EOF >pch2.c
+int main()
+{
+ void *p = NULL;
+ return 0;
+}
+EOF
+}
+
+SUITE_pch() {
+ # Clang and GCC handle precompiled headers similarly, but GCC is much more
+ # forgiving with precompiled headers. Both GCC and Clang keep an absolute
+ # path reference to the original file except that Clang uses that reference
+ # to validate the pch and GCC ignores the reference. Also, Clang has an
+ # additional feature: pre-tokenized headers. For these reasons, Clang
+ # should be tested differently from GCC. Clang can only use pch or pth
+ # headers on the command line and not as an #include statement inside a
+ # source file.
+
+ if $COMPILER_TYPE_CLANG; then
+ pch_suite_clang
+ else
+ pch_suite_gcc
+ fi
+}
+
+pch_suite_gcc() {
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, -c, no -o, without opt-in"
+
+ $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, no -c, -o, without opt-in"
+
+ $CCACHE_COMPILE pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, -c, no -o, with opt-in"
+
+ CCACHE_SLOPPINESS=pch_defines $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm pch.h.gch
+
+ CCACHE_SLOPPINESS=pch_defines $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ if [ ! -f pch.h.gch ]; then
+ test_failed "pch.h.gch missing"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, no -c, -o, with opt-in"
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ if [ ! -f pch.gch ]; then
+ test_failed "pch.gch missing"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, #include"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ $CCACHE_COMPILE $SYSROOT -c pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ # Preprocessor error because GCC can't find the real include file when
+ # trying to preprocess:
+ expect_stat 'preprocessor error' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, -include, no sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ # Must enable sloppy time macros:
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, -include, sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, -fpch-preprocess, #include, no sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ # Must enable sloppy time macros:
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, -fpch-preprocess, #include, sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, -fpch-preprocess, #include, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo "updated" >>pch.h.gch # GCC seems to cope with this...
+ backdate pch.h.gch
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, preprocessor mode"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, preprocessor mode, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+ rm pch.h
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo "updated" >>pch.h.gch # GCC seems to cope with this...
+ backdate pch.h.gch
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+}
+
+pch_suite_clang() {
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, -c, no -o, without opt-in"
+
+ $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, no -c, -o, without opt-in"
+
+ $CCACHE_COMPILE pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, -c, no -o, with opt-in"
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm pch.h.gch
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT -c pch.h
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ if [ ! -f pch.h.gch ]; then
+ test_failed "pch.h.gch missing"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "Create .gch, no -c, -o, with opt-in"
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT pch.h -o pch.gch
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ if [ ! -f pch.gch ]; then
+ test_failed "pch.gch missing"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, -include, no sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+
+ $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c 2>/dev/null
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ # Must enable sloppy time macros:
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, no -fpch-preprocess, -include, sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, -fpch-preprocess, -include, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo "updated" >>pch.h.gch # clang seems to cope with this...
+ backdate pch.h.gch
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, preprocessor mode"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .gch, preprocessor mode, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h
+ backdate pch.h.gch
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo "updated" >>pch.h.gch # clang seems to cope with this...
+ backdate pch.h.gch
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Create .pth, -c, -o"
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm -f pch.h.pth
+
+ CCACHE_SLOPPINESS=pch_defines,time_macros $CCACHE_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ if [ ! -f pch.h.pth ]; then
+ test_failed "pch.h.pth missing"
+ fi
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, no -fpch-preprocess, -include, no sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ backdate pch.h.pth
+
+ $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 0
+ # Must enable sloppy time macros:
+ expect_stat "can't use precompiled header" 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, no -fpch-preprocess, -include, sloppiness"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ backdate pch.h.pth
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h pch2.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, -fpch-preprocess, -include, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ backdate pch.h.pth
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo "updated" >>pch.h.pth # clang seems to cope with this...
+ backdate pch.h.pth
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, preprocessor mode"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ backdate pch.h.pth
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pth, preprocessor mode, file changed"
+
+ $UNCACHED_COMPILE $SYSROOT -c pch.h -o pch.h.pth
+ backdate pch.h.pth
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo "updated" >>pch.h.pth # clang seems to cope with this...
+ backdate pch.h.pth
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_NODIRECT=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -include pch.h -fpch-preprocess pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+}
+
+# =============================================================================
+
+SUITE_upgrade() {
+ TEST "Keep maxfiles and maxsize settings"
+
+ rm $CCACHE_CONFIGPATH
+ mkdir -p $CCACHE_DIR/0
+ echo "0 0 0 0 0 0 0 0 0 0 0 0 0 2000 131072" >$CCACHE_DIR/0/stats
+ expect_stat 'max files' 32000
+ expect_stat 'max cache size' '2.1 GB'
+}
+
+# =============================================================================
+
+SUITE_input_charset_PROBE() {
+ touch test.c
+ if ! $UNCACHED_COMPILE -c -finput-charset=latin1 test.c >/dev/null 2>&1; then
+ echo "compiler doesn't support -finput-charset"
+ fi
+}
+
+SUITE_input_charset() {
+ # -------------------------------------------------------------------------
+ TEST "-finput-charset"
+
+ printf '#include <wchar.h>\nwchar_t foo[] = L"\xbf";\n' >latin1.c
+
+ $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 1
+
+ CCACHE_NOCPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+ expect_stat 'cache hit (preprocessed)' 1
+ expect_stat 'cache miss' 2
+
+ CCACHE_NOCPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c
+ expect_stat 'cache hit (preprocessed)' 2
+ expect_stat 'cache miss' 2
+}
+
+# =============================================================================
+# main program
+
+if pwd | grep '[^A-Za-z0-9/.,=_%+-]' >/dev/null 2>&1; then
+ cat <<EOF
+Error: The test suite doesn't work in directories with whitespace or other
+funny characters in the name. Sorry.
+EOF
+ exit 1
+fi
+
+if [ -n "$CC" ]; then
+ COMPILER="$CC"
+else
+ COMPILER=gcc
+fi
+if [ -z "$CCACHE" ]; then
+ CCACHE=`pwd`/ccache
+fi
+
+COMPILER_TYPE_CLANG=false
+COMPILER_TYPE_GCC=false
+
+COMPILER_USES_LLVM=false
+COMPILER_USES_MINGW=false
+
+HOST_OS_APPLE=false
+HOST_OS_LINUX=false
+HOST_OS_WINDOWS=false
+
+compiler_version="`$COMPILER --version 2>&1 | head -1`"
+case $compiler_version in
+ *gcc*|*g++*|2.95*)
+ COMPILER_TYPE_GCC=true
+ ;;
+ *clang*)
+ COMPILER_TYPE_CLANG=true
+ ;;
+ *)
+ echo "WARNING: Compiler $COMPILER not supported (version: $compiler_version) -- not running tests" >&2
+ exit 0
+ ;;
+esac
+
+case $compiler_version in
+ *llvm*|*LLVM*)
+ COMPILER_USES_LLVM=true
+ ;;
+ *MINGW*|*mingw*)
+ COMPILER_USES_MINGW=true
+ ;;
+esac
+
+case $(uname -s) in
+ *MINGW*|*mingw*)
+ HOST_OS_WINDOWS=true
+ ;;
+ *Darwin*)
+ HOST_OS_APPLE=true
+ ;;
+ *Linux*)
+ HOST_OS_LINUX=true
+ ;;
+esac
+
+if $HOST_OS_WINDOWS; then
+ PATH_DELIM=";"
+else
+ PATH_DELIM=":"
+fi
+
+if $HOST_OS_APPLE; then
+ # Grab the developer directory from the environment or try xcode-select
+ if [ "$XCODE_DEVELOPER_DIR" = "" ]; then
+ XCODE_DEVELOPER_DIR=`xcode-select --print-path`
+ if [ "$XCODE_DEVELOPER_DIR" = "" ]; then
+ echo "Error: XCODE_DEVELOPER_DIR environment variable not set and xcode-select path not set"
+ exit 1
+ fi
+ fi
+
+ # Choose the latest SDK if an SDK root is not set
+ MAC_PLATFORM_DIR=$XCODE_DEVELOPER_DIR/Platforms/MacOSX.platform
+ if [ "$SDKROOT" = "" ]; then
+ SDKROOT="`eval ls -f -1 -d \"$MAC_PLATFORM_DIR/Developer/SDKs/\"*.sdk | tail -1`"
+ if [ "$SDKROOT" = "" ]; then
+ echo "Error: Cannot find a valid SDK root directory"
+ exit 1
+ fi
+ fi
+
+ SYSROOT="-isysroot `echo \"$SDKROOT\" | sed 's/ /\\ /g'`"
+else
+ SYSROOT=
+fi
+
+# ---------------------------------------
+
+TESTDIR=testdir.$$
+ABS_TESTDIR=$PWD/$TESTDIR
+rm -rf $TESTDIR
+mkdir $TESTDIR
+cd $TESTDIR || exit 1
+
+# ---------------------------------------
+
+all_suites="
+base
+nocpp2
+multi_arch
+serialize_diagnostics
+debug_prefix_map
+masquerading
+hardlink
+direct
+basedir
+compression
+readonly
+readonly_direct
+cleanup
+pch
+upgrade
+input_charset
+"
+
+compiler_location=$(which $(echo "$COMPILER" | awk '{print $1}'))
+if [ "$compiler_location" = "$COMPILER" ]; then
+ echo "Compiler: $COMPILER"
+else
+ echo "Compiler: $COMPILER ($compiler_location)"
+fi
+echo "Compiler version: $($COMPILER --version | head -n 1)"
+echo
+
+VERBOSE=false
+[ "$1" = "-v" ] && { VERBOSE=true; shift; }
+
+suites="$*"
+if [ -z "$suites" ]; then
+ suites="$all_suites"
+fi
+
+for suite in $suites; do
+ run_suite $suite
+done
+
+cd /
+rm -rf $ABS_TESTDIR
+green PASSED
+exit 0
diff --git a/test/framework.c b/test/framework.c
new file mode 100644
index 0000000..ccaa785
--- /dev/null
+++ b/test/framework.c
@@ -0,0 +1,301 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "../ccache.h"
+#include "framework.h"
+#include "util.h"
+
+#include <float.h>
+#include <math.h>
+#if defined(HAVE_TERMIOS_H)
+#define USE_COLOR
+#include <termios.h>
+#endif
+
+static unsigned total_asserts;
+static unsigned total_tests;
+static unsigned total_suites;
+static unsigned failed_tests;
+static const char *current_suite;
+static const char *current_test;
+static char *dir_before_suite;
+static char *dir_before_test;
+static int verbose;
+
+static const char COLOR_END[] = "\x1b[m";
+static const char COLOR_GREEN[] = "\x1b[1;32m";
+static const char COLOR_RED[] = "\x1b[1;31m";
+
+#define COLOR(tty, color) ((tty) ? COLOR_ ## color : "")
+
+static int
+is_tty(int fd)
+{
+#ifdef USE_COLOR
+ struct termios t;
+ return tcgetattr(fd, &t) == 0;
+#else
+ (void)fd;
+ return 0;
+#endif
+}
+
+static const char *
+plural_s(unsigned n)
+{
+ return n == 1 ? "" : "s";
+}
+
+int
+cct_run(suite_fn *suites, int verbose_output)
+{
+ suite_fn *suite;
+ int tty = is_tty(1);
+
+ x_unsetenv("GCC_COLORS"); // Avoid confusing argument processing tests.
+ verbose = verbose_output;
+
+ for (suite = suites; *suite; suite++) {
+ unsigned test_index = 0;
+ while (true) {
+ test_index = (*suite)(test_index + 1);
+ if (test_index == 0) {
+ // We have reached the end of the suite.
+ break;
+ }
+ }
+ }
+
+ if (failed_tests == 0) {
+ printf("%sPASSED%s: %u assertion%s, %u test%s, %u suite%s\n",
+ COLOR(tty, GREEN), COLOR(tty, END),
+ total_asserts, plural_s(total_asserts),
+ total_tests, plural_s(total_tests),
+ total_suites, plural_s(total_suites));
+ } else {
+ printf("%sFAILED%s: %u test%s\n",
+ COLOR(tty, RED), COLOR(tty, END),
+ failed_tests, plural_s(failed_tests));
+ }
+ return failed_tests > 0 ? 1 : 0;
+}
+
+void
+cct_suite_begin(const char *name)
+{
+ ++total_suites;
+ if (verbose) {
+ printf("=== SUITE: %s ===\n", name);
+ }
+ dir_before_suite = gnu_getcwd();
+ create_dir(name);
+ cct_chdir(name);
+ current_suite = name;
+}
+
+void
+cct_suite_end()
+{
+ cct_chdir(dir_before_suite);
+ free(dir_before_suite);
+ dir_before_suite = NULL;
+}
+
+void
+cct_test_begin(const char *name)
+{
+ ++total_tests;
+ if (verbose) {
+ printf("--- TEST: %s ---\n", name);
+ }
+ dir_before_test = gnu_getcwd();
+ create_dir(name);
+ cct_chdir(name);
+ current_test = name;
+
+ putenv("CCACHE_CONFIG_PATH=/dev/null");
+ cc_reset();
+}
+
+void
+cct_test_end()
+{
+ if (dir_before_test) {
+ cct_chdir(dir_before_test);
+ free(dir_before_test);
+ dir_before_test = NULL;
+ }
+}
+
+void
+cct_check_passed(const char *file, int line, const char *what)
+{
+ ++total_asserts;
+ if (verbose) {
+ printf("%s:%d: Passed assertion: %s\n", file, line, what);
+ }
+}
+
+void
+cct_check_failed(const char *file, int line, const char *what,
+ const char *expected, const char *actual)
+{
+ ++total_asserts;
+ ++failed_tests;
+ fprintf(stderr, "%s:%d: Failed assertion:\n", file, line);
+ fprintf(stderr, " Suite: %s\n", current_suite);
+ fprintf(stderr, " Test: %s\n", current_test);
+ if (expected) {
+ fprintf(stderr, " Expression: %s\n", what);
+ if (actual) {
+ fprintf(stderr, " Expected: %s\n", expected);
+ fprintf(stderr, " Actual: %s\n", actual);
+ } else {
+ fprintf(stderr, " Message: %s\n", expected);
+ }
+ } else {
+ fprintf(stderr, " Assertion: %s\n", what);
+ }
+ fprintf(stderr, "\n");
+}
+
+bool
+cct_check_float_eq(const char *file, int line, const char *expression,
+ double expected, double actual)
+{
+ if (fabs(expected - actual) < DBL_EPSILON) {
+ cct_check_passed(file, line, expression);
+ return true;
+ } else {
+ char *exp_str = format("%.1f", (double)expected);
+ char *act_str = format("%.1f", (double)actual);
+ cct_check_failed(file, line, expression, exp_str, act_str);
+ free(exp_str);
+ free(act_str);
+ return false;
+ }
+}
+bool
+cct_check_int_eq(const char *file, int line, const char *expression,
+ int64_t expected, int64_t actual)
+{
+ if (expected == actual) {
+ cct_check_passed(file, line, expression);
+ return true;
+ } else {
+#if defined(HAVE_LONG_LONG) && !defined(__MINGW32__)
+ char *exp_str = format("%lld", (long long)expected);
+ char *act_str = format("%lld", (long long)actual);
+#else
+ char *exp_str = format("%ld", (long)expected);
+ char *act_str = format("%ld", (long)actual);
+#endif
+ cct_check_failed(file, line, expression, exp_str, act_str);
+ free(exp_str);
+ free(act_str);
+ return false;
+ }
+}
+
+bool
+cct_check_str_eq(const char *file, int line, const char *expression,
+ const char *expected, const char *actual, bool free1,
+ bool free2)
+{
+ bool result;
+
+ if (expected && actual && str_eq(actual, expected)) {
+ cct_check_passed(file, line, expression);
+ result = true;
+ } else {
+ char *exp_str = expected ? format("\"%s\"", expected) : x_strdup("(null)");
+ char *act_str = actual ? format("\"%s\"", actual) : x_strdup("(null)");
+ cct_check_failed(file, line, expression, exp_str, act_str);
+ free(exp_str);
+ free(act_str);
+ result = false;
+ }
+
+ if (free1) {
+ free((char *)expected);
+ }
+ if (free2) {
+ free((char *)actual);
+ }
+ return result;
+}
+
+bool
+cct_check_args_eq(const char *file, int line, const char *expression,
+ struct args *expected, struct args *actual,
+ bool free1, bool free2)
+{
+ bool result;
+
+ if (expected && actual && args_equal(actual, expected)) {
+ cct_check_passed(file, line, expression);
+ result = true;
+ } else {
+ char *exp_str = expected ? args_to_string(expected) : x_strdup("(null)");
+ char *act_str = actual ? args_to_string(actual) : x_strdup("(null)");
+ cct_check_failed(file, line, expression, exp_str, act_str);
+ free(exp_str);
+ free(act_str);
+ result = false;
+ }
+
+ if (free1) {
+ args_free(expected);
+ }
+ if (free2) {
+ args_free(actual);
+ }
+ return result;
+}
+
+void
+cct_chdir(const char *path)
+{
+ if (chdir(path) != 0) {
+ fprintf(stderr, "chdir: %s: %s", path, strerror(errno));
+ abort();
+ }
+}
+
+void
+cct_wipe(const char *path)
+{
+ // TODO: rewrite using traverse().
+#ifndef __MINGW32__
+ char *command = format("rm -rf %s", path);
+#else
+ char *command = format("rd /s /q %s", path);
+#endif
+ if (system(command) != 0) {
+ perror(command);
+ }
+ free(command);
+}
+
+void
+cct_create_fresh_dir(const char *path)
+{
+ cct_wipe(path);
+ if (mkdir(path, 0777) != 0) {
+ fprintf(stderr, "mkdir: %s: %s", path, strerror(errno));;
+ abort();
+ }
+}
diff --git a/test/framework.h b/test/framework.h
new file mode 100644
index 0000000..d1aa6a7
--- /dev/null
+++ b/test/framework.h
@@ -0,0 +1,151 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef TEST_FRAMEWORK_H
+#define TEST_FRAMEWORK_H
+
+#include "../ccache.h"
+
+// ============================================================================
+
+#define TEST_SUITE(name) \
+ unsigned suite_##name(unsigned _start_point) \
+ { \
+ unsigned _test_counter = 0; \
+ cct_suite_begin(#name); \
+ { \
+ // Empty due to macro trickery.
+
+#define TEST(name) \
+ cct_test_end(); \
+ } \
+ ++_test_counter; \
+ { static int name = 0; (void)name; /* Verify test name. */ } \
+ if (_test_counter >= _start_point) { \
+ cct_test_begin(#name);
+
+#define TEST_SUITE_END \
+ cct_test_end(); \
+ } \
+ cct_suite_end(); \
+ return 0; /* We have reached the end. */ \
+ }
+
+// ============================================================================
+
+#define CHECKM(assertion, message) \
+ do { \
+ if ((assertion)) { \
+ cct_check_passed(__FILE__, __LINE__, #assertion); \
+ } else { \
+ cct_check_failed(__FILE__, __LINE__, #assertion, (message), NULL); \
+ cct_test_end(); \
+ cct_suite_end(); \
+ return _test_counter; \
+ } \
+ } while (false)
+
+#define CHECK(assertion) \
+ CHECKM(assertion, NULL)
+
+#define CHECK_POINTER_EQ_BASE(t, e, a, f1, f2) \
+ do { \
+ if (!cct_check_##t##_eq(__FILE__, __LINE__, #a, (e), (a), (f1), (f2))) { \
+ cct_test_end(); \
+ cct_suite_end(); \
+ return _test_counter; \
+ } \
+ } while (false)
+
+// ============================================================================
+
+#define CHECK_INT_EQ(expected, actual) \
+ do { \
+ if (!cct_check_int_eq(__FILE__, __LINE__, #actual, (expected), \
+ (actual))) { \
+ cct_test_end(); \
+ cct_suite_end(); \
+ return _test_counter; \
+ } \
+ } while (false)
+
+// ============================================================================
+
+#define CHECK_FLOAT_EQ(expected, actual) \
+ do { \
+ if (!cct_check_float_eq(__FILE__, __LINE__, #actual, (expected), \
+ (actual))) { \
+ cct_test_end(); \
+ cct_suite_end(); \
+ return _test_counter; \
+ } \
+ } while (false)
+
+// ============================================================================
+
+#define CHECK_STR_EQ(expected, actual) \
+ CHECK_POINTER_EQ_BASE(str, expected, actual, false, false)
+
+#define CHECK_STR_EQ_FREE1(expected, actual) \
+ CHECK_POINTER_EQ_BASE(str, expected, actual, true, false)
+
+#define CHECK_STR_EQ_FREE2(expected, actual) \
+ CHECK_POINTER_EQ_BASE(str, expected, actual, false, true)
+
+#define CHECK_STR_EQ_FREE12(expected, actual) \
+ CHECK_POINTER_EQ_BASE(str, expected, actual, true, true)
+
+// ============================================================================
+
+#define CHECK_ARGS_EQ(expected, actual) \
+ CHECK_POINTER_EQ_BASE(args, expected, actual, false, false)
+
+#define CHECK_ARGS_EQ_FREE1(expected, actual) \
+ CHECK_POINTER_EQ_BASE(args, expected, actual, true, false)
+
+#define CHECK_ARGS_EQ_FREE2(expected, actual) \
+ CHECK_POINTER_EQ_BASE(args, expected, actual, false, true)
+
+#define CHECK_ARGS_EQ_FREE12(expected, actual) \
+ CHECK_POINTER_EQ_BASE(args, expected, actual, true, true)
+
+// ============================================================================
+
+typedef unsigned (*suite_fn)(unsigned);
+int cct_run(suite_fn *suites, int verbose);
+
+void cct_suite_begin(const char *name);
+void cct_suite_end(void);
+void cct_test_begin(const char *name);
+void cct_test_end(void);
+void cct_check_passed(const char *file, int line, const char *assertion);
+void cct_check_failed(const char *file, int line, const char *assertion,
+ const char *expected, const char *actual);
+bool cct_check_float_eq(const char *file, int line, const char *expression,
+ double expected, double actual);
+bool cct_check_int_eq(const char *file, int line, const char *expression,
+ int64_t expected, int64_t actual);
+bool cct_check_str_eq(const char *file, int line, const char *expression,
+ const char *expected, const char *actual, bool free1,
+ bool free2);
+bool cct_check_args_eq(const char *file, int line, const char *expression,
+ struct args *expected, struct args *actual,
+ bool free1, bool free2);
+void cct_chdir(const char *path);
+void cct_wipe(const char *path);
+void cct_create_fresh_dir(const char *path);
+
+#endif
diff --git a/test/main.c b/test/main.c
new file mode 100644
index 0000000..965ffed
--- /dev/null
+++ b/test/main.c
@@ -0,0 +1,93 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "framework.h"
+#ifdef HAVE_GETOPT_LONG
+#include <getopt.h>
+#else
+#include "../getopt_long.h"
+#endif
+
+// *INDENT-OFF* disable uncrustify
+#define SUITE(name) unsigned suite_ ## name(unsigned);
+#include "suites.h"
+#undef SUITE
+// *INDENT-ON* enable uncrustify
+
+const char USAGE_TEXT[] =
+ "Usage:\n"
+ " test [options]\n"
+ "\n"
+ "Options:\n"
+ " -h, --help print this help text\n"
+ " -v, --verbose enable verbose logging of tests\n";
+
+int
+main(int argc, char **argv)
+{
+ suite_fn suites[] = {
+#define SUITE(name) &suite_ ## name,
+#include "suites.h"
+#undef SUITE
+ NULL
+ };
+ static const struct option options[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"verbose", no_argument, NULL, 'v'},
+ {NULL, 0, NULL, 0}
+ };
+ int verbose = 0;
+ int c;
+ char *testdir, *dir_before;
+ int result;
+
+#ifdef _WIN32
+ putenv("CCACHE_DETECT_SHEBANG=1");
+#endif
+
+ while ((c = getopt_long(argc, argv, "hv", options, NULL)) != -1) {
+ switch (c) {
+ case 'h':
+ fprintf(stdout, USAGE_TEXT);
+ return 0;
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ default:
+ fprintf(stderr, USAGE_TEXT);
+ return 1;
+ }
+ }
+
+ if (getenv("RUN_FROM_BUILD_FARM")) {
+ verbose = 1;
+ }
+
+ testdir = format("testdir.%d", (int)getpid());
+ cct_create_fresh_dir(testdir);
+ dir_before = gnu_getcwd();
+ cct_chdir(testdir);
+ result = cct_run(suites, verbose);
+ if (result == 0) {
+ cct_chdir(dir_before);
+ cct_wipe(testdir);
+ }
+ free(testdir);
+ free(dir_before);
+ return result;
+}
diff --git a/test/suites.h b/test/suites.h
new file mode 100644
index 0000000..335b29d
--- /dev/null
+++ b/test/suites.h
@@ -0,0 +1,10 @@
+SUITE(args)
+SUITE(argument_processing)
+SUITE(compopt)
+SUITE(conf)
+SUITE(counters)
+SUITE(hash)
+SUITE(hashutil)
+SUITE(lockfile)
+SUITE(stats)
+SUITE(util)
diff --git a/test/test_args.c b/test/test_args.c
new file mode 100644
index 0000000..6b11dc4
--- /dev/null
+++ b/test/test_args.c
@@ -0,0 +1,213 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for the functions operating on struct args.
+
+#include "../ccache.h"
+#include "framework.h"
+#include "util.h"
+
+TEST_SUITE(args)
+
+TEST(args_init_empty)
+{
+ struct args *args = args_init(0, NULL);
+ CHECK(args);
+ CHECK_INT_EQ(0, args->argc);
+ CHECK(!args->argv[0]);
+ args_free(args);
+}
+
+TEST(args_init_populated)
+{
+ char *argv[] = {"first", "second"};
+ struct args *args = args_init(2, argv);
+ CHECK(args);
+ CHECK_INT_EQ(2, args->argc);
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK_STR_EQ("second", args->argv[1]);
+ CHECK(!args->argv[2]);
+ args_free(args);
+}
+
+TEST(args_init_from_string)
+{
+ struct args *args = args_init_from_string("first second\tthird\nfourth");
+ CHECK(args);
+ CHECK_INT_EQ(4, args->argc);
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK_STR_EQ("second", args->argv[1]);
+ CHECK_STR_EQ("third", args->argv[2]);
+ CHECK_STR_EQ("fourth", args->argv[3]);
+ CHECK(!args->argv[4]);
+ args_free(args);
+}
+
+TEST(args_init_from_gcc_atfile)
+{
+ struct args *args;
+ const char *argtext =
+ "first\rsec\\\tond\tthi\\\\rd\nfourth \tfif\\ th \"si'x\\\" th\""
+ " 'seve\nth'\\";
+
+ create_file("gcc_atfile", argtext);
+
+ args = args_init_from_gcc_atfile("gcc_atfile");
+ CHECK(args);
+ CHECK_INT_EQ(7, args->argc);
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK_STR_EQ("sec\tond", args->argv[1]);
+ CHECK_STR_EQ("thi\\rd", args->argv[2]);
+ CHECK_STR_EQ("fourth", args->argv[3]);
+ CHECK_STR_EQ("fif th", args->argv[4]);
+ CHECK_STR_EQ("si'x\" th", args->argv[5]);
+#ifndef _WIN32
+ CHECK_STR_EQ("seve\nth", args->argv[6]);
+#else
+ CHECK_STR_EQ("seve\r\nth", args->argv[6]);
+#endif
+ CHECK(!args->argv[7]);
+ args_free(args);
+}
+
+TEST(args_copy)
+{
+ struct args *args1 = args_init_from_string("foo");
+ struct args *args2 = args_copy(args1);
+ CHECK_ARGS_EQ_FREE12(args1, args2);
+}
+
+TEST(args_add)
+{
+ struct args *args = args_init_from_string("first");
+ CHECK_INT_EQ(1, args->argc);
+ args_add(args, "second");
+ CHECK_INT_EQ(2, args->argc);
+ CHECK_STR_EQ("second", args->argv[1]);
+ CHECK(!args->argv[2]);
+ args_free(args);
+}
+
+TEST(args_extend)
+{
+ struct args *args1 = args_init_from_string("first");
+ struct args *args2 = args_init_from_string("second third");
+ CHECK_INT_EQ(1, args1->argc);
+ args_extend(args1, args2);
+ CHECK_INT_EQ(3, args1->argc);
+ CHECK_STR_EQ("second", args1->argv[1]);
+ CHECK_STR_EQ("third", args1->argv[2]);
+ CHECK(!args1->argv[3]);
+ args_free(args1);
+ args_free(args2);
+}
+
+TEST(args_pop)
+{
+ struct args *args = args_init_from_string("first second third");
+ args_pop(args, 2);
+ CHECK_INT_EQ(1, args->argc);
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK(!args->argv[1]);
+ args_free(args);
+}
+
+TEST(args_set)
+{
+ struct args *args = args_init_from_string("first second third");
+ args_set(args, 1, "2nd");
+ CHECK_INT_EQ(3, args->argc);
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK_STR_EQ("2nd", args->argv[1]);
+ CHECK_STR_EQ("third", args->argv[2]);
+ CHECK(!args->argv[3]);
+ args_free(args);
+}
+
+TEST(args_remove_first)
+{
+ struct args *args1 = args_init_from_string("first second third");
+ struct args *args2 = args_init_from_string("second third");
+ args_remove_first(args1);
+ CHECK_ARGS_EQ_FREE12(args1, args2);
+}
+
+TEST(args_add_prefix)
+{
+ struct args *args1 = args_init_from_string("second third");
+ struct args *args2 = args_init_from_string("first second third");
+ args_add_prefix(args1, "first");
+ CHECK_ARGS_EQ_FREE12(args1, args2);
+}
+
+TEST(args_strip)
+{
+ struct args *args1 = args_init_from_string("first xsecond third xfourth");
+ struct args *args2 = args_init_from_string("first third");
+ args_strip(args1, "x");
+ CHECK_ARGS_EQ_FREE12(args1, args2);
+}
+
+TEST(args_to_string)
+{
+ struct args *args = args_init_from_string("first second");
+ CHECK_STR_EQ_FREE2("first second", args_to_string(args));
+ args_free(args);
+}
+
+TEST(args_insert)
+{
+ struct args *args = args_init_from_string("first second third fourth fifth");
+
+ struct args *src1 = args_init_from_string("alpha beta gamma");
+ struct args *src2 = args_init_from_string("one");
+ struct args *src3 = args_init_from_string("");
+ struct args *src4 = args_init_from_string("alpha beta gamma");
+ struct args *src5 = args_init_from_string("one");
+ struct args *src6 = args_init_from_string("");
+
+ args_insert(args, 2, src1, true);
+ CHECK_STR_EQ_FREE2("first second alpha beta gamma fourth fifth",
+ args_to_string(args));
+ CHECK_INT_EQ(7, args->argc);
+ args_insert(args, 2, src2, true);
+ CHECK_STR_EQ_FREE2("first second one beta gamma fourth fifth",
+ args_to_string(args));
+ CHECK_INT_EQ(7, args->argc);
+ args_insert(args, 2, src3, true);
+ CHECK_STR_EQ_FREE2("first second beta gamma fourth fifth",
+ args_to_string(args));
+ CHECK_INT_EQ(6, args->argc);
+
+ args_insert(args, 1, src4, false);
+ CHECK_STR_EQ_FREE2("first alpha beta gamma second beta gamma fourth fifth",
+ args_to_string(args));
+ CHECK_INT_EQ(9, args->argc);
+ args_insert(args, 1, src5, false);
+ CHECK_STR_EQ_FREE2(
+ "first one alpha beta gamma second beta gamma fourth fifth",
+ args_to_string(args));
+ CHECK_INT_EQ(10, args->argc);
+ args_insert(args, 1, src6, false);
+ CHECK_STR_EQ_FREE2(
+ "first one alpha beta gamma second beta gamma fourth fifth",
+ args_to_string(args));
+ CHECK_INT_EQ(10, args->argc);
+
+ args_free(args);
+}
+
+TEST_SUITE_END
diff --git a/test/test_argument_processing.c b/test/test_argument_processing.c
new file mode 100644
index 0000000..80f23db
--- /dev/null
+++ b/test/test_argument_processing.c
@@ -0,0 +1,441 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for the processing of compiler arguments.
+
+#include "../ccache.h"
+#include "../conf.h"
+#include "framework.h"
+#include "util.h"
+
+extern struct conf *conf;
+
+static char *
+get_root(void)
+{
+#ifndef _WIN32
+ return x_strdup("/");
+#else
+ char volume[4]; // "C:\"
+ GetVolumePathName(get_cwd(), volume, sizeof(volume));
+ return x_strdup(volume);
+#endif
+}
+
+static char *
+get_posix_path(char *path)
+{
+#ifndef _WIN32
+ return x_strdup(path);
+#else
+ char *posix;
+ char *p;
+
+ // /-escape volume.
+ if (path[0] >= 'A' && path[0] <= 'Z' && path[1] == ':') {
+ posix = format("/%s", path);
+ } else {
+ posix = x_strdup(path);
+ }
+ // Convert slashes.
+ for (p = posix; *p; p++) {
+ if (*p == '\\') {
+ *p = '/';
+ }
+ }
+ return posix;
+#endif
+}
+
+TEST_SUITE(argument_processing)
+
+TEST(dash_E_should_result_in_called_for_preprocessing)
+{
+ struct args *orig = args_init_from_string("cc -c foo.c -E");
+ struct args *preprocessed, *compiler;
+
+ create_file("foo.c", "");
+ CHECK(!cc_process_args(orig, &preprocessed, &compiler));
+ CHECK_INT_EQ(1, stats_get_pending(STATS_PREPROCESSING));
+
+ args_free(orig);
+}
+
+TEST(dash_M_should_be_unsupported)
+{
+ struct args *orig = args_init_from_string("cc -c foo.c -M");
+ struct args *preprocessed, *compiler;
+
+ create_file("foo.c", "");
+ CHECK(!cc_process_args(orig, &preprocessed, &compiler));
+ CHECK_INT_EQ(1, stats_get_pending(STATS_UNSUPPORTED_OPTION));
+
+ args_free(orig);
+}
+
+TEST(dependency_flags_should_only_be_sent_to_the_preprocessor)
+{
+#define CMD \
+ "cc -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2" \
+ " -Wp,-MD,wpmd -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
+ struct args *orig = args_init_from_string(CMD " -c foo.c -o foo.o");
+ struct args *exp_cpp = args_init_from_string(CMD);
+#undef CMD
+ struct args *exp_cc = args_init_from_string("cc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(cpp_only_flags_to_preprocessor_if_run_second_cpp_is_false)
+{
+#define CMD \
+ "cc -I. -idirafter . -iframework. -imacros . -imultilib ." \
+ " -include test.h -include-pch test.pch -iprefix . -iquote ." \
+ " -isysroot . -isystem . -iwithprefix . -iwithprefixbefore ." \
+ " -DTEST_MACRO -DTEST_MACRO2=1 -F. -trigraphs -fworking-directory" \
+ " -fno-working-directory -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2" \
+ " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt" \
+ " -Wp,-MQ,wpmq -Wp,-MF,wpf"
+ struct args *orig = args_init_from_string(CMD " -c foo.c -o foo.o");
+ struct args *exp_cpp = args_init_from_string(CMD);
+#undef CMD
+ struct args *exp_cc = args_init_from_string("cc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ conf->run_second_cpp = false;
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(cpp_only_flags_to_preprocessor_and_compiler_if_run_second_cpp_is_true)
+{
+#define CMD \
+ "cc -I. -idirafter . -iframework. -imacros . -imultilib ." \
+ " -include test.h -include-pch test.pch -iprefix . -iquote ." \
+ " -isysroot . -isystem . -iwithprefix . -iwithprefixbefore ." \
+ " -DTEST_MACRO -DTEST_MACRO2=1 -F. -trigraphs -fworking-directory" \
+ " -fno-working-directory"
+#define DEP_OPTS \
+ " -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 " \
+ " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd"
+ struct args *orig = args_init_from_string(CMD DEP_OPTS " -c foo.c -o foo.o");
+ struct args *exp_cpp = args_init_from_string(CMD DEP_OPTS);
+ struct args *exp_cc = args_init_from_string(CMD " -c");
+#undef CMD
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ conf->run_second_cpp = true;
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(dependency_flags_that_take_an_argument_should_not_require_space_delimiter)
+{
+ struct args *orig = args_init_from_string(
+ "cc -c -MMD -MFfoo.d -MT mt -MTmt -MQmq foo.c -o foo.o");
+ struct args *exp_cpp = args_init_from_string(
+ "cc -MMD -MFfoo.d -MT mt -MTmt -MQmq");
+ struct args *exp_cc = args_init_from_string("cc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(sysroot_should_be_rewritten_if_basedir_is_used)
+{
+ extern char *current_working_dir;
+ char *arg_string;
+ struct args *orig;
+ struct args *act_cpp = NULL, *act_cc = NULL;
+
+ create_file("foo.c", "");
+ free(conf->base_dir);
+ conf->base_dir = get_root();
+ current_working_dir = get_cwd();
+ arg_string = format("cc --sysroot=%s/foo -c foo.c", current_working_dir);
+ orig = args_init_from_string(arg_string);
+ free(arg_string);
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_STR_EQ(act_cpp->argv[1], "--sysroot=./foo");
+
+ args_free(orig);
+ args_free(act_cpp);
+ args_free(act_cc);
+}
+
+TEST(MF_flag_with_immediate_argument_should_work_as_last_argument)
+{
+ struct args *orig = args_init_from_string(
+ "cc -c foo.c -o foo.o -MMD -MT bar -MFfoo.d");
+ struct args *exp_cpp = args_init_from_string(
+ "cc -MMD -MT bar -MFfoo.d");
+ struct args *exp_cc = args_init_from_string("cc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(MT_flag_with_immediate_argument_should_work_as_last_argument)
+{
+ struct args *orig = args_init_from_string(
+ "cc -c foo.c -o foo.o -MMD -MFfoo.d -MT foo -MTbar");
+ struct args *exp_cpp = args_init_from_string(
+ "cc -MMD -MFfoo.d -MT foo -MTbar");
+ struct args *exp_cc = args_init_from_string("cc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(MQ_flag_with_immediate_argument_should_work_as_last_argument)
+{
+ struct args *orig = args_init_from_string(
+ "cc -c foo.c -o foo.o -MMD -MFfoo.d -MQ foo -MQbar");
+ struct args *exp_cpp = args_init_from_string(
+ "cc -MMD -MFfoo.d -MQ foo -MQbar");
+ struct args *exp_cc = args_init_from_string("cc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(MQ_flag_without_immediate_argument_should_not_add_MQobj)
+{
+ struct args *orig = args_init_from_string(
+ "gcc -c -MD -MP -MFfoo.d -MQ foo.d foo.c");
+ struct args *exp_cpp = args_init_from_string(
+ "gcc -MD -MP -MFfoo.d -MQ foo.d");
+ struct args *exp_cc = args_init_from_string("gcc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(MT_flag_without_immediate_argument_should_not_add_MTobj)
+{
+ struct args *orig = args_init_from_string(
+ "gcc -c -MD -MP -MFfoo.d -MT foo.d foo.c");
+ struct args *exp_cpp = args_init_from_string(
+ "gcc -MD -MP -MFfoo.d -MT foo.d");
+ struct args *exp_cc = args_init_from_string("gcc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(MQ_flag_with_immediate_argument_should_not_add_MQobj)
+{
+ struct args *orig = args_init_from_string(
+ "gcc -c -MD -MP -MFfoo.d -MQfoo.d foo.c");
+ struct args *exp_cpp = args_init_from_string(
+ "gcc -MD -MP -MFfoo.d -MQfoo.d");
+ struct args *exp_cc = args_init_from_string("gcc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(MT_flag_with_immediate_argument_should_not_add_MQobj)
+{
+ struct args *orig = args_init_from_string(
+ "gcc -c -MD -MP -MFfoo.d -MTfoo.d foo.c");
+ struct args *exp_cpp = args_init_from_string(
+ "gcc -MD -MP -MFfoo.d -MTfoo.d");
+ struct args *exp_cc = args_init_from_string("gcc -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(fprofile_flag_with_existing_dir_should_be_rewritten_to_real_path)
+{
+ struct args *orig = args_init_from_string(
+ "gcc -c -fprofile-generate=some/dir foo.c");
+ struct args *exp_cpp = args_init_from_string("gcc");
+ struct args *exp_cc = args_init_from_string("gcc");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+ char *s, *path;
+
+ create_file("foo.c", "");
+ mkdir("some", 0777);
+ mkdir("some/dir", 0777);
+ path = x_realpath("some/dir");
+ s = format("-fprofile-generate=%s", path);
+ free(path);
+ args_add(exp_cpp, s);
+ args_add(exp_cc, s);
+ args_add(exp_cc, "-c");
+ free(s);
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(fprofile_flag_with_nonexisting_dir_should_not_be_rewritten)
+{
+ struct args *orig = args_init_from_string(
+ "gcc -c -fprofile-generate=some/dir foo.c");
+ struct args *exp_cpp = args_init_from_string(
+ "gcc -fprofile-generate=some/dir");
+ struct args *exp_cc = args_init_from_string(
+ "gcc -fprofile-generate=some/dir -c");
+ struct args *act_cpp = NULL, *act_cc = NULL;
+
+ create_file("foo.c", "");
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
+TEST(isystem_flag_with_separate_arg_should_be_rewritten_if_basedir_is_used)
+{
+ extern char *current_working_dir;
+ char *arg_string;
+ struct args *orig;
+ struct args *act_cpp = NULL, *act_cc = NULL;
+
+ create_file("foo.c", "");
+ free(conf->base_dir);
+ conf->base_dir = get_root();
+ current_working_dir = get_cwd();
+ arg_string = format("cc -isystem %s/foo -c foo.c", current_working_dir);
+ orig = args_init_from_string(arg_string);
+ free(arg_string);
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_STR_EQ("./foo", act_cpp->argv[2]);
+
+ args_free(orig);
+ args_free(act_cpp);
+ args_free(act_cc);
+}
+
+TEST(isystem_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
+{
+ extern char *current_working_dir;
+ char *cwd;
+ char *arg_string;
+ struct args *orig;
+ struct args *act_cpp = NULL, *act_cc = NULL;
+
+ create_file("foo.c", "");
+ free(conf->base_dir);
+ conf->base_dir = x_strdup("/"); // posix
+ current_working_dir = get_cwd();
+ // Windows path doesn't work concatenated.
+ cwd = get_posix_path(current_working_dir);
+ arg_string = format("cc -isystem%s/foo -c foo.c", cwd);
+ orig = args_init_from_string(arg_string);
+ free(arg_string);
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_STR_EQ("-isystem./foo", act_cpp->argv[1]);
+
+ free(cwd);
+ args_free(orig);
+ args_free(act_cpp);
+ args_free(act_cc);
+}
+
+TEST(I_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
+{
+ extern char *current_working_dir;
+ char *cwd;
+ char *arg_string;
+ struct args *orig;
+ struct args *act_cpp = NULL, *act_cc = NULL;
+
+ create_file("foo.c", "");
+ free(conf->base_dir);
+ conf->base_dir = x_strdup("/"); // posix
+ current_working_dir = get_cwd();
+ // Windows path doesn't work concatenated.
+ cwd = get_posix_path(current_working_dir);
+ arg_string = format("cc -I%s/foo -c foo.c", cwd);
+ orig = args_init_from_string(arg_string);
+ free(arg_string);
+
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_STR_EQ("-I./foo", act_cpp->argv[1]);
+
+ free(cwd);
+ args_free(orig);
+ args_free(act_cpp);
+ args_free(act_cc);
+}
+
+TEST_SUITE_END
diff --git a/test/test_compopt.c b/test/test_compopt.c
new file mode 100644
index 0000000..dc1e74c
--- /dev/null
+++ b/test/test_compopt.c
@@ -0,0 +1,108 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for the compopt_* functions.
+
+#include "../ccache.h"
+#include "../compopt.h"
+#include "framework.h"
+
+TEST_SUITE(compopt)
+
+TEST(option_table_should_be_sorted)
+{
+ bool compopt_verify_sortedness();
+ CHECK(compopt_verify_sortedness());
+}
+
+TEST(dash_I_affects_cpp)
+{
+ CHECK(compopt_affects_cpp("-I"));
+ CHECK(!compopt_affects_cpp("-Ifoo"));
+}
+
+TEST(compopt_short)
+{
+ CHECK(compopt_short(compopt_affects_cpp, "-Ifoo"));
+ CHECK(!compopt_short(compopt_affects_cpp, "-include"));
+}
+
+TEST(dash_V_doesnt_affect_cpp)
+{
+ CHECK(!compopt_affects_cpp("-V"));
+}
+
+TEST(dash_doesnexist_doesnt_affect_cpp)
+{
+ CHECK(!compopt_affects_cpp("-doesntexist"));
+}
+
+TEST(dash_MM_too_hard)
+{
+ CHECK(compopt_too_hard("-MM"));
+}
+
+TEST(dash_MD_not_too_hard)
+{
+ CHECK(!compopt_too_hard("-MD"));
+}
+
+TEST(dash_fprofile_arcs_not_too_hard)
+{
+ CHECK(!compopt_too_hard("-fprofile-arcs"));
+}
+
+TEST(dash_ftest_coverage_not_too_hard)
+{
+ CHECK(!compopt_too_hard("-ftest-coverage"));
+}
+
+TEST(dash_doesnexist_not_too_hard)
+{
+ CHECK(!compopt_too_hard("-doesntexist"));
+}
+
+TEST(dash_Xpreprocessor_too_hard_for_direct_mode)
+{
+ CHECK(compopt_too_hard_for_direct_mode("-Xpreprocessor"));
+}
+
+TEST(dash_nostdinc_not_too_hard_for_direct_mode)
+{
+ CHECK(!compopt_too_hard_for_direct_mode("-nostdinc"));
+}
+
+TEST(dash_I_takes_path)
+{
+ CHECK(compopt_takes_path("-I"));
+}
+
+TEST(dash_Xlinker_takes_arg)
+{
+ CHECK(compopt_takes_arg("-Xlinker"));
+}
+
+TEST(dash_xxx_doesnt_take_arg)
+{
+ CHECK(!compopt_takes_arg("-xxx"));
+}
+
+TEST(dash_iframework_prefix_affects_cpp)
+{
+ CHECK(compopt_prefix_affects_cpp("-iframework"));
+}
+
+TEST_SUITE_END
diff --git a/test/test_conf.c b/test/test_conf.c
new file mode 100644
index 0000000..ea43e2e
--- /dev/null
+++ b/test/test_conf.c
@@ -0,0 +1,465 @@
+// Copyright (C) 2011-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "../conf.h"
+#include "framework.h"
+#include "util.h"
+
+#define N_CONFIG_ITEMS 31
+static struct {
+ char *descr;
+ const char *origin;
+} received_conf_items[N_CONFIG_ITEMS];
+static size_t n_received_conf_items = 0;
+
+static void
+conf_item_receiver(const char *descr, const char *origin, void *context)
+{
+ (void)context;
+ received_conf_items[n_received_conf_items].descr = x_strdup(descr);
+ received_conf_items[n_received_conf_items].origin = origin;
+ ++n_received_conf_items;
+}
+
+static void
+free_received_conf_items(void)
+{
+ while (n_received_conf_items > 0) {
+ --n_received_conf_items;
+ free(received_conf_items[n_received_conf_items].descr);
+ }
+}
+
+TEST_SUITE(conf)
+
+TEST(conf_create)
+{
+ struct conf *conf = conf_create();
+ CHECK_STR_EQ("", conf->base_dir);
+ CHECK_STR_EQ_FREE1(format("%s/.ccache", get_home_directory()),
+ conf->cache_dir);
+ CHECK_INT_EQ(2, conf->cache_dir_levels);
+ CHECK_STR_EQ("", conf->compiler);
+ CHECK_STR_EQ("mtime", conf->compiler_check);
+ CHECK(!conf->compression);
+ CHECK_INT_EQ(6, conf->compression_level);
+ CHECK_STR_EQ("", conf->cpp_extension);
+ CHECK(conf->direct_mode);
+ CHECK(!conf->disable);
+ CHECK_STR_EQ("", conf->extra_files_to_hash);
+ CHECK(!conf->hard_link);
+ CHECK(conf->hash_dir);
+ CHECK_STR_EQ("", conf->ignore_headers_in_manifest);
+ CHECK(!conf->keep_comments_cpp);
+ CHECK_FLOAT_EQ(0.8f, conf->limit_multiple);
+ CHECK_STR_EQ("", conf->log_file);
+ CHECK_INT_EQ(0, conf->max_files);
+ CHECK_INT_EQ((uint64_t)5 * 1000 * 1000 * 1000, conf->max_size);
+ CHECK_STR_EQ("", conf->path);
+ CHECK_STR_EQ("", conf->prefix_command);
+ CHECK_STR_EQ("", conf->prefix_command_cpp);
+ CHECK(!conf->read_only);
+ CHECK(!conf->read_only_direct);
+ CHECK(!conf->recache);
+ CHECK(conf->run_second_cpp);
+ CHECK_INT_EQ(0, conf->sloppiness);
+ CHECK(conf->stats);
+ CHECK_STR_EQ("", conf->temporary_dir);
+ CHECK_INT_EQ(UINT_MAX, conf->umask);
+ CHECK(!conf->unify);
+ conf_free(conf);
+}
+
+TEST(conf_read_valid_config)
+{
+ struct conf *conf = conf_create();
+ char *errmsg, *user;
+ putenv("USER=rabbit");
+ user = getenv("USER");
+ CHECK_STR_EQ("rabbit", user);
+ create_file(
+ "ccache.conf",
+#ifndef _WIN32
+ "base_dir = /$USER/foo/${USER} \n"
+#else
+ "base_dir = C:/$USER/foo/${USER}\n"
+#endif
+ "cache_dir=\n"
+ "cache_dir = $USER$/${USER}/.ccache\n"
+ "\n"
+ "\n"
+ " #A comment\n"
+ " cache_dir_levels = 4\n"
+ "\t compiler = foo\n"
+ "compiler_check = none\n"
+ "compression=true\n"
+ "compression_level= 2\n"
+ "cpp_extension = .foo\n"
+ "direct_mode = false\n"
+ "disable = true\n"
+ "extra_files_to_hash = a:b c:$USER\n"
+ "hard_link = true\n"
+ "hash_dir = false\n"
+ "ignore_headers_in_manifest = a:b/c\n"
+ "keep_comments_cpp = true\n"
+ "limit_multiple = 1.0\n"
+ "log_file = $USER${USER} \n"
+ "max_files = 17\n"
+ "max_size = 123M\n"
+ "path = $USER.x\n"
+ "prefix_command = x$USER\n"
+ "prefix_command_cpp = y\n"
+ "read_only = true\n"
+ "read_only_direct = true\n"
+ "recache = true\n"
+ "run_second_cpp = false\n"
+ "sloppiness = file_macro ,time_macros, include_file_mtime,include_file_ctime,file_stat_matches,pch_defines , no_system_headers \n"
+ "stats = false\n"
+ "temporary_dir = ${USER}_foo\n"
+ "umask = 777\n"
+ "unify = true"); // Note: no newline.
+ CHECK(conf_read(conf, "ccache.conf", &errmsg));
+ CHECK(!errmsg);
+
+#ifndef _WIN32
+ CHECK_STR_EQ_FREE1(format("/%s/foo/%s", user, user), conf->base_dir);
+#else
+ CHECK_STR_EQ_FREE1(format("C:/%s/foo/%s", user, user), conf->base_dir);
+#endif
+ CHECK_STR_EQ_FREE1(format("%s$/%s/.ccache", user, user), conf->cache_dir);
+ CHECK_INT_EQ(4, conf->cache_dir_levels);
+ CHECK_STR_EQ("foo", conf->compiler);
+ CHECK_STR_EQ("none", conf->compiler_check);
+ CHECK(conf->compression);
+ CHECK_INT_EQ(2, conf->compression_level);
+ CHECK_STR_EQ(".foo", conf->cpp_extension);
+ CHECK(!conf->direct_mode);
+ CHECK(conf->disable);
+ CHECK_STR_EQ_FREE1(format("a:b c:%s", user), conf->extra_files_to_hash);
+ CHECK(conf->hard_link);
+ CHECK(!conf->hash_dir);
+ CHECK_STR_EQ("a:b/c", conf->ignore_headers_in_manifest);
+ CHECK(conf->keep_comments_cpp);
+ CHECK_FLOAT_EQ(1.0, conf->limit_multiple);
+ CHECK_STR_EQ_FREE1(format("%s%s", user, user), conf->log_file);
+ CHECK_INT_EQ(17, conf->max_files);
+ CHECK_INT_EQ(123 * 1000 * 1000, conf->max_size);
+ CHECK_STR_EQ_FREE1(format("%s.x", user), conf->path);
+ CHECK_STR_EQ_FREE1(format("x%s", user), conf->prefix_command);
+ CHECK_STR_EQ("y", conf->prefix_command_cpp);
+ CHECK(conf->read_only);
+ CHECK(conf->read_only_direct);
+ CHECK(conf->recache);
+ CHECK(!conf->run_second_cpp);
+ CHECK_INT_EQ(SLOPPY_INCLUDE_FILE_MTIME|SLOPPY_INCLUDE_FILE_CTIME|
+ SLOPPY_FILE_MACRO|SLOPPY_TIME_MACROS|
+ SLOPPY_FILE_STAT_MATCHES|SLOPPY_NO_SYSTEM_HEADERS|
+ SLOPPY_PCH_DEFINES,
+ conf->sloppiness);
+ CHECK(!conf->stats);
+ CHECK_STR_EQ_FREE1(format("%s_foo", user), conf->temporary_dir);
+ CHECK_INT_EQ(0777, conf->umask);
+ CHECK(conf->unify);
+
+ conf_free(conf);
+}
+
+TEST(conf_read_with_missing_equal_sign)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "no equal sign");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: missing equal sign",
+ errmsg);
+ conf_free(conf);
+}
+
+TEST(conf_read_with_bad_config_key)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "# Comment\nfoo = bar");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:2: unknown configuration option \"foo\"",
+ errmsg);
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_bool)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ create_file("ccache.conf", "disable=");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: not a boolean value: \"\"",
+ errmsg);
+
+ create_file("ccache.conf", "disable=foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: not a boolean value: \"foo\"",
+ errmsg);
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_env_string)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "base_dir = ${foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: syntax error: missing '}' after \"foo\"",
+ errmsg);
+ // Other cases tested in test_util.c.
+ conf_free(conf);
+}
+
+TEST(conf_read_empty_umask)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "umask = ");
+ CHECK(conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_INT_EQ(conf->umask, UINT_MAX);
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_size)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "max_size = foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: invalid size: \"foo\"",
+ errmsg);
+ // Other cases tested in test_util.c.
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_sloppiness)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "sloppiness = file_macro, foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: unknown sloppiness: \"foo\"",
+ errmsg);
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_unsigned)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ create_file("ccache.conf", "max_files =");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: invalid unsigned integer: \"\"",
+ errmsg);
+
+ create_file("ccache.conf", "max_files = -42");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: invalid unsigned integer: \"-42\"",
+ errmsg);
+
+ create_file("ccache.conf", "max_files = foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: invalid unsigned integer: \"foo\"",
+ errmsg);
+
+ conf_free(conf);
+}
+
+TEST(verify_absolute_base_dir)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ create_file("ccache.conf", "base_dir = relative/path");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: not an absolute path: \"relative/path\"",
+ errmsg);
+
+ create_file("ccache.conf", "base_dir =");
+ CHECK(conf_read(conf, "ccache.conf", &errmsg));
+
+ conf_free(conf);
+}
+
+TEST(verify_dir_levels)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ create_file("ccache.conf", "cache_dir_levels = 0");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2(
+ "ccache.conf:1: cache directory levels must be between 1 and 8",
+ errmsg);
+ create_file("ccache.conf", "cache_dir_levels = 9");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2(
+ "ccache.conf:1: cache directory levels must be between 1 and 8",
+ errmsg);
+
+ conf_free(conf);
+}
+
+TEST(conf_update_from_environment)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ putenv("CCACHE_COMPRESS=1");
+ CHECK(conf_update_from_environment(conf, &errmsg));
+ CHECK(conf->compression);
+
+ x_unsetenv("CCACHE_COMPRESS");
+ putenv("CCACHE_NOCOMPRESS=1");
+ CHECK(conf_update_from_environment(conf, &errmsg));
+ CHECK(!conf->compression);
+
+ conf_free(conf);
+}
+
+TEST(conf_set_new_value)
+{
+ char *errmsg;
+ char *data;
+
+ create_file("ccache.conf", "path = vanilla\n");
+ CHECK(conf_set_value_in_file("ccache.conf", "stats", "chocolate", &errmsg));
+ data = read_text_file("ccache.conf", 0);
+ CHECK(data);
+ CHECK_STR_EQ_FREE2("path = vanilla\nstats = chocolate\n", data);
+}
+
+TEST(conf_set_existing_value)
+{
+ char *errmsg;
+ char *data;
+
+ create_file("ccache.conf", "path = chocolate\nstats = chocolate\n");
+ CHECK(conf_set_value_in_file("ccache.conf", "path", "vanilla", &errmsg));
+ data = read_text_file("ccache.conf", 0);
+ CHECK(data);
+ CHECK_STR_EQ_FREE2("path = vanilla\nstats = chocolate\n", data);
+}
+
+TEST(conf_print_items)
+{
+ size_t i;
+ struct conf conf = {
+ "bd",
+ "cd",
+ 7,
+ "c",
+ "cc",
+ true,
+ 8,
+ "ce",
+ false,
+ true,
+ "efth",
+ true,
+ .hash_dir = false,
+ "ihim",
+ true,
+ 0.0,
+ "lf",
+ 4711,
+ 98.7 * 1000 * 1000,
+ "p",
+ "pc",
+ "pcc",
+ true,
+ true,
+ true,
+ .run_second_cpp = false,
+ SLOPPY_FILE_MACRO|SLOPPY_INCLUDE_FILE_MTIME|
+ SLOPPY_INCLUDE_FILE_CTIME|SLOPPY_TIME_MACROS|
+ SLOPPY_FILE_STAT_MATCHES|SLOPPY_PCH_DEFINES|
+ SLOPPY_NO_SYSTEM_HEADERS,
+ false,
+ "td",
+ 022,
+ true,
+ NULL
+ };
+ size_t n = 0;
+
+ conf.item_origins = x_malloc(N_CONFIG_ITEMS * sizeof(char *));
+ for (i = 0; i < N_CONFIG_ITEMS; ++i) {
+#ifndef __MINGW32__
+ conf.item_origins[i] = format("origin%zu", i);
+#else
+ conf.item_origins[i] = format("origin%u", (unsigned) i);
+#endif
+ }
+
+ conf_print_items(&conf, conf_item_receiver, NULL);
+ CHECK_INT_EQ(N_CONFIG_ITEMS, n_received_conf_items);
+ CHECK_STR_EQ("base_dir = bd", received_conf_items[n++].descr);
+ CHECK_STR_EQ("cache_dir = cd", received_conf_items[n++].descr);
+ CHECK_STR_EQ("cache_dir_levels = 7", received_conf_items[n++].descr);
+ CHECK_STR_EQ("compiler = c", received_conf_items[n++].descr);
+ CHECK_STR_EQ("compiler_check = cc", received_conf_items[n++].descr);
+ CHECK_STR_EQ("compression = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("compression_level = 8", received_conf_items[n++].descr);
+ CHECK_STR_EQ("cpp_extension = ce", received_conf_items[n++].descr);
+ CHECK_STR_EQ("direct_mode = false", received_conf_items[n++].descr);
+ CHECK_STR_EQ("disable = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("extra_files_to_hash = efth", received_conf_items[n++].descr);
+ CHECK_STR_EQ("hard_link = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("hash_dir = false", received_conf_items[n++].descr);
+ CHECK_STR_EQ("ignore_headers_in_manifest = ihim",
+ received_conf_items[n++].descr);
+ CHECK_STR_EQ("keep_comments_cpp = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("limit_multiple = 0.0", received_conf_items[n++].descr);
+ CHECK_STR_EQ("log_file = lf", received_conf_items[n++].descr);
+ CHECK_STR_EQ("max_files = 4711", received_conf_items[n++].descr);
+ CHECK_STR_EQ("max_size = 98.7M", received_conf_items[n++].descr);
+ CHECK_STR_EQ("path = p", received_conf_items[n++].descr);
+ CHECK_STR_EQ("prefix_command = pc", received_conf_items[n++].descr);
+ CHECK_STR_EQ("prefix_command_cpp = pcc", received_conf_items[n++].descr);
+ CHECK_STR_EQ("read_only = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("read_only_direct = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("recache = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("run_second_cpp = false", received_conf_items[n++].descr);
+ CHECK_STR_EQ("sloppiness = file_macro, include_file_mtime,"
+ " include_file_ctime, time_macros, pch_defines,"
+ " file_stat_matches, no_system_headers",
+ received_conf_items[n++].descr);
+ CHECK_STR_EQ("stats = false", received_conf_items[n++].descr);
+ CHECK_STR_EQ("temporary_dir = td", received_conf_items[n++].descr);
+ CHECK_STR_EQ("umask = 022", received_conf_items[n++].descr);
+ CHECK_STR_EQ("unify = true", received_conf_items[n++].descr);
+
+ for (i = 0; i < N_CONFIG_ITEMS; ++i) {
+#ifndef __MINGW32__
+ char *expected = format("origin%zu", i);
+#else
+ char *expected = format("origin%u", (unsigned) i);
+#endif
+ CHECK_STR_EQ_FREE1(expected, received_conf_items[i].origin);
+ }
+
+ free_received_conf_items();
+ free(conf.item_origins);
+}
+
+TEST_SUITE_END
diff --git a/test/test_counters.c b/test/test_counters.c
new file mode 100644
index 0000000..1705b76
--- /dev/null
+++ b/test/test_counters.c
@@ -0,0 +1,60 @@
+// Copyright (C) 2010-2011 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "../ccache.h"
+#include "../counters.h"
+#include "framework.h"
+#include "util.h"
+
+TEST_SUITE(counters)
+
+TEST(counters_init_0_should_allocate_0)
+{
+ struct counters *counters = counters_init(0);
+
+ CHECK_INT_EQ(0, counters->allocated);
+ CHECK_INT_EQ(0, counters->size);
+
+ counters_free(counters);
+}
+
+TEST(counters_init_7_should_allocate_32)
+{
+ int i;
+ struct counters *counters = counters_init(7);
+
+ CHECK_INT_EQ(32, counters->allocated);
+ CHECK_INT_EQ(7, counters->size);
+ for (i = 0; i < 7; i++) {
+ CHECK_INT_EQ(0, counters->data[i]);
+ }
+
+ counters_free(counters);
+}
+
+TEST(counters_resize_50_should_allocate_96)
+{
+ struct counters *counters = counters_init(0);
+
+ CHECK_INT_EQ(0, counters->allocated);
+ counters_resize(counters, 50);
+ CHECK_INT_EQ(50, counters->size);
+ CHECK_INT_EQ(96, counters->allocated);
+
+ counters_free(counters);
+}
+
+TEST_SUITE_END
diff --git a/test/test_hash.c b/test/test_hash.c
new file mode 100644
index 0000000..3fe3d69
--- /dev/null
+++ b/test/test_hash.c
@@ -0,0 +1,57 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for functions in hash.c.
+
+#include "../ccache.h"
+#include "framework.h"
+
+TEST_SUITE(hash)
+
+TEST(test_vectors_from_rfc_1320_should_be_correct)
+{
+ struct mdfour h;
+
+ hash_start(&h);
+ hash_string(&h, "");
+ CHECK_STR_EQ_FREE2("31d6cfe0d16ae931b73c59d7e0c089c0-0", hash_result(&h));
+
+ hash_start(&h);
+ hash_string(&h, "a");
+ CHECK_STR_EQ_FREE2("bde52cb31de33e46245e05fbdbd6fb24-1", hash_result(&h));
+
+ hash_start(&h);
+ hash_string(&h, "message digest");
+ CHECK_STR_EQ_FREE2("d9130a8164549fe818874806e1c7014b-14", hash_result(&h));
+
+ hash_start(&h);
+ hash_string(
+ &h,
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ CHECK_STR_EQ_FREE2("e33b4ddc9c38f2199c3e7b164fcc0536-80", hash_result(&h));
+}
+
+TEST(hash_result_should_be_idempotent)
+{
+ struct mdfour h;
+
+ hash_start(&h);
+ hash_string(&h, "");
+ CHECK_STR_EQ_FREE2("31d6cfe0d16ae931b73c59d7e0c089c0-0", hash_result(&h));
+ CHECK_STR_EQ_FREE2("31d6cfe0d16ae931b73c59d7e0c089c0-0", hash_result(&h));
+}
+
+TEST_SUITE_END
diff --git a/test/test_hashutil.c b/test/test_hashutil.c
new file mode 100644
index 0000000..22930c9
--- /dev/null
+++ b/test/test_hashutil.c
@@ -0,0 +1,188 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for functions in hashutil.c.
+
+#include "../ccache.h"
+#include "../hashutil.h"
+#include "framework.h"
+#include "util.h"
+
+TEST_SUITE(hashutil)
+
+TEST(hash_command_output_simple)
+{
+ struct mdfour h1, h2;
+ hash_start(&h1);
+ hash_start(&h2);
+ CHECK(hash_command_output(&h1, "echo", "not used"));
+ CHECK(hash_command_output(&h2, "echo", "not used"));
+ CHECK(hash_equal(&h1, &h2));
+}
+
+TEST(hash_command_output_space_removal)
+{
+ struct mdfour h1, h2;
+ hash_start(&h1);
+ hash_start(&h2);
+ CHECK(hash_command_output(&h1, "echo", "not used"));
+ CHECK(hash_command_output(&h2, " echo ", "not used"));
+ CHECK(hash_equal(&h1, &h2));
+}
+
+TEST(hash_command_output_hash_inequality)
+{
+ struct mdfour h1, h2;
+ hash_start(&h1);
+ hash_start(&h2);
+ CHECK(hash_command_output(&h1, "echo foo", "not used"));
+ CHECK(hash_command_output(&h2, "echo bar", "not used"));
+ CHECK(!hash_equal(&h1, &h2));
+}
+
+TEST(hash_command_output_compiler_substitution)
+{
+ struct mdfour h1, h2;
+ hash_start(&h1);
+ hash_start(&h2);
+ CHECK(hash_command_output(&h1, "echo foo", "not used"));
+ CHECK(hash_command_output(&h2, "%compiler% foo", "echo"));
+ CHECK(hash_equal(&h1, &h2));
+}
+
+TEST(hash_command_output_stdout_versus_stderr)
+{
+ struct mdfour h1, h2;
+ hash_start(&h1);
+ hash_start(&h2);
+#ifndef _WIN32
+ create_file("stderr.sh", "#!/bin/sh\necho foo >&2\n");
+ chmod("stderr.sh", 0555);
+ CHECK(hash_command_output(&h1, "echo foo", "not used"));
+ CHECK(hash_command_output(&h2, "./stderr.sh", "not used"));
+#else
+ create_file("stderr.bat", "@echo off\r\necho foo>&2\r\n");
+ CHECK(hash_command_output(&h1, "echo foo", "not used"));
+ CHECK(hash_command_output(&h2, "stderr.bat", "not used"));
+#endif
+ CHECK(hash_equal(&h1, &h2));
+}
+
+TEST(hash_multicommand_output)
+{
+ struct mdfour h1, h2;
+ hash_start(&h1);
+ hash_start(&h2);
+#ifndef _WIN32
+ create_file("foo.sh", "#!/bin/sh\necho foo\necho bar\n");
+ chmod("foo.sh", 0555);
+ CHECK(hash_multicommand_output(&h2, "echo foo; echo bar", "not used"));
+ CHECK(hash_multicommand_output(&h1, "./foo.sh", "not used"));
+#else
+ create_file("foo.bat", "@echo off\r\necho foo\r\necho bar\r\n");
+ CHECK(hash_multicommand_output(&h2, "echo foo; echo bar", "not used"));
+ CHECK(hash_multicommand_output(&h1, "foo.bat", "not used"));
+#endif
+ CHECK(hash_equal(&h1, &h2));
+}
+
+TEST(hash_multicommand_output_error_handling)
+{
+ struct mdfour h1, h2;
+ hash_start(&h1);
+ hash_start(&h2);
+ CHECK(!hash_multicommand_output(&h2, "false; true", "not used"));
+}
+
+TEST(check_for_temporal_macros)
+{
+ const char time_start[] =
+ "__TIME__\n"
+ "int a;\n";
+ const char time_middle[] =
+ "#define a __TIME__\n"
+ "int a;\n";
+ const char time_end[] =
+ "#define a __TIME__";
+
+ const char date_start[] =
+ "__DATE__\n"
+ "int ab;\n";
+ const char date_middle[] =
+ "#define ab __DATE__\n"
+ "int ab;\n";
+ const char date_end[] =
+ "#define ab __DATE__";
+
+ const char no_temporal[] =
+ "#define ab _ _DATE__\n"
+ "#define ab __ DATE__\n"
+ "#define ab __D ATE__\n"
+ "#define ab __DA TE__\n"
+ "#define ab __DAT E__\n"
+ "#define ab __DATE __\n"
+ "#define ab __DATE_ _\n"
+ "#define ab _ _TIME__\n"
+ "#define ab __ TIME__\n"
+ "#define ab __T IME__\n"
+ "#define ab __TI ME__\n"
+ "#define ab __TIM E__\n"
+ "#define ab __TIME __\n"
+ "#define ab __TIME_ _\n";
+
+ CHECK(check_for_temporal_macros(time_start + 0, sizeof(time_start) - 0));
+ CHECK(!check_for_temporal_macros(time_start + 1, sizeof(time_start) - 1));
+
+ CHECK(check_for_temporal_macros(time_middle + 0, sizeof(time_middle) - 0));
+ CHECK(check_for_temporal_macros(time_middle + 1, sizeof(time_middle) - 1));
+ CHECK(check_for_temporal_macros(time_middle + 2, sizeof(time_middle) - 2));
+ CHECK(check_for_temporal_macros(time_middle + 3, sizeof(time_middle) - 3));
+ CHECK(check_for_temporal_macros(time_middle + 4, sizeof(time_middle) - 4));
+ CHECK(check_for_temporal_macros(time_middle + 5, sizeof(time_middle) - 5));
+ CHECK(check_for_temporal_macros(time_middle + 6, sizeof(time_middle) - 6));
+ CHECK(check_for_temporal_macros(time_middle + 7, sizeof(time_middle) - 7));
+
+ CHECK(check_for_temporal_macros(time_end + 0, sizeof(time_end) - 0));
+ CHECK(check_for_temporal_macros(time_end + sizeof(time_end) - 9, 9));
+ CHECK(!check_for_temporal_macros(time_end + sizeof(time_end) - 8, 8));
+
+ CHECK(check_for_temporal_macros(date_start + 0, sizeof(date_start) - 0));
+ CHECK(!check_for_temporal_macros(date_start + 1, sizeof(date_start) - 1));
+
+ CHECK(check_for_temporal_macros(date_middle + 0, sizeof(date_middle) - 0));
+ CHECK(check_for_temporal_macros(date_middle + 1, sizeof(date_middle) - 1));
+ CHECK(check_for_temporal_macros(date_middle + 2, sizeof(date_middle) - 2));
+ CHECK(check_for_temporal_macros(date_middle + 3, sizeof(date_middle) - 3));
+ CHECK(check_for_temporal_macros(date_middle + 4, sizeof(date_middle) - 4));
+ CHECK(check_for_temporal_macros(date_middle + 5, sizeof(date_middle) - 5));
+ CHECK(check_for_temporal_macros(date_middle + 6, sizeof(date_middle) - 6));
+ CHECK(check_for_temporal_macros(date_middle + 7, sizeof(date_middle) - 7));
+
+ CHECK(check_for_temporal_macros(date_end + 0, sizeof(date_end) - 0));
+ CHECK(check_for_temporal_macros(date_end + sizeof(date_end) - 9, 9));
+ CHECK(!check_for_temporal_macros(date_end + sizeof(date_end) - 8, 8));
+
+ CHECK(!check_for_temporal_macros(no_temporal + 0, sizeof(no_temporal) - 0));
+ CHECK(!check_for_temporal_macros(no_temporal + 1, sizeof(no_temporal) - 1));
+ CHECK(!check_for_temporal_macros(no_temporal + 2, sizeof(no_temporal) - 2));
+ CHECK(!check_for_temporal_macros(no_temporal + 3, sizeof(no_temporal) - 3));
+ CHECK(!check_for_temporal_macros(no_temporal + 4, sizeof(no_temporal) - 4));
+ CHECK(!check_for_temporal_macros(no_temporal + 5, sizeof(no_temporal) - 5));
+ CHECK(!check_for_temporal_macros(no_temporal + 6, sizeof(no_temporal) - 6));
+ CHECK(!check_for_temporal_macros(no_temporal + 7, sizeof(no_temporal) - 7));
+}
+
+TEST_SUITE_END
diff --git a/test/test_lockfile.c b/test/test_lockfile.c
new file mode 100644
index 0000000..cb76176
--- /dev/null
+++ b/test/test_lockfile.c
@@ -0,0 +1,77 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for functions in lockfile.c.
+
+#include "../ccache.h"
+#include "framework.h"
+#include "util.h"
+
+TEST_SUITE(lockfile)
+
+TEST(acquire_should_create_symlink)
+{
+ lockfile_acquire("test", 1000);
+
+#ifdef _WIN32
+ CHECK(path_exists("test.lock"));
+#else
+ CHECK(is_symlink("test.lock"));
+#endif
+}
+
+TEST(release_should_delete_file)
+{
+ create_file("test.lock", "");
+ lockfile_release("test");
+
+ CHECK(!path_exists("test.lock"));
+}
+
+TEST(lock_breaking)
+{
+ char *p;
+
+#ifdef _WIN32
+ create_file("test.lock", "foo");
+ create_file("test.lock.lock", "foo");
+#else
+ CHECK_INT_EQ(0, symlink("foo", "test.lock"));
+ CHECK_INT_EQ(0, symlink("foo", "test.lock.lock"));
+#endif
+ CHECK(lockfile_acquire("test", 1000));
+
+#ifdef _WIN32
+ p = read_text_file("test.lock", 0);
+#else
+ p = x_readlink("test.lock");
+#endif
+ CHECK(p);
+ CHECK(!str_eq(p, "foo"));
+ CHECK(!path_exists("test.lock.lock"));
+
+ free(p);
+}
+
+#ifndef _WIN32
+TEST(failed_lock_breaking)
+{
+ create_file("test.lock", "");
+ CHECK(!lockfile_acquire("test", 1000));
+}
+#endif
+
+TEST_SUITE_END
diff --git a/test/test_stats.c b/test/test_stats.c
new file mode 100644
index 0000000..2815b9e
--- /dev/null
+++ b/test/test_stats.c
@@ -0,0 +1,49 @@
+// Copyright (C) 2010-2011 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for statistics handling.
+
+#include "../ccache.h"
+#include "../counters.h"
+#include "framework.h"
+#include "util.h"
+
+TEST_SUITE(stats)
+
+TEST(forward_compatibility)
+{
+ unsigned i;
+ FILE *f;
+ struct counters *counters = counters_init(0);
+
+ f = fopen("stats", "w");
+ for (i = 0; i < 100; i++) {
+ fprintf(f, "%u\n", i);
+ }
+ fclose(f);
+
+ stats_read("stats", counters);
+ CHECK_INT_EQ(100, counters->size);
+ CHECK_INT_EQ(73, counters->data[73]);
+
+ stats_write("stats", counters);
+ CHECK_INT_EQ(100, counters->size);
+ CHECK_INT_EQ(99, counters->data[99]);
+
+ counters_free(counters);
+}
+
+TEST_SUITE_END
diff --git a/test/test_util.c b/test/test_util.c
new file mode 100644
index 0000000..dca718c
--- /dev/null
+++ b/test/test_util.c
@@ -0,0 +1,202 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for functions in util.c.
+
+#include "../ccache.h"
+#include "framework.h"
+
+TEST_SUITE(util)
+
+TEST(basename)
+{
+ CHECK_STR_EQ_FREE2("foo.c", basename("foo.c"));
+ CHECK_STR_EQ_FREE2("foo.c", basename("dir1/dir2/foo.c"));
+ CHECK_STR_EQ_FREE2("foo.c", basename("/dir/foo.c"));
+ CHECK_STR_EQ_FREE2("", basename("dir1/dir2/"));
+}
+
+TEST(dirname)
+{
+ CHECK_STR_EQ_FREE2(".", dirname("foo.c"));
+ CHECK_STR_EQ_FREE2(".", dirname(""));
+ CHECK_STR_EQ_FREE2("/", dirname("/"));
+ CHECK_STR_EQ_FREE2("/", dirname("/foo.c"));
+ CHECK_STR_EQ_FREE2("dir1/dir2", dirname("dir1/dir2/foo.c"));
+ CHECK_STR_EQ_FREE2("/dir", dirname("/dir/foo.c"));
+ CHECK_STR_EQ_FREE2("dir1/dir2", dirname("dir1/dir2/"));
+}
+
+TEST(common_dir_prefix_length)
+{
+ CHECK_INT_EQ(0, common_dir_prefix_length("", ""));
+ CHECK_INT_EQ(0, common_dir_prefix_length("/", "/"));
+ CHECK_INT_EQ(0, common_dir_prefix_length("/", "/b"));
+ CHECK_INT_EQ(0, common_dir_prefix_length("/a", "/b"));
+ CHECK_INT_EQ(2, common_dir_prefix_length("/a", "/a"));
+ CHECK_INT_EQ(2, common_dir_prefix_length("/a", "/a/b"));
+ CHECK_INT_EQ(2, common_dir_prefix_length("/a/b", "/a/c"));
+ CHECK_INT_EQ(4, common_dir_prefix_length("/a/b", "/a/b"));
+ CHECK_INT_EQ(2, common_dir_prefix_length("/a/bc", "/a/b"));
+ CHECK_INT_EQ(2, common_dir_prefix_length("/a/b", "/a/bc"));
+}
+
+TEST(get_relative_path)
+{
+#ifdef _WIN32
+ CHECK_STR_EQ_FREE2("a", get_relative_path("C:/doesn't matter", "a"));
+ CHECK_STR_EQ_FREE2("a/b", get_relative_path("C:/doesn't matter", "a/b"));
+ CHECK_STR_EQ_FREE2(".", get_relative_path("C:/a", "C:/a"));
+ CHECK_STR_EQ_FREE2("..", get_relative_path("C:/a/b", "C:/a"));
+ CHECK_STR_EQ_FREE2("b", get_relative_path("C:/a", "C:/a/b"));
+ CHECK_STR_EQ_FREE2("b/c", get_relative_path("C:/a", "C:/a/b/c"));
+ CHECK_STR_EQ_FREE2("../c", get_relative_path("C:/a/b", "C:/a/c"));
+ CHECK_STR_EQ_FREE2("../c/d", get_relative_path("C:/a/b", "C:/a/c/d"));
+ CHECK_STR_EQ_FREE2("../../c/d", get_relative_path("C:/a/b/c", "C:/a/c/d"));
+ CHECK_STR_EQ_FREE2("../..", get_relative_path("C:/a/b", "C:/"));
+ CHECK_STR_EQ_FREE2("../../c", get_relative_path("C:/a/b", "C:/c"));
+ CHECK_STR_EQ_FREE2("a/b", get_relative_path("C:/", "C:/a/b"));
+#else
+ CHECK_STR_EQ_FREE2("a", get_relative_path("/doesn't matter", "a"));
+ CHECK_STR_EQ_FREE2("a/b", get_relative_path("/doesn't matter", "a/b"));
+ CHECK_STR_EQ_FREE2(".", get_relative_path("/a", "/a"));
+ CHECK_STR_EQ_FREE2("..", get_relative_path("/a/b", "/a"));
+ CHECK_STR_EQ_FREE2("b", get_relative_path("/a", "/a/b"));
+ CHECK_STR_EQ_FREE2("b/c", get_relative_path("/a", "/a/b/c"));
+ CHECK_STR_EQ_FREE2("../c", get_relative_path("/a/b", "/a/c"));
+ CHECK_STR_EQ_FREE2("../c/d", get_relative_path("/a/b", "/a/c/d"));
+ CHECK_STR_EQ_FREE2("../../c/d", get_relative_path("/a/b/c", "/a/c/d"));
+ CHECK_STR_EQ_FREE2("../..", get_relative_path("/a/b", "/"));
+ CHECK_STR_EQ_FREE2("../../c", get_relative_path("/a/b", "/c"));
+ CHECK_STR_EQ_FREE2("a/b", get_relative_path("/", "/a/b"));
+#endif
+}
+
+TEST(format_hash_as_string)
+{
+ unsigned char hash[16] = {
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ };
+
+ CHECK_STR_EQ_FREE2("00000000000000000000000000000000",
+ format_hash_as_string(hash, -1));
+ CHECK_STR_EQ_FREE2("00000000000000000000000000000000-0",
+ format_hash_as_string(hash, 0));
+ hash[0] = 17;
+ hash[15] = 42;
+ CHECK_STR_EQ_FREE2("1100000000000000000000000000002a-12345",
+ format_hash_as_string(hash, 12345));
+}
+
+TEST(subst_env_in_string)
+{
+ char *errmsg;
+
+ putenv("FOO=bar");
+
+ CHECK_STR_EQ_FREE2("bar",
+ subst_env_in_string("$FOO", &errmsg));
+ CHECK(!errmsg);
+
+ errmsg = "";
+ CHECK_STR_EQ_FREE2("$",
+ subst_env_in_string("$", &errmsg));
+ CHECK(!errmsg);
+
+ errmsg = "";
+ CHECK_STR_EQ_FREE2("bar bar:bar",
+ subst_env_in_string("$FOO $FOO:$FOO", &errmsg));
+ CHECK(!errmsg);
+
+ errmsg = "";
+ CHECK_STR_EQ_FREE2("xbar",
+ subst_env_in_string("x$FOO", &errmsg));
+ CHECK(!errmsg);
+
+ errmsg = "";
+ CHECK_STR_EQ_FREE2("barx",
+ subst_env_in_string("${FOO}x", &errmsg));
+ CHECK(!errmsg);
+
+ CHECK(!subst_env_in_string("$surelydoesntexist", &errmsg));
+ CHECK_STR_EQ_FREE2("environment variable \"surelydoesntexist\" not set",
+ errmsg);
+
+ CHECK(!subst_env_in_string("${FOO", &errmsg));
+ CHECK_STR_EQ_FREE2("syntax error: missing '}' after \"FOO\"", errmsg);
+}
+
+TEST(format_human_readable_size)
+{
+ CHECK_STR_EQ_FREE2("0.0 kB", format_human_readable_size(0));
+ CHECK_STR_EQ_FREE2("0.0 kB", format_human_readable_size(49));
+ CHECK_STR_EQ_FREE2("0.1 kB", format_human_readable_size(50));
+ CHECK_STR_EQ_FREE2("42.0 kB", format_human_readable_size(42 * 1000));
+ CHECK_STR_EQ_FREE2("1.0 MB", format_human_readable_size(1000 * 1000));
+ CHECK_STR_EQ_FREE2("1.2 MB", format_human_readable_size(1234 * 1000));
+ CHECK_STR_EQ_FREE2("438.5 MB",
+ format_human_readable_size(438.5 * 1000 * 1000));
+ CHECK_STR_EQ_FREE2("1.0 GB",
+ format_human_readable_size(1000 * 1000 * 1000));
+ CHECK_STR_EQ_FREE2("17.1 GB",
+ format_human_readable_size(17.11 * 1000 * 1000 * 1000));
+}
+
+TEST(format_parsable_size_with_suffix)
+{
+ CHECK_STR_EQ_FREE2("0", format_parsable_size_with_suffix(0));
+ CHECK_STR_EQ_FREE2("42.0k", format_parsable_size_with_suffix(42 * 1000));
+ CHECK_STR_EQ_FREE2("1.0M", format_parsable_size_with_suffix(1000 * 1000));
+ CHECK_STR_EQ_FREE2("1.2M", format_parsable_size_with_suffix(1234 * 1000));
+ CHECK_STR_EQ_FREE2("438.5M",
+ format_parsable_size_with_suffix(438.5 * 1000 * 1000));
+ CHECK_STR_EQ_FREE2("1.0G",
+ format_parsable_size_with_suffix(1000 * 1000 * 1000));
+ CHECK_STR_EQ_FREE2(
+ "17.1G",
+ format_parsable_size_with_suffix(17.11 * 1000 * 1000 * 1000));
+}
+
+TEST(parse_size_with_suffix)
+{
+ uint64_t size;
+ size_t i;
+ struct { const char *size; int64_t expected; } sizes[] = {
+ {"0", 0},
+ {"42", (int64_t)42 * 1000 * 1000 * 1000}, // Default suffix: G
+
+ {"78k", 78 * 1000},
+ {"78K", 78 * 1000},
+ {"1.1 M", 1.1 * 1000 * 1000},
+ {"438.55M", 438.55 * 1000 * 1000},
+ {"1 G", 1 * 1000 * 1000 * 1000},
+ {"2T", (int64_t)2 * 1000 * 1000 * 1000 * 1000},
+
+ {"78 Ki", 78 * 1024},
+ {"1.1Mi", 1.1 * 1024 * 1024},
+ {"438.55 Mi", 438.55 * 1024 * 1024},
+ {"1Gi", 1 * 1024 * 1024 * 1024},
+ {"2 Ti", (int64_t)2 * 1024 * 1024 * 1024 * 1024},
+
+ };
+
+ for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); ++i) {
+ CHECKM(parse_size_with_suffix(sizes[i].size, &size), sizes[i].size);
+ CHECK_INT_EQ(sizes[i].expected, size);
+ }
+}
+
+TEST_SUITE_END
diff --git a/test/util.c b/test/util.c
new file mode 100644
index 0000000..826eebd
--- /dev/null
+++ b/test/util.c
@@ -0,0 +1,41 @@
+// Copyright (C) 2010-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "../system.h"
+#include "util.h"
+
+#ifdef _WIN32
+# define lstat(a, b) stat(a, b)
+#endif
+
+bool
+path_exists(const char *path)
+{
+ struct stat st;
+ return lstat(path, &st) == 0;
+}
+
+void
+create_file(const char *path, const char *content)
+{
+ FILE *f = fopen(path, "w");
+ if (!f || fputs(content, f) < 0) {
+ fprintf(stderr, "create_file: %s: %s\n", path, strerror(errno));
+ }
+ if (f) {
+ fclose(f);
+ }
+}
diff --git a/test/util.h b/test/util.h
new file mode 100644
index 0000000..23636b9
--- /dev/null
+++ b/test/util.h
@@ -0,0 +1,10 @@
+#ifndef TEST_UTIL_H
+#define TEST_UTIL_H
+
+#include <stdbool.h>
+
+bool path_exists(const char *path);
+bool is_symlink(const char *path);
+void create_file(const char *path, const char *content);
+
+#endif
diff --git a/unify.c b/unify.c
new file mode 100644
index 0000000..7c54e9f
--- /dev/null
+++ b/unify.c
@@ -0,0 +1,252 @@
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2009-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// C/C++ unifier
+//
+// The idea is that changes that don't affect the resulting C code should not
+// change the hash. This is achieved by folding white-space and other
+// non-semantic fluff in the input into a single unified format.
+//
+// This unifier was design to match the output of the unifier in compilercache,
+// which is flex based. The major difference is that this unifier is much
+// faster (about 2x) and more forgiving of syntactic errors. Continuing on
+// syntactic errors is important to cope with C/C++ extensions in the local
+// compiler (for example, inline assembly systems).
+
+#include "ccache.h"
+
+static const char *const s_tokens[] = {
+ "...", ">>=", "<<=", "+=", "-=", "*=", "/=", "%=", "&=", "^=",
+ "|=", ">>", "<<", "++", "--", "->", "&&", "||", "<=", ">=",
+ "==", "!=", ";", "{", "<%", "}", "%>", ",", ":", "=",
+ "(", ")", "[", "<:", "]", ":>", ".", "&", "!", "~",
+ "-", "+", "*", "/", "%", "<", ">", "^", "|", "?",
+ 0
+};
+
+#define C_ALPHA 1
+#define C_SPACE 2
+#define C_TOKEN 4
+#define C_QUOTE 8
+#define C_DIGIT 16
+#define C_HEX 32
+#define C_FLOAT 64
+#define C_SIGN 128
+
+static struct {
+ unsigned char type;
+ unsigned char num_toks;
+ const char *toks[7];
+} tokens[256];
+
+// Build up the table used by the unifier.
+static void
+build_table(void)
+{
+ static bool done;
+ if (done) {
+ return;
+ }
+ done = true;
+
+ memset(tokens, 0, sizeof(tokens));
+ for (unsigned char c = 0; c < 128; c++) {
+ if (isalpha(c) || c == '_') {
+ tokens[c].type |= C_ALPHA;
+ }
+ if (isdigit(c)) {
+ tokens[c].type |= C_DIGIT;
+ }
+ if (isspace(c)) {
+ tokens[c].type |= C_SPACE;
+ }
+ if (isxdigit(c)) {
+ tokens[c].type |= C_HEX;
+ }
+ }
+ tokens['\''].type |= C_QUOTE;
+ tokens['"'].type |= C_QUOTE;
+ tokens['l'].type |= C_FLOAT;
+ tokens['L'].type |= C_FLOAT;
+ tokens['f'].type |= C_FLOAT;
+ tokens['F'].type |= C_FLOAT;
+ tokens['U'].type |= C_FLOAT;
+ tokens['u'].type |= C_FLOAT;
+
+ tokens['-'].type |= C_SIGN;
+ tokens['+'].type |= C_SIGN;
+
+ for (int i = 0; s_tokens[i]; i++) {
+ unsigned char c = s_tokens[i][0];
+ tokens[c].type |= C_TOKEN;
+ tokens[c].toks[tokens[c].num_toks] = s_tokens[i];
+ tokens[c].num_toks++;
+ }
+}
+
+// Buffer up characters before hashing them.
+static void
+pushchar(struct mdfour *hash, unsigned char c)
+{
+ static unsigned char buf[64];
+ static size_t len;
+
+ if (c == 0) {
+ if (len > 0) {
+ hash_buffer(hash, (char *)buf, len);
+ len = 0;
+ }
+ hash_buffer(hash, NULL, 0);
+ return;
+ }
+
+ buf[len++] = c;
+ if (len == 64) {
+ hash_buffer(hash, (char *)buf, len);
+ len = 0;
+ }
+}
+
+// Hash some C/C++ code after unifying.
+static void
+unify(struct mdfour *hash, unsigned char *p, size_t size)
+{
+ build_table();
+
+ for (size_t ofs = 0; ofs < size; ) {
+ if (p[ofs] == '#') {
+ if ((size-ofs) > 2 && p[ofs+1] == ' ' && isdigit(p[ofs+2])) {
+ do {
+ ofs++;
+ } while (ofs < size && p[ofs] != '\n');
+ ofs++;
+ } else {
+ do {
+ pushchar(hash, p[ofs]);
+ ofs++;
+ } while (ofs < size && p[ofs] != '\n');
+ pushchar(hash, '\n');
+ ofs++;
+ }
+ continue;
+ }
+
+ if (tokens[p[ofs]].type & C_ALPHA) {
+ do {
+ pushchar(hash, p[ofs]);
+ ofs++;
+ } while (ofs < size && (tokens[p[ofs]].type & (C_ALPHA|C_DIGIT)));
+ pushchar(hash, '\n');
+ continue;
+ }
+
+ if (tokens[p[ofs]].type & C_DIGIT) {
+ do {
+ pushchar(hash, p[ofs]);
+ ofs++;
+ } while (ofs < size &&
+ ((tokens[p[ofs]].type & C_DIGIT) || p[ofs] == '.'));
+ if (ofs < size && (p[ofs] == 'x' || p[ofs] == 'X')) {
+ do {
+ pushchar(hash, p[ofs]);
+ ofs++;
+ } while (ofs < size && (tokens[p[ofs]].type & C_HEX));
+ }
+ if (ofs < size && (p[ofs] == 'E' || p[ofs] == 'e')) {
+ pushchar(hash, p[ofs]);
+ ofs++;
+ while (ofs < size && (tokens[p[ofs]].type & (C_DIGIT|C_SIGN))) {
+ pushchar(hash, p[ofs]);
+ ofs++;
+ }
+ }
+ while (ofs < size && (tokens[p[ofs]].type & C_FLOAT)) {
+ pushchar(hash, p[ofs]);
+ ofs++;
+ }
+ pushchar(hash, '\n');
+ continue;
+ }
+
+ if (tokens[p[ofs]].type & C_SPACE) {
+ do {
+ ofs++;
+ } while (ofs < size && (tokens[p[ofs]].type & C_SPACE));
+ continue;
+ }
+
+ if (tokens[p[ofs]].type & C_QUOTE) {
+ unsigned char q = p[ofs];
+ pushchar(hash, p[ofs]);
+ do {
+ ofs++;
+ while (ofs < size-1 && p[ofs] == '\\') {
+ pushchar(hash, p[ofs]);
+ pushchar(hash, p[ofs+1]);
+ ofs += 2;
+ }
+ pushchar(hash, p[ofs]);
+ } while (ofs < size && p[ofs] != q);
+ pushchar(hash, '\n');
+ ofs++;
+ continue;
+ }
+
+ if (tokens[p[ofs]].type & C_TOKEN) {
+ unsigned char q = p[ofs];
+ int i;
+ for (i = 0; i < tokens[q].num_toks; i++) {
+ unsigned char *s = (unsigned char *)tokens[q].toks[i];
+ int len = strlen((char *)s);
+ if (size >= ofs+len && memcmp(&p[ofs], s, len) == 0) {
+ int j;
+ for (j = 0; s[j]; j++) {
+ pushchar(hash, s[j]);
+ ofs++;
+ }
+ pushchar(hash, '\n');
+ break;
+ }
+ }
+ if (i < tokens[q].num_toks) {
+ continue;
+ }
+ }
+
+ pushchar(hash, p[ofs]);
+ pushchar(hash, '\n');
+ ofs++;
+ }
+ pushchar(hash, 0);
+}
+
+
+// Hash a file that consists of preprocessor output, but remove any line number
+// information from the hash.
+int
+unify_hash(struct mdfour *hash, const char *fname)
+{
+ char *data;
+ size_t size;
+ if (!read_file(fname, 0, &data, &size)) {
+ stats_update(STATS_PREPROCESSOR);
+ return -1;
+ }
+ unify(hash, (unsigned char *)data, size);
+ free(data);
+ return 0;
+}
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..f048d97
--- /dev/null
+++ b/util.c
@@ -0,0 +1,1661 @@
+// Copyright (C) 2002 Andrew Tridgell
+// Copyright (C) 2009-2016 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "ccache.h"
+
+#include <zlib.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <sys/locking.h>
+#include <psapi.h>
+#include <tchar.h>
+#endif
+
+static FILE *logfile;
+
+static bool
+init_log(void)
+{
+ extern struct conf *conf;
+
+ if (logfile) {
+ return true;
+ }
+ assert(conf);
+ if (str_eq(conf->log_file, "")) {
+ return false;
+ }
+ logfile = fopen(conf->log_file, "a");
+ if (logfile) {
+#ifndef _WIN32
+ int fd = fileno(logfile);
+ int flags = fcntl(fd, F_GETFD, 0);
+ if (flags >= 0) {
+ fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ }
+#endif
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static void
+log_prefix(bool log_updated_time)
+{
+#ifdef HAVE_GETTIMEOFDAY
+ static char prefix[200];
+
+ if (log_updated_time) {
+ char timestamp[100];
+ struct tm *tm;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+#ifdef __MINGW64_VERSION_MAJOR
+ tm = localtime((time_t *)&tv.tv_sec);
+#else
+ tm = localtime(&tv.tv_sec);
+#endif
+ strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", tm);
+ snprintf(prefix, sizeof(prefix),
+ "[%s.%06d %-5d] ", timestamp, (int)tv.tv_usec, (int)getpid());
+ }
+ fputs(prefix, logfile);
+#else
+ fprintf(logfile, "[%-5d] ", (int)getpid());
+#endif
+}
+
+static long
+path_max(const char *path)
+{
+#ifdef PATH_MAX
+ (void)path;
+ return PATH_MAX;
+#elif defined(MAXPATHLEN)
+ (void)path;
+ return MAXPATHLEN;
+#elif defined(_PC_PATH_MAX)
+ long maxlen = pathconf(path, _PC_PATH_MAX);
+ return maxlen >= 4096 ? maxlen : 4096;
+#endif
+}
+
+// Warn about failure writing to the log file and then exit.
+static void
+warn_log_fail(void)
+{
+ extern struct conf *conf;
+
+ // Note: Can't call fatal() since that would lead to recursion.
+ fprintf(stderr, "ccache: error: Failed to write to %s: %s\n",
+ conf->log_file, strerror(errno));
+ x_exit(EXIT_FAILURE);
+}
+
+static void
+vlog(const char *format, va_list ap, bool log_updated_time)
+{
+ if (!init_log()) {
+ return;
+ }
+
+ log_prefix(log_updated_time);
+ int rc1 = vfprintf(logfile, format, ap);
+ int rc2 = fprintf(logfile, "\n");
+ if (rc1 < 0 || rc2 < 0) {
+ warn_log_fail();
+ }
+}
+
+// Write a message to the log file (adding a newline) and flush.
+void
+cc_log(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog(format, ap, true);
+ va_end(ap);
+ if (logfile) {
+ fflush(logfile);
+ }
+}
+
+// Write a message to the log file (adding a newline) without flushing and with
+// a reused timestamp.
+void
+cc_bulklog(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog(format, ap, false);
+ va_end(ap);
+}
+
+// Log an executed command to the CCACHE_LOGFILE location.
+void
+cc_log_argv(const char *prefix, char **argv)
+{
+ if (!init_log()) {
+ return;
+ }
+
+ log_prefix(true);
+ fputs(prefix, logfile);
+ print_command(logfile, argv);
+ int rc = fflush(logfile);
+ if (rc) {
+ warn_log_fail();
+ }
+}
+
+// Something went badly wrong!
+void
+fatal(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char msg[1000];
+ vsnprintf(msg, sizeof(msg), format, ap);
+ va_end(ap);
+
+ cc_log("FATAL: %s", msg);
+ fprintf(stderr, "ccache: error: %s\n", msg);
+
+ x_exit(1);
+}
+
+// Copy all data from fd_in to fd_out, decompressing data from fd_in if needed.
+void
+copy_fd(int fd_in, int fd_out)
+{
+ gzFile gz_in = gzdopen(dup(fd_in), "rb");
+ if (!gz_in) {
+ fatal("Failed to copy fd");
+ }
+
+ int n;
+ char buf[READ_BUFFER_SIZE];
+ while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
+ ssize_t written = 0;
+ do {
+ ssize_t count = write(fd_out, buf + written, n - written);
+ if (count == -1) {
+ if (errno != EAGAIN && errno != EINTR) {
+ fatal("Failed to copy fd");
+ }
+ } else {
+ written += count;
+ }
+ } while (written < n);
+ }
+
+ gzclose(gz_in);
+}
+
+#ifndef HAVE_MKSTEMP
+// Cheap and nasty mkstemp replacement.
+int
+mkstemp(char *template)
+{
+ mktemp(template);
+ return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
+}
+#endif
+
+#ifndef _WIN32
+static mode_t
+get_umask(void)
+{
+ static bool mask_retrieved = false;
+ static mode_t mask;
+ if (!mask_retrieved) {
+ mask = umask(0);
+ umask(mask);
+ mask_retrieved = true;
+ }
+ return mask;
+}
+#endif
+
+// Copy src to dest, decompressing src if needed. compress_level > 0 decides
+// whether dest will be compressed, and with which compression level. Returns 0
+// on success and -1 on failure. On failure, errno represents the error.
+int
+copy_file(const char *src, const char *dest, int compress_level)
+{
+ int fd_out;
+ gzFile gz_in = NULL;
+ gzFile gz_out = NULL;
+ int saved_errno = 0;
+
+ // Open destination file.
+ char *tmp_name = x_strdup(dest);
+ fd_out = create_tmp_fd(&tmp_name);
+ cc_log("Copying %s to %s via %s (%scompressed)",
+ src, dest, tmp_name, compress_level > 0 ? "" : "un");
+
+ // Open source file.
+ int fd_in = open(src, O_RDONLY | O_BINARY);
+ if (fd_in == -1) {
+ saved_errno = errno;
+ cc_log("open error: %s", strerror(saved_errno));
+ goto error;
+ }
+
+ gz_in = gzdopen(fd_in, "rb");
+ if (!gz_in) {
+ saved_errno = errno;
+ cc_log("gzdopen(src) error: %s", strerror(saved_errno));
+ close(fd_in);
+ goto error;
+ }
+
+ if (compress_level > 0) {
+ // A gzip file occupies at least 20 bytes, so it will always occupy an
+ // entire filesystem block, even for empty files. Turn off compression for
+ // empty files to save some space.
+ struct stat st;
+ if (x_fstat(fd_in, &st) != 0) {
+ goto error;
+ }
+ if (file_size(&st) == 0) {
+ compress_level = 0;
+ }
+ }
+
+ if (compress_level > 0) {
+ gz_out = gzdopen(dup(fd_out), "wb");
+ if (!gz_out) {
+ saved_errno = errno;
+ cc_log("gzdopen(dest) error: %s", strerror(saved_errno));
+ goto error;
+ }
+ gzsetparams(gz_out, compress_level, Z_DEFAULT_STRATEGY);
+ }
+
+ int n;
+ char buf[READ_BUFFER_SIZE];
+ while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
+ int written;
+ if (compress_level > 0) {
+ written = gzwrite(gz_out, buf, n);
+ } else {
+ written = 0;
+ do {
+ ssize_t count = write(fd_out, buf + written, n - written);
+ if (count == -1 && errno != EINTR) {
+ saved_errno = errno;
+ break;
+ }
+ written += count;
+ } while (written < n);
+ }
+ if (written != n) {
+ if (compress_level > 0) {
+ int errnum;
+ cc_log("gzwrite error: %s (errno: %s)",
+ gzerror(gz_in, &errnum),
+ strerror(saved_errno));
+ } else {
+ cc_log("write error: %s", strerror(saved_errno));
+ }
+ goto error;
+ }
+ }
+
+ // gzeof won't tell if there's an error in the trailing CRC, so we must check
+ // gzerror before considering everything OK.
+ int errnum;
+ gzerror(gz_in, &errnum);
+ if (!gzeof(gz_in) || (errnum != Z_OK && errnum != Z_STREAM_END)) {
+ saved_errno = errno;
+ cc_log("gzread error: %s (errno: %s)",
+ gzerror(gz_in, &errnum), strerror(saved_errno));
+ gzclose(gz_in);
+ if (gz_out) {
+ gzclose(gz_out);
+ }
+ close(fd_out);
+ tmp_unlink(tmp_name);
+ free(tmp_name);
+ return -1;
+ }
+
+ gzclose(gz_in);
+ gz_in = NULL;
+ if (gz_out) {
+ gzclose(gz_out);
+ gz_out = NULL;
+ }
+
+#ifndef _WIN32
+ fchmod(fd_out, 0666 & ~get_umask());
+#endif
+
+ // The close can fail on NFS if out of space.
+ if (close(fd_out) == -1) {
+ saved_errno = errno;
+ cc_log("close error: %s", strerror(saved_errno));
+ goto error;
+ }
+
+ if (x_rename(tmp_name, dest) == -1) {
+ saved_errno = errno;
+ cc_log("rename error: %s", strerror(saved_errno));
+ goto error;
+ }
+
+ free(tmp_name);
+
+ return 0;
+
+error:
+ if (gz_in) {
+ gzclose(gz_in);
+ }
+ if (gz_out) {
+ gzclose(gz_out);
+ }
+ if (fd_out != -1) {
+ close(fd_out);
+ }
+ tmp_unlink(tmp_name);
+ free(tmp_name);
+ errno = saved_errno;
+ return -1;
+}
+
+// Run copy_file() and, if successful, delete the source file.
+int
+move_file(const char *src, const char *dest, int compress_level)
+{
+ int ret = copy_file(src, dest, compress_level);
+ if (ret != -1) {
+ x_unlink(src);
+ }
+ return ret;
+}
+
+// Like move_file(), but assumes that src is uncompressed and that src and dest
+// are on the same file system.
+int
+move_uncompressed_file(const char *src, const char *dest, int compress_level)
+{
+ if (compress_level > 0) {
+ return move_file(src, dest, compress_level);
+ } else {
+ return x_rename(src, dest);
+ }
+}
+
+// Test if a file is zlib compressed.
+bool
+file_is_compressed(const char *filename)
+{
+ FILE *f = fopen(filename, "rb");
+ if (!f) {
+ return false;
+ }
+
+ // Test if file starts with 1F8B, which is zlib's magic number.
+ if ((fgetc(f) != 0x1f) || (fgetc(f) != 0x8b)) {
+ fclose(f);
+ return false;
+ }
+
+ fclose(f);
+ return true;
+}
+
+// Make sure a directory exists.
+int
+create_dir(const char *dir)
+{
+ struct stat st;
+ if (stat(dir, &st) == 0) {
+ if (S_ISDIR(st.st_mode)) {
+ return 0;
+ }
+ errno = ENOTDIR;
+ return 1;
+ }
+ if (mkdir(dir, 0777) != 0 && errno != EEXIST) {
+ return 1;
+ }
+ return 0;
+}
+
+// Create directories leading to path. Returns 0 on success, otherwise -1.
+int
+create_parent_dirs(const char *path)
+{
+ int res;
+ char *parent = dirname(path);
+ struct stat st;
+ if (stat(parent, &st) == 0) {
+ if (S_ISDIR(st.st_mode)) {
+ res = 0;
+ } else {
+ res = -1;
+ errno = ENOTDIR;
+ }
+ } else {
+ res = create_parent_dirs(parent);
+ if (res == 0) {
+ res = mkdir(parent, 0777);
+ // Have to handle the condition of the directory already existing because
+ // the file system could have changed in between calling stat and
+ // actually creating the directory. This can happen when there are
+ // multiple instances of ccache running and trying to create the same
+ // directory chain, which usually is the case when the cache root does
+ // not initially exist. As long as one of the processes creates the
+ // directories then our condition is satisfied and we avoid a race
+ // condition.
+ if (res != 0 && errno == EEXIST) {
+ res = 0;
+ }
+ } else {
+ res = -1;
+ }
+ }
+ free(parent);
+ return res;
+}
+
+// Return a static string with the current hostname.
+const char *
+get_hostname(void)
+{
+ static char hostname[260] = "";
+
+ if (hostname[0]) {
+ return hostname;
+ }
+
+ strcpy(hostname, "unknown");
+#if HAVE_GETHOSTNAME
+ gethostname(hostname, sizeof(hostname) - 1);
+#elif defined(_WIN32)
+ const char *computer_name = getenv("COMPUTERNAME");
+ if (computer_name) {
+ snprintf(hostname, sizeof(hostname), "%s", computer_name);
+ return hostname;
+ }
+
+ WORD w_version_requested = MAKEWORD(2, 2);
+ WSADATA wsa_data;
+ int err = WSAStartup(w_version_requested, &wsa_data);
+ if (err != 0) {
+ // Tell the user that we could not find a usable Winsock DLL.
+ cc_log("WSAStartup failed with error: %d", err);
+ return hostname;
+ }
+
+ if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) {
+ // Tell the user that we could not find a usable WinSock DLL.
+ cc_log("Could not find a usable version of Winsock.dll");
+ WSACleanup();
+ return hostname;
+ }
+
+ int result = gethostname(hostname, sizeof(hostname) - 1);
+ if (result != 0) {
+ LPVOID lp_msg_buf;
+ DWORD dw = WSAGetLastError();
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lp_msg_buf, 0, NULL);
+
+ LPVOID lp_display_buf = (LPVOID) LocalAlloc(
+ LMEM_ZEROINIT,
+ (lstrlen((LPCTSTR) lp_msg_buf) + lstrlen((LPCTSTR) __FILE__) + 200)
+ * sizeof(TCHAR));
+ _snprintf((LPTSTR) lp_display_buf,
+ LocalSize(lp_display_buf) / sizeof(TCHAR),
+ TEXT("%s failed with error %d: %s"), __FILE__, dw,
+ lp_msg_buf);
+
+ cc_log("can't get hostname OS returned error: %s", (char *)lp_display_buf);
+
+ LocalFree(lp_msg_buf);
+ LocalFree(lp_display_buf);
+ }
+ WSACleanup();
+#endif
+
+ hostname[sizeof(hostname) - 1] = 0;
+ return hostname;
+}
+
+// Return a string to be passed to mkstemp to create a temporary file. Also
+// tries to cope with NFS by adding the local hostname.
+const char *
+tmp_string(void)
+{
+ static char *ret;
+ if (!ret) {
+ ret = format("%s.%u.XXXXXX", get_hostname(), (unsigned)getpid());
+ }
+ return ret;
+}
+
+// Return the hash result as a hex string. Size -1 means don't include size
+// suffix. Caller frees.
+char *
+format_hash_as_string(const unsigned char *hash, int size)
+{
+ int i;
+ char *ret = x_malloc(53);
+ for (i = 0; i < 16; i++) {
+ sprintf(&ret[i*2], "%02x", (unsigned) hash[i]);
+ }
+ if (size >= 0) {
+ sprintf(&ret[i*2], "-%d", size);
+ }
+ return ret;
+}
+
+char const CACHEDIR_TAG[] =
+ "Signature: 8a477f597d28d172789f06886806bc55\n"
+ "# This file is a cache directory tag created by ccache.\n"
+ "# For information about cache directory tags, see:\n"
+ "#\thttp://www.brynosaurus.com/cachedir/\n";
+
+int
+create_cachedirtag(const char *dir)
+{
+ char *filename = format("%s/CACHEDIR.TAG", dir);
+ struct stat st;
+ if (stat(filename, &st) == 0) {
+ if (S_ISREG(st.st_mode)) {
+ goto success;
+ }
+ errno = EEXIST;
+ goto error;
+ }
+ FILE *f = fopen(filename, "w");
+ if (!f) {
+ goto error;
+ }
+ if (fwrite(CACHEDIR_TAG, sizeof(CACHEDIR_TAG)-1, 1, f) != 1) {
+ fclose(f);
+ goto error;
+ }
+ if (fclose(f)) {
+ goto error;
+ }
+success:
+ free(filename);
+ return 0;
+error:
+ free(filename);
+ return 1;
+}
+
+// Construct a string according to a format. Caller frees.
+char *
+format(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+
+ char *ptr = NULL;
+ if (vasprintf(&ptr, format, ap) == -1) {
+ fatal("Out of memory in format");
+ }
+ va_end(ap);
+
+ if (!*ptr) {
+ fatal("Internal error in format");
+ }
+ return ptr;
+}
+
+// This is like strdup() but dies if the malloc fails.
+char *
+x_strdup(const char *s)
+{
+ char *ret = strdup(s);
+ if (!ret) {
+ fatal("Out of memory in x_strdup");
+ }
+ return ret;
+}
+
+// This is like strndup() but dies if the malloc fails.
+char *
+x_strndup(const char *s, size_t n)
+{
+#ifndef HAVE_STRNDUP
+ if (!s) {
+ return NULL;
+ }
+ size_t m = 0;
+ while (m < n && s[m]) {
+ m++;
+ }
+ char *ret = malloc(m + 1);
+ if (ret) {
+ memcpy(ret, s, m);
+ ret[m] = '\0';
+ }
+#else
+ char *ret = strndup(s, n);
+#endif
+ if (!ret) {
+ fatal("x_strndup: Could not allocate %lu bytes", (unsigned long)n);
+ }
+ return ret;
+}
+
+// This is like malloc() but dies if the malloc fails.
+void *
+x_malloc(size_t size)
+{
+ if (size == 0) {
+ // malloc() may return NULL if size is zero, so always do this to make sure
+ // that the code handles it regardless of platform.
+ return NULL;
+ }
+ void *ret = malloc(size);
+ if (!ret) {
+ fatal("x_malloc: Could not allocate %lu bytes", (unsigned long)size);
+ }
+ return ret;
+}
+
+// This is like calloc() but dies if the allocation fails.
+void *
+x_calloc(size_t nmemb, size_t size)
+{
+ if (nmemb * size == 0) {
+ // calloc() may return NULL if nmemb or size is 0, so always do this to
+ // make sure that the code handles it regardless of platform.
+ return NULL;
+ }
+ void *ret = calloc(nmemb, size);
+ if (!ret) {
+ fatal("x_calloc: Could not allocate %lu bytes", (unsigned long)size);
+ }
+ return ret;
+}
+
+// This is like realloc() but dies if the malloc fails.
+void *
+x_realloc(void *ptr, size_t size)
+{
+ if (!ptr) {
+ return x_malloc(size);
+ }
+ void *p2 = realloc(ptr, size);
+ if (!p2) {
+ fatal("x_realloc: Could not allocate %lu bytes", (unsigned long)size);
+ }
+ return p2;
+}
+
+// This is like unsetenv.
+void x_unsetenv(const char *name)
+{
+#ifdef HAVE_UNSETENV
+ unsetenv(name);
+#else
+ putenv(x_strdup(name)); // Leak to environment.
+#endif
+}
+
+// Like fstat() but also call cc_log on failure.
+int
+x_fstat(int fd, struct stat *buf)
+{
+ int result = fstat(fd, buf);
+ if (result != 0) {
+ cc_log("Failed to fstat fd %d: %s", fd, strerror(errno));
+ }
+ return result;
+}
+
+// Like lstat() but also call cc_log on failure.
+int
+x_lstat(const char *pathname, struct stat *buf)
+{
+ int result = lstat(pathname, buf);
+ if (result != 0) {
+ cc_log("Failed to lstat %s: %s", pathname, strerror(errno));
+ }
+ return result;
+}
+
+// Like stat() but also call cc_log on failure.
+int
+x_stat(const char *pathname, struct stat *buf)
+{
+ int result = stat(pathname, buf);
+ if (result != 0) {
+ cc_log("Failed to stat %s: %s", pathname, strerror(errno));
+ }
+ return result;
+}
+
+// Construct a string according to the format and store it in *ptr. The
+// original *ptr is then freed.
+void
+reformat(char **ptr, const char *format, ...)
+{
+ char *saved = *ptr;
+ *ptr = NULL;
+
+ va_list ap;
+ va_start(ap, format);
+ if (vasprintf(ptr, format, ap) == -1) {
+ fatal("Out of memory in reformat");
+ }
+ va_end(ap);
+
+ if (!ptr) {
+ fatal("Out of memory in reformat");
+ }
+ if (saved) {
+ free(saved);
+ }
+}
+
+// Recursive directory traversal. fn() is called on all entries in the tree.
+void
+traverse(const char *dir, void (*fn)(const char *, struct stat *))
+{
+ DIR *d = opendir(dir);
+ if (!d) {
+ return;
+ }
+
+ struct dirent *de;
+ while ((de = readdir(d))) {
+ if (str_eq(de->d_name, ".")) {
+ continue;
+ }
+ if (str_eq(de->d_name, "..")) {
+ continue;
+ }
+
+ if (strlen(de->d_name) == 0) {
+ continue;
+ }
+
+ char *fname = format("%s/%s", dir, de->d_name);
+ struct stat st;
+ if (lstat(fname, &st)) {
+ if (errno != ENOENT && errno != ESTALE) {
+ fatal("lstat %s failed: %s", fname, strerror(errno));
+ }
+ free(fname);
+ continue;
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ traverse(fname, fn);
+ }
+
+ fn(fname, &st);
+ free(fname);
+ }
+
+ closedir(d);
+}
+
+
+// Return the base name of a file - caller frees.
+char *
+basename(const char *path)
+{
+ char *p = strrchr(path, '/');
+ if (p) {
+ path = p + 1;
+ }
+#ifdef _WIN32
+ p = strrchr(path, '\\');
+ if (p) {
+ path = p + 1;
+ }
+#endif
+
+ return x_strdup(path);
+}
+
+// Return the dir name of a file - caller frees.
+char *
+dirname(const char *path)
+{
+ char *s = x_strdup(path);
+ char *p = strrchr(s, '/');
+#ifdef _WIN32
+ char *p2 = strrchr(s, '\\');
+ if (!p || (p2 && p < p2)) {
+ p = p2;
+ }
+#endif
+ if (!p) {
+ free(s);
+ s = x_strdup(".");
+ } else if (p == s) {
+ *(p + 1) = 0;
+ } else {
+ *p = 0;
+ }
+ return s;
+}
+
+// Return the file extension (including the dot) of a path as a pointer into
+// path. If path has no file extension, the empty string and the end of path is
+// returned.
+const char *
+get_extension(const char *path)
+{
+ size_t len = strlen(path);
+ for (const char *p = &path[len - 1]; p >= path; --p) {
+ if (*p == '.') {
+ return p;
+ }
+ if (*p == '/') {
+ break;
+ }
+ }
+ return &path[len];
+}
+
+// Return a string containing the given path without the filename extension.
+// Caller frees.
+char *
+remove_extension(const char *path)
+{
+ return x_strndup(path, strlen(path) - strlen(get_extension(path)));
+}
+
+// Return size on disk of a file.
+size_t
+file_size(struct stat *st)
+{
+#ifdef _WIN32
+ return (st->st_size + 1023) & ~1023;
+#else
+ size_t size = st->st_blocks * 512;
+ if ((size_t)st->st_size > size) {
+ // Probably a broken stat() call...
+ size = (st->st_size + 1023) & ~1023;
+ }
+ return size;
+#endif
+}
+
+// Format a size as a human-readable string. Caller frees.
+char *
+format_human_readable_size(uint64_t v)
+{
+ char *s;
+ if (v >= 1000*1000*1000) {
+ s = format("%.1f GB", v/((double)(1000*1000*1000)));
+ } else if (v >= 1000*1000) {
+ s = format("%.1f MB", v/((double)(1000*1000)));
+ } else {
+ s = format("%.1f kB", v/((double)(1000)));
+ }
+ return s;
+}
+
+// Format a size as a parsable string. Caller frees.
+char *
+format_parsable_size_with_suffix(uint64_t size)
+{
+ char *s;
+ if (size >= 1000*1000*1000) {
+ s = format("%.1fG", size / ((double)(1000*1000*1000)));
+ } else if (size >= 1000*1000) {
+ s = format("%.1fM", size / ((double)(1000*1000)));
+ } else if (size >= 1000) {
+ s = format("%.1fk", size / ((double)(1000)));
+ } else {
+ s = format("%u", (unsigned)size);
+ }
+ return s;
+}
+
+// Parse a "size value", i.e. a string that can end in k, M, G, T (10-based
+// suffixes) or Ki, Mi, Gi, Ti (2-based suffixes). For backward compatibility,
+// K is also recognized as a synonym of k.
+bool
+parse_size_with_suffix(const char *str, uint64_t *size)
+{
+ errno = 0;
+
+ char *p;
+ double x = strtod(str, &p);
+ if (errno != 0 || x < 0 || p == str || *str == '\0') {
+ return false;
+ }
+
+ while (isspace(*p)) {
+ ++p;
+ }
+
+ if (*p != '\0') {
+ unsigned multiplier = *(p+1) == 'i' ? 1024 : 1000;
+ switch (*p) {
+ case 'T':
+ x *= multiplier;
+ case 'G':
+ x *= multiplier;
+ case 'M':
+ x *= multiplier;
+ case 'K':
+ case 'k':
+ x *= multiplier;
+ break;
+ default:
+ return false;
+ }
+ } else {
+ // Default suffix: G.
+ x *= 1000 * 1000 * 1000;
+ }
+ *size = x;
+ return true;
+}
+
+
+#if !defined(HAVE_REALPATH) && \
+ defined(_WIN32) && \
+ !defined(HAVE_GETFINALPATHNAMEBYHANDLEW)
+static BOOL GetFileNameFromHandle(HANDLE file_handle, TCHAR *filename,
+ WORD cch_filename)
+{
+ BOOL success = FALSE;
+
+ // Get the file size.
+ DWORD file_size_hi = 0;
+ DWORD file_size_lo = GetFileSize(file_handle, &file_size_hi);
+ if (file_size_lo == 0 && file_size_hi == 0) {
+ // Cannot map a file with a length of zero.
+ return FALSE;
+ }
+
+ // Create a file mapping object.
+ HANDLE file_map =
+ CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 1, NULL);
+ if (!file_map) {
+ return FALSE;
+ }
+
+ // Create a file mapping to get the file name.
+ void *mem = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 1);
+ if (mem) {
+ if (GetMappedFileName(GetCurrentProcess(),
+ mem,
+ filename,
+ cch_filename)) {
+ // Translate path with device name to drive letters.
+ TCHAR temp[512];
+ temp[0] = '\0';
+
+ if (GetLogicalDriveStrings(512-1, temp)) {
+ TCHAR name[MAX_PATH];
+ TCHAR drive[3] = TEXT(" :");
+ BOOL found = FALSE;
+ TCHAR *p = temp;
+
+ do {
+ // Copy the drive letter to the template string.
+ *drive = *p;
+
+ // Look up each device name.
+ if (QueryDosDevice(drive, name, MAX_PATH)) {
+ size_t name_len = _tcslen(name);
+ if (name_len < MAX_PATH) {
+ found = _tcsnicmp(filename, name, name_len) == 0
+ && *(filename + name_len) == _T('\\');
+ if (found) {
+ // Reconstruct filename using temp_file and replace device path
+ // with DOS path.
+ TCHAR temp_file[MAX_PATH];
+ _sntprintf(temp_file,
+ MAX_PATH - 1,
+ TEXT("%s%s"),
+ drive,
+ filename+name_len);
+ _tcsncpy(filename, temp_file, _tcslen(temp_file));
+ }
+ }
+ }
+
+ // Go to the next NULL character.
+ while (*p++) {
+ // Do nothing.
+ }
+ } while (!found && *p); // End of string.
+ }
+ }
+ success = TRUE;
+ UnmapViewOfFile(mem);
+ }
+
+ CloseHandle(file_map);
+ return success;
+}
+#endif
+
+// A sane realpath() function, trying to cope with stupid path limits and a
+// broken API. Caller frees.
+char *
+x_realpath(const char *path)
+{
+ long maxlen = path_max(path);
+ char *ret = x_malloc(maxlen);
+ char *p;
+
+#if HAVE_REALPATH
+ p = realpath(path, ret);
+#elif defined(_WIN32)
+ if (path[0] == '/') {
+ path++; // Skip leading slash.
+ }
+ HANDLE path_handle = CreateFile(
+ path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (INVALID_HANDLE_VALUE != path_handle) {
+#ifdef HAVE_GETFINALPATHNAMEBYHANDLEW
+ GetFinalPathNameByHandle(path_handle, ret, maxlen, FILE_NAME_NORMALIZED);
+#else
+ GetFileNameFromHandle(path_handle, ret, maxlen);
+#endif
+ CloseHandle(path_handle);
+ p = ret + 4; // Strip \\?\ from the file name.
+ } else {
+ snprintf(ret, maxlen, "%s", path);
+ p = ret;
+ }
+#else
+ // Yes, there are such systems. This replacement relies on the fact that when
+ // we call x_realpath we only care about symlinks.
+ {
+ int len = readlink(path, ret, maxlen-1);
+ if (len == -1) {
+ free(ret);
+ return NULL;
+ }
+ ret[len] = 0;
+ p = ret;
+ }
+#endif
+ if (p) {
+ p = x_strdup(p);
+ free(ret);
+ return p;
+ }
+ free(ret);
+ return NULL;
+}
+
+// A getcwd that will returns an allocated buffer.
+char *
+gnu_getcwd(void)
+{
+ unsigned size = 128;
+
+ while (true) {
+ char *buffer = (char *)x_malloc(size);
+ if (getcwd(buffer, size) == buffer) {
+ return buffer;
+ }
+ free(buffer);
+ if (errno != ERANGE) {
+ cc_log("getcwd error: %d (%s)", errno, strerror(errno));
+ return NULL;
+ }
+ size *= 2;
+ }
+}
+
+#ifndef HAVE_STRTOK_R
+// strtok_r replacement.
+char *
+strtok_r(char *str, const char *delim, char **saveptr)
+{
+ if (!str) {
+ str = *saveptr;
+ }
+ int len = strlen(str);
+ char *ret = strtok(str, delim);
+ if (ret) {
+ char *save = ret;
+ while (*save++) {
+ // Do nothing.
+ }
+ if ((len + 1) == (intptr_t) (save - str)) {
+ save--;
+ }
+ *saveptr = save;
+ }
+ return ret;
+}
+#endif
+
+// Create an empty temporary file. *fname will be reallocated and set to the
+// resulting filename. Returns an open file descriptor to the file.
+int
+create_tmp_fd(char **fname)
+{
+ char *template = format("%s.%s", *fname, tmp_string());
+ int fd = mkstemp(template);
+ if (fd == -1 && errno == ENOENT) {
+ if (create_parent_dirs(*fname) != 0) {
+ fatal("Failed to create directory %s: %s",
+ dirname(*fname), strerror(errno));
+ }
+ reformat(&template, "%s.%s", *fname, tmp_string());
+ fd = mkstemp(template);
+ }
+ if (fd == -1) {
+ fatal("Failed to create temporary file for %s: %s",
+ *fname, strerror(errno));
+ }
+
+#ifndef _WIN32
+ fchmod(fd, 0666 & ~get_umask());
+#endif
+
+ free(*fname);
+ *fname = template;
+ return fd;
+}
+
+// Create an empty temporary file. *fname will be reallocated and set to the
+// resulting filename. Returns an open FILE*.
+FILE *
+create_tmp_file(char **fname, const char *mode)
+{
+ FILE *file = fdopen(create_tmp_fd(fname), mode);
+ if (!file) {
+ fatal("Failed to create file %s: %s", *fname, strerror(errno));
+ }
+ return file;
+}
+
+// Return current user's home directory, or NULL if it can't be determined.
+const char *
+get_home_directory(void)
+{
+ const char *p = getenv("HOME");
+ if (p) {
+ return p;
+ }
+#ifdef _WIN32
+ p = getenv("APPDATA");
+ if (p) {
+ return p;
+ }
+#endif
+#ifdef HAVE_GETPWUID
+ {
+ struct passwd *pwd = getpwuid(getuid());
+ if (pwd) {
+ return pwd->pw_dir;
+ }
+ }
+#endif
+ return NULL;
+}
+
+// Get the current directory by reading $PWD. If $PWD isn't sane, gnu_getcwd()
+// is used. Caller frees.
+char *
+get_cwd(void)
+{
+ struct stat st_pwd;
+ struct stat st_cwd;
+
+ char *cwd = gnu_getcwd();
+ if (!cwd) {
+ return NULL;
+ }
+ char *pwd = getenv("PWD");
+ if (!pwd) {
+ return cwd;
+ }
+ if (stat(pwd, &st_pwd) != 0) {
+ return cwd;
+ }
+ if (stat(cwd, &st_cwd) != 0) {
+ return cwd;
+ }
+ if (st_pwd.st_dev == st_cwd.st_dev && st_pwd.st_ino == st_cwd.st_ino) {
+ free(cwd);
+ return x_strdup(pwd);
+ } else {
+ return cwd;
+ }
+}
+
+// Check whether s1 and s2 have the same executable name.
+bool
+same_executable_name(const char *s1, const char *s2)
+{
+#ifdef _WIN32
+ bool eq = strcasecmp(s1, s2) == 0;
+ if (!eq) {
+ char *tmp = format("%s.exe", s2);
+ eq = strcasecmp(s1, tmp) == 0;
+ free(tmp);
+ }
+ return eq;
+#else
+ return str_eq(s1, s2);
+#endif
+}
+
+// Compute the length of the longest directory path that is common to two
+// paths. s1 is assumed to be the path to a directory.
+size_t
+common_dir_prefix_length(const char *s1, const char *s2)
+{
+ const char *p1 = s1;
+ const char *p2 = s2;
+
+ while (*p1 && *p2 && *p1 == *p2) {
+ ++p1;
+ ++p2;
+ }
+ while ((*p1 && *p1 != '/') || (*p2 && *p2 != '/')) {
+ p1--;
+ p2--;
+ }
+ if (!*p1 && !*p2 && p2 == s2 + 1) {
+ // Special case for s1 and s2 both being "/".
+ return 0;
+ }
+ return p1 - s1;
+}
+
+// Compute a relative path from from (an absolute path to a directory) to to (a
+// path). Assumes that both from and to are well-formed and canonical. Caller
+// frees.
+char *
+get_relative_path(const char *from, const char *to)
+{
+ size_t common_prefix_len;
+ char *result;
+
+ assert(from && is_absolute_path(from));
+ assert(to);
+
+ if (!*to || !is_absolute_path(to)) {
+ return x_strdup(to);
+ }
+
+#ifdef _WIN32
+ // Paths can be escaped by a slash for use with -isystem.
+ if (from[0] == '/') {
+ from++;
+ }
+ if (to[0] == '/') {
+ to++;
+ }
+ // Both paths are absolute, drop the drive letters.
+ assert(from[0] == to[0]); // Assume the same drive letter.
+ from += 2;
+ to += 2;
+#endif
+
+ result = x_strdup("");
+ common_prefix_len = common_dir_prefix_length(from, to);
+ if (common_prefix_len > 0 || !str_eq(from, "/")) {
+ const char *p;
+ for (p = from + common_prefix_len; *p; p++) {
+ if (*p == '/') {
+ reformat(&result, "../%s", result);
+ }
+ }
+ }
+ if (strlen(to) > common_prefix_len) {
+ reformat(&result, "%s%s", result, to + common_prefix_len + 1);
+ }
+ for (int i = strlen(result) - 1; i >= 0 && result[i] == '/'; i--) {
+ result[i] = '\0';
+ }
+ if (str_eq(result, "")) {
+ free(result);
+ result = x_strdup(".");
+ }
+ return result;
+}
+
+// Return whether path is absolute.
+bool
+is_absolute_path(const char *path)
+{
+#ifdef _WIN32
+ return path[0] && path[1] == ':';
+#else
+ return path[0] == '/';
+#endif
+}
+
+// Return whether the argument is a full path.
+bool
+is_full_path(const char *path)
+{
+ if (strchr(path, '/')) {
+ return true;
+ }
+#ifdef _WIN32
+ if (strchr(path, '\\')) {
+ return true;
+ }
+#endif
+ return false;
+}
+
+bool is_symlink(const char *path)
+{
+#ifdef _WIN32
+ (void)path;
+ return false;
+#else
+ struct stat st;
+ return x_lstat(path, &st) == 0 && ((st.st_mode & S_IFMT) == S_IFLNK);
+#endif
+}
+
+// Update the modification time of a file in the cache to save it from LRU
+// cleanup.
+void
+update_mtime(const char *path)
+{
+#ifdef HAVE_UTIMES
+ utimes(path, NULL);
+#else
+ utime(path, NULL);
+#endif
+}
+
+// If exit() already has been called, call _exit(), otherwise exit(). This is
+// used to avoid calling exit() inside an atexit handler.
+void
+x_exit(int status)
+{
+ static bool first_time = true;
+ if (first_time) {
+ first_time = false;
+ exit(status);
+ } else {
+ _exit(status);
+ }
+}
+
+// Rename oldpath to newpath (deleting newpath).
+int
+x_rename(const char *oldpath, const char *newpath)
+{
+#ifndef _WIN32
+ return rename(oldpath, newpath);
+#else
+ // Windows' rename() refuses to overwrite an existing file.
+ unlink(newpath); // Not x_unlink, as x_unlink calls x_rename.
+ // If the function succeeds, the return value is nonzero.
+ if (MoveFileA(oldpath, newpath) == 0) {
+ LPVOID lp_msg_buf;
+ DWORD dw = GetLastError();
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lp_msg_buf,
+ 0,
+ NULL);
+
+ LPVOID lp_display_buf = (LPVOID) LocalAlloc(
+ LMEM_ZEROINIT,
+ (lstrlen((LPCTSTR) lp_msg_buf) + lstrlen((LPCTSTR) __FILE__) + 40)
+ * sizeof(TCHAR));
+ _snprintf((LPTSTR) lp_display_buf,
+ LocalSize(lp_display_buf) / sizeof(TCHAR),
+ TEXT("%s failed with error %d: %s"), __FILE__, dw, lp_msg_buf);
+
+ cc_log("can't rename file %s to %s OS returned error: %s",
+ oldpath, newpath, (char *) lp_display_buf);
+
+ LocalFree(lp_msg_buf);
+ LocalFree(lp_display_buf);
+ return -1;
+ } else {
+ return 0;
+ }
+#endif
+}
+
+// Remove path, NFS hazardous. Use only for temporary files that will not exist
+// on other systems. That is, the path should include tmp_string().
+int
+tmp_unlink(const char *path)
+{
+ cc_log("Unlink %s", path);
+ int rc = unlink(path);
+ if (rc) {
+ cc_log("Unlink failed: %s", strerror(errno));
+ }
+ return rc;
+}
+
+// Remove path, NFS safe.
+int
+x_unlink(const char *path)
+{
+ int saved_errno = 0;
+
+ // If path is on an NFS share, unlink isn't atomic, so we rename to a temp
+ // file. We don't care if the temp file is trashed, so it's always safe to
+ // unlink it first.
+ char *tmp_name = format("%s.rm.%s", path, tmp_string());
+ cc_log("Unlink %s via %s", path, tmp_name);
+
+ int result = 0;
+ if (x_rename(path, tmp_name) == -1) {
+ result = -1;
+ saved_errno = errno;
+ goto out;
+ }
+ if (unlink(tmp_name) == -1) {
+ // If it was released in a race, that's OK.
+ if (errno != ENOENT && errno != ESTALE) {
+ result = -1;
+ saved_errno = errno;
+ }
+ }
+
+out:
+ free(tmp_name);
+ if (result) {
+ cc_log("x_unlink failed: %s", strerror(saved_errno));
+ }
+ errno = saved_errno;
+ return result;
+}
+
+#ifndef _WIN32
+// Like readlink() but returns the string or NULL on failure. Caller frees.
+char *
+x_readlink(const char *path)
+{
+ long maxlen = path_max(path);
+ char *buf = x_malloc(maxlen);
+ ssize_t len = readlink(path, buf, maxlen-1);
+ if (len == -1) {
+ free(buf);
+ return NULL;
+ }
+ buf[len] = 0;
+ return buf;
+}
+#endif
+
+// Reads the content of a file. Size hint 0 means no hint. Returns true on
+// success, otherwise false.
+bool
+read_file(const char *path, size_t size_hint, char **data, size_t *size)
+{
+ if (size_hint == 0) {
+ struct stat st;
+ if (x_stat(path, &st) == 0) {
+ size_hint = st.st_size;
+ }
+ }
+ size_hint = (size_hint < 1024) ? 1024 : size_hint;
+
+ int fd = open(path, O_RDONLY | O_BINARY);
+ if (fd == -1) {
+ return false;
+ }
+ size_t allocated = size_hint;
+ *data = x_malloc(allocated);
+ int ret;
+ size_t pos = 0;
+ while (true) {
+ if (pos > allocated / 2) {
+ allocated *= 2;
+ *data = x_realloc(*data, allocated);
+ }
+ ret = read(fd, *data + pos, allocated - pos);
+ if (ret == 0 || (ret == -1 && errno != EINTR)) {
+ break;
+ }
+ if (ret > 0) {
+ pos += ret;
+ }
+ }
+ close(fd);
+ if (ret == -1) {
+ cc_log("Failed reading %s", path);
+ free(*data);
+ *data = NULL;
+ return false;
+ }
+
+ *size = pos;
+ return true;
+}
+
+// Return the content (with NUL termination) of a text file, or NULL on error.
+// Caller frees. Size hint 0 means no hint.
+char *
+read_text_file(const char *path, size_t size_hint)
+{
+ size_t size;
+ char *data;
+ if (read_file(path, size_hint, &data, &size)) {
+ data = x_realloc(data, size + 1);
+ data[size] = '\0';
+ return data;
+ } else {
+ return NULL;
+ }
+}
+
+static bool
+expand_variable(const char **str, char **result, char **errmsg)
+{
+ assert(**str == '$');
+
+ bool curly;
+ const char *p = *str + 1;
+ if (*p == '{') {
+ curly = true;
+ ++p;
+ } else {
+ curly = false;
+ }
+
+ const char *q = p;
+ while (isalnum(*q) || *q == '_') {
+ ++q;
+ }
+ if (curly) {
+ if (*q != '}') {
+ *errmsg = format("syntax error: missing '}' after \"%s\"", p);
+ return false;
+ }
+ }
+
+ if (q == p) {
+ // Special case: don't consider a single $ the start of a variable.
+ reformat(result, "%s$", *result);
+ return true;
+ }
+
+ char *name = x_strndup(p, q - p);
+ const char *value = getenv(name);
+ if (!value) {
+ *errmsg = format("environment variable \"%s\" not set", name);
+ free(name);
+ return false;
+ }
+ reformat(result, "%s%s", *result, value);
+ if (!curly) {
+ --q;
+ }
+ *str = q;
+ free(name);
+ return true;
+}
+
+// Substitute all instances of $VAR or ${VAR}, where VAR is an environment
+// variable, in a string. Caller frees. If one of the environment variables
+// doesn't exist, NULL will be returned and *errmsg will be an appropriate
+// error message (caller frees).
+char *
+subst_env_in_string(const char *str, char **errmsg)
+{
+ assert(errmsg);
+ *errmsg = NULL;
+
+ char *result = x_strdup("");
+ const char *p = str; // Interval start.
+ const char *q = str; // Interval end.
+ for (q = str; *q; ++q) {
+ if (*q == '$') {
+ reformat(&result, "%s%.*s", result, (int)(q - p), p);
+ if (!expand_variable(&q, &result, errmsg)) {
+ free(result);
+ return NULL;
+ }
+ p = q + 1;
+ }
+ }
+ reformat(&result, "%s%.*s", result, (int)(q - p), p);
+ return result;
+}
diff --git a/version.c b/version.c
new file mode 100644
index 0000000..7866f76
--- /dev/null
+++ b/version.c
@@ -0,0 +1 @@
+const char CCACHE_VERSION[] = "3.3.4";
diff --git a/zlib/adler32.c b/zlib/adler32.c
new file mode 100644
index 0000000..a868f07
--- /dev/null
+++ b/zlib/adler32.c
@@ -0,0 +1,179 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2011 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#define local static
+
+local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
+
+#define BASE 65521 /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware --
+ try it both ways to see which is faster */
+#ifdef NO_DIVIDE
+/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
+ (thank you to John Reiser for pointing this out) */
+# define CHOP(a) \
+ do { \
+ unsigned long tmp = a >> 16; \
+ a &= 0xffffUL; \
+ a += (tmp << 4) - tmp; \
+ } while (0)
+# define MOD28(a) \
+ do { \
+ CHOP(a); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD(a) \
+ do { \
+ CHOP(a); \
+ MOD28(a); \
+ } while (0)
+# define MOD63(a) \
+ do { /* this assumes a is not negative */ \
+ z_off64_t tmp = a >> 32; \
+ a &= 0xffffffffL; \
+ a += (tmp << 8) - (tmp << 5) + tmp; \
+ tmp = a >> 16; \
+ a &= 0xffffL; \
+ a += (tmp << 4) - tmp; \
+ tmp = a >> 16; \
+ a &= 0xffffL; \
+ a += (tmp << 4) - tmp; \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD28(a) a %= BASE
+# define MOD63(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD28(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* for negative len, return invalid adler32 as a clue for debugging */
+ if (len2 < 0)
+ return 0xffffffffUL;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ MOD63(len2); /* assumes len2 >= 0 */
+ rem = (unsigned)len2;
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 >= BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
diff --git a/zlib/crc32.c b/zlib/crc32.c
new file mode 100644
index 0000000..979a719
--- /dev/null
+++ b/zlib/crc32.c
@@ -0,0 +1,425 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+
+ DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Definitions for doing the crc four data bytes at a time. */
+#if !defined(NOBYFOUR) && defined(Z_U4)
+# define BYFOUR
+#endif
+#ifdef BYFOUR
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));
+
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local z_crc_t FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const z_crc_t FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ z_crc_t c;
+ int n, k;
+ z_crc_t poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0;
+ for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
+ poly |= (z_crc_t)1 << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (z_crc_t)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = ZSWAP32(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = ZSWAP32(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const z_crc_t FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const z_crc_t FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ",
+ (unsigned long)(table[n]),
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const z_crc_t FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const z_crc_t FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ uInt len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ z_crc_t endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register z_crc_t c;
+ register const z_crc_t FAR *buf4;
+
+ c = (z_crc_t)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register z_crc_t c;
+ register const z_crc_t FAR *buf4;
+
+ c = ZSWAP32((z_crc_t)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(ZSWAP32(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+local uLong crc32_combine_(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case (also disallow negative lengths) */
+ if (len2 <= 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
+
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
diff --git a/zlib/crc32.h b/zlib/crc32.h
new file mode 100644
index 0000000..9e0c778
--- /dev/null
+++ b/zlib/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const z_crc_t FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/zlib/deflate.c b/zlib/deflate.c
new file mode 100644
index 0000000..6969577
--- /dev/null
+++ b/zlib/deflate.c
@@ -0,0 +1,1967 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://tools.ietf.org/html/rfc1951
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local block_state deflate_rle OF((deflate_state *s, int flush));
+local block_state deflate_huff OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */
+#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0))
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+#endif
+ }
+ if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zfree = zcfree;
+#endif
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->high_water = 0; /* nothing written to s->window yet */
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt str, n;
+ int wrap;
+ unsigned avail;
+ z_const unsigned char *next;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+ return Z_STREAM_ERROR;
+ s = strm->state;
+ wrap = s->wrap;
+ if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)
+ return Z_STREAM_ERROR;
+
+ /* when using zlib wrappers, compute Adler-32 for provided dictionary */
+ if (wrap == 1)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+ s->wrap = 0; /* avoid computing Adler-32 in read_buf */
+
+ /* if dictionary would fill window, just replace the history */
+ if (dictLength >= s->w_size) {
+ if (wrap == 0) { /* already empty otherwise */
+ CLEAR_HASH(s);
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->insert = 0;
+ }
+ dictionary += dictLength - s->w_size; /* use the tail */
+ dictLength = s->w_size;
+ }
+
+ /* insert dictionary into window and hash */
+ avail = strm->avail_in;
+ next = strm->next_in;
+ strm->avail_in = dictLength;
+ strm->next_in = (z_const Bytef *)dictionary;
+ fill_window(s);
+ while (s->lookahead >= MIN_MATCH) {
+ str = s->strstart;
+ n = s->lookahead - (MIN_MATCH-1);
+ do {
+ UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+ s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+ s->head[s->ins_h] = (Pos)str;
+ str++;
+ } while (--n);
+ s->strstart = str;
+ s->lookahead = MIN_MATCH-1;
+ fill_window(s);
+ }
+ s->strstart += s->lookahead;
+ s->block_start = (long)s->strstart;
+ s->insert = s->lookahead;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ strm->next_in = next;
+ strm->avail_in = avail;
+ s->wrap = wrap;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateResetKeep (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ int ret;
+
+ ret = deflateResetKeep(strm);
+ if (ret == Z_OK)
+ lm_init(strm->state);
+ return ret;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePending (strm, pending, bits)
+ unsigned *pending;
+ int *bits;
+ z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (pending != Z_NULL)
+ *pending = strm->state->pending;
+ if (bits != Z_NULL)
+ *bits = strm->state->bi_valid;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ deflate_state *s;
+ int put;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
+ return Z_BUF_ERROR;
+ do {
+ put = Buf_size - s->bi_valid;
+ if (put > bits)
+ put = bits;
+ s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);
+ s->bi_valid += put;
+ _tr_flush_bits(s);
+ value >>= put;
+ bits -= put;
+ } while (bits);
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if ((strategy != s->strategy || func != configuration_table[level].func) &&
+ strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_BLOCK);
+ if (err == Z_BUF_ERROR && s->pending == 0)
+ err = Z_OK;
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds for
+ * every combination of windowBits and memLevel. But even the conservative
+ * upper bound of about 14% expansion does not seem onerous for output buffer
+ * allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong complen, wraplen;
+ Bytef *str;
+
+ /* conservative upper bound for compressed data */
+ complen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
+
+ /* if can't get parameters, return conservative bound plus zlib wrapper */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return complen + 6;
+
+ /* compute wrapper length */
+ s = strm->state;
+ switch (s->wrap) {
+ case 0: /* raw deflate */
+ wraplen = 0;
+ break;
+ case 1: /* zlib wrapper */
+ wraplen = 6 + (s->strstart ? 4 : 0);
+ break;
+ case 2: /* gzip wrapper */
+ wraplen = 18;
+ if (s->gzhead != Z_NULL) { /* user-supplied gzip header */
+ if (s->gzhead->extra != Z_NULL)
+ wraplen += 2 + s->gzhead->extra_len;
+ str = s->gzhead->name;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ str = s->gzhead->comment;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ if (s->gzhead->hcrc)
+ wraplen += 2;
+ }
+ break;
+ default: /* for compiler happiness */
+ wraplen = 6;
+ }
+
+ /* if not default parameters, return conservative bound */
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return complen + wraplen;
+
+ /* default settings: return tight bound for that case */
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+ (sourceLen >> 25) + 13 - 6 + wraplen;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len;
+ deflate_state *s = strm->state;
+
+ _tr_flush_bits(s);
+ len = s->pending;
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, s->pending_out, len);
+ strm->next_out += len;
+ s->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ s->pending -= len;
+ if (s->pending == 0) {
+ s->pending_out = s->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_BLOCK || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == Z_NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != Z_NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+ (s->strategy == Z_RLE ? deflate_rle(s, flush) :
+ (*(configuration_table[s->level].func))(s, flush));
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ if (s->lookahead == 0) {
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->insert = 0;
+ }
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ zmemcpy(buf, strm->next_in, len);
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, buf, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, buf, len);
+ }
+#endif
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->insert = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+
+#else /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#endif /* FASTEST */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) break;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead + s->insert >= MIN_MATCH) {
+ uInt str = s->strstart - s->insert;
+ s->ins_h = s->window[str];
+ UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ while (s->insert) {
+ UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+ s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+ s->head[s->ins_h] = (Pos)str;
+ str++;
+ s->insert--;
+ if (s->lookahead + s->insert < MIN_MATCH)
+ break;
+ }
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+ /* If the WIN_INIT bytes after the end of the current data have never been
+ * written, then zero those bytes in order to avoid memory check reports of
+ * the use of uninitialized (or uninitialised as Julian writes) bytes by
+ * the longest match routines. Update the high water mark for the next
+ * time through here. WIN_INIT is set to MAX_MATCH since the longest match
+ * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+ */
+ if (s->high_water < s->window_size) {
+ ulg curr = s->strstart + (ulg)(s->lookahead);
+ ulg init;
+
+ if (s->high_water < curr) {
+ /* Previous high water mark below current data -- zero WIN_INIT
+ * bytes or up to end of window, whichever is less.
+ */
+ init = s->window_size - curr;
+ if (init > WIN_INIT)
+ init = WIN_INIT;
+ zmemzero(s->window + curr, (unsigned)init);
+ s->high_water = curr + init;
+ }
+ else if (s->high_water < (ulg)curr + WIN_INIT) {
+ /* High water mark at or above current data, but below current data
+ * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+ * to end of window, whichever is less.
+ */
+ init = (ulg)curr + WIN_INIT - s->high_water;
+ if (init > s->window_size - s->high_water)
+ init = s->window_size - s->high_water;
+ zmemzero(s->window + s->high_water, (unsigned)init);
+ s->high_water += init;
+ }
+ }
+
+ Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
+ "not enough room for search");
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, last) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (last)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, last) { \
+ FLUSH_BLOCK_ONLY(s, last); \
+ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ s->insert = 0;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if ((long)s->strstart > s->block_start)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+#endif /* FASTEST */
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan, *strend; /* scan goes up to strend for length of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest run, plus one for the unrolled loop.
+ */
+ if (s->lookahead <= MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ s->match_length = 0;
+ if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
+ scan = s->window + s->strstart - 1;
+ prev = *scan;
+ if (prev == *++scan && prev == *++scan && prev == *++scan) {
+ strend = s->window + s->strstart + MAX_MATCH;
+ do {
+ } while (prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ scan < strend);
+ s->match_length = MAX_MATCH - (int)(strend - scan);
+ if (s->match_length > s->lookahead)
+ s->match_length = s->lookahead;
+ }
+ Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, s->match_length);
+
+ _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ s->insert = 0;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+local block_state deflate_huff(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we have a literal to write. */
+ if (s->lookahead == 0) {
+ fill_window(s);
+ if (s->lookahead == 0) {
+ if (flush == Z_NO_FLUSH)
+ return need_more;
+ break; /* flush the current block */
+ }
+ }
+
+ /* Output a literal byte */
+ s->match_length = 0;
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ s->insert = 0;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
diff --git a/zlib/deflate.h b/zlib/deflate.h
new file mode 100644
index 0000000..ce0299e
--- /dev/null
+++ b/zlib/deflate.h
@@ -0,0 +1,346 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2012 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define Buf_size 16
+/* size of bit buffer in bi_buf */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* can only be DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to suppress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ uInt insert; /* bytes at end of window left to insert */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+ ulg high_water;
+ /* High water mark offset in window for initialized bytes -- bytes above
+ * this are set to zero in order to avoid memory check warnings when
+ * longest match routines access bytes past the input. This is then
+ * updated to the new high water mark.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define WIN_INIT MAX_MATCH
+/* Number of bytes after end of data in window to initialize in order to avoid
+ memory checker errors from longest match routines */
+
+ /* in trees.c */
+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch ZLIB_INTERNAL _length_code[];
+ extern uch ZLIB_INTERNAL _dist_code[];
+#else
+ extern const uch ZLIB_INTERNAL _length_code[];
+ extern const uch ZLIB_INTERNAL _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/zlib/gzclose.c b/zlib/gzclose.c
new file mode 100644
index 0000000..caeb99a
--- /dev/null
+++ b/zlib/gzclose.c
@@ -0,0 +1,25 @@
+/* gzclose.c -- zlib gzclose() function
+ * Copyright (C) 2004, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* gzclose() is in a separate file so that it is linked in only if it is used.
+ That way the other gzclose functions can be used instead to avoid linking in
+ unneeded compression or decompression routines. */
+int ZEXPORT gzclose(file)
+ gzFile file;
+{
+#ifndef NO_GZCOMPRESS
+ gz_statep state;
+
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file);
+#else
+ return gzclose_r(file);
+#endif
+}
diff --git a/zlib/gzguts.h b/zlib/gzguts.h
new file mode 100644
index 0000000..d87659d
--- /dev/null
+++ b/zlib/gzguts.h
@@ -0,0 +1,209 @@
+/* gzguts.h -- zlib internal header definitions for gz* operations
+ * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifdef _LARGEFILE64_SOURCE
+# ifndef _LARGEFILE_SOURCE
+# define _LARGEFILE_SOURCE 1
+# endif
+# ifdef _FILE_OFFSET_BITS
+# undef _FILE_OFFSET_BITS
+# endif
+#endif
+
+#ifdef HAVE_HIDDEN
+# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+# define ZLIB_INTERNAL
+#endif
+
+#include <stdio.h>
+#include "zlib.h"
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+# include <limits.h>
+#endif
+#include <fcntl.h>
+
+#ifdef _WIN32
+# include <stddef.h>
+#endif
+
+#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
+# include <io.h>
+#endif
+
+#ifdef WINAPI_FAMILY
+# define open _open
+# define read _read
+# define write _write
+# define close _close
+#endif
+
+#ifdef NO_DEFLATE /* for compatibility with old definition */
+# define NO_GZCOMPRESS
+#endif
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+
+#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+# ifdef VMS
+# define NO_vsnprintf
+# endif
+# ifdef __OS400__
+# define NO_vsnprintf
+# endif
+# ifdef __MVS__
+# define NO_vsnprintf
+# endif
+#endif
+
+/* unlike snprintf (which is required in C99, yet still not supported by
+ Microsoft more than a decade later!), _snprintf does not guarantee null
+ termination of the result -- however this is only used in gzlib.c where
+ the result is assured to fit in the space provided */
+#ifdef _MSC_VER
+# define snprintf _snprintf
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+/* gz* functions always use library allocation functions */
+#ifndef STDC
+ extern voidp malloc OF((uInt size));
+ extern void free OF((voidpf ptr));
+#endif
+
+/* get errno and strerror definition */
+#if defined UNDER_CE
+# include <windows.h>
+# define zstrerror() gz_strwinerror((DWORD)GetLastError())
+#else
+# ifndef NO_STRERROR
+# include <errno.h>
+# define zstrerror() strerror(errno)
+# else
+# define zstrerror() "stdio error (consult errno)"
+# endif
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+#endif
+
+/* default memLevel */
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+
+/* default i/o buffer size -- double this for output when reading (this and
+ twice this must be able to fit in an unsigned type) */
+#define GZBUFSIZE 8192
+
+/* gzip modes, also provide a little integrity check on the passed structure */
+#define GZ_NONE 0
+#define GZ_READ 7247
+#define GZ_WRITE 31153
+#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */
+
+/* values for gz_state how */
+#define LOOK 0 /* look for a gzip header */
+#define COPY 1 /* copy input directly */
+#define GZIP 2 /* decompress a gzip stream */
+
+/* internal gzip file state data structure */
+typedef struct {
+ /* exposed contents for gzgetc() macro */
+ struct gzFile_s x; /* "x" for exposed */
+ /* x.have: number of bytes available at x.next */
+ /* x.next: next output data to deliver or write */
+ /* x.pos: current position in uncompressed data */
+ /* used for both reading and writing */
+ int mode; /* see gzip modes above */
+ int fd; /* file descriptor */
+ char *path; /* path or fd for error messages */
+ unsigned size; /* buffer size, zero if not allocated yet */
+ unsigned want; /* requested buffer size, default is GZBUFSIZE */
+ unsigned char *in; /* input buffer */
+ unsigned char *out; /* output buffer (double-sized when reading) */
+ int direct; /* 0 if processing gzip, 1 if transparent */
+ /* just for reading */
+ int how; /* 0: get header, 1: copy, 2: decompress */
+ z_off64_t start; /* where the gzip data started, for rewinding */
+ int eof; /* true if end of input file reached */
+ int past; /* true if read requested past end */
+ /* just for writing */
+ int level; /* compression level */
+ int strategy; /* compression strategy */
+ /* seek request */
+ z_off64_t skip; /* amount to skip (already rewound if backwards) */
+ int seek; /* true if seek request pending */
+ /* error information */
+ int err; /* error code */
+ char *msg; /* error message */
+ /* zlib inflate or deflate stream */
+ z_stream strm; /* stream structure in-place (not a pointer) */
+} gz_state;
+typedef gz_state FAR *gz_statep;
+
+/* shared functions */
+void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
+#if defined UNDER_CE
+char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
+#endif
+
+/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
+ value -- needed when comparing unsigned to z_off64_t, which is signed
+ (possible z_off64_t types off_t, off64_t, and long are all signed) */
+#ifdef INT_MAX
+# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
+#else
+unsigned ZLIB_INTERNAL gz_intmax OF((void));
+# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
+#endif
diff --git a/zlib/gzlib.c b/zlib/gzlib.c
new file mode 100644
index 0000000..fae202e
--- /dev/null
+++ b/zlib/gzlib.c
@@ -0,0 +1,634 @@
+/* gzlib.c -- zlib functions common to reading and writing gzip files
+ * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+#if defined(_WIN32) && !defined(__BORLANDC__)
+# define LSEEK _lseeki64
+#else
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+# define LSEEK lseek64
+#else
+# define LSEEK lseek
+#endif
+#endif
+
+/* Local functions */
+local void gz_reset OF((gz_statep));
+local gzFile gz_open OF((const void *, int, const char *));
+
+#if defined UNDER_CE
+
+/* Map the Windows error number in ERROR to a locale-dependent error message
+ string and return a pointer to it. Typically, the values for ERROR come
+ from GetLastError.
+
+ The string pointed to shall not be modified by the application, but may be
+ overwritten by a subsequent call to gz_strwinerror
+
+ The gz_strwinerror function does not change the current setting of
+ GetLastError. */
+char ZLIB_INTERNAL *gz_strwinerror (error)
+ DWORD error;
+{
+ static char buf[1024];
+
+ wchar_t *msgbuf;
+ DWORD lasterr = GetLastError();
+ DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ error,
+ 0, /* Default language */
+ (LPVOID)&msgbuf,
+ 0,
+ NULL);
+ if (chars != 0) {
+ /* If there is an \r\n appended, zap it. */
+ if (chars >= 2
+ && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
+ chars -= 2;
+ msgbuf[chars] = 0;
+ }
+
+ if (chars > sizeof (buf) - 1) {
+ chars = sizeof (buf) - 1;
+ msgbuf[chars] = 0;
+ }
+
+ wcstombs(buf, msgbuf, chars + 1);
+ LocalFree(msgbuf);
+ }
+ else {
+ sprintf(buf, "unknown win32 error (%ld)", error);
+ }
+
+ SetLastError(lasterr);
+ return buf;
+}
+
+#endif /* UNDER_CE */
+
+/* Reset gzip file state */
+local void gz_reset(state)
+ gz_statep state;
+{
+ state->x.have = 0; /* no output data available */
+ if (state->mode == GZ_READ) { /* for reading ... */
+ state->eof = 0; /* not at end of file */
+ state->past = 0; /* have not read past end yet */
+ state->how = LOOK; /* look for gzip header */
+ }
+ state->seek = 0; /* no seek request pending */
+ gz_error(state, Z_OK, NULL); /* clear error */
+ state->x.pos = 0; /* no uncompressed data yet */
+ state->strm.avail_in = 0; /* no input data yet */
+}
+
+/* Open a gzip file either by name or file descriptor. */
+local gzFile gz_open(path, fd, mode)
+ const void *path;
+ int fd;
+ const char *mode;
+{
+ gz_statep state;
+ size_t len;
+ int oflag;
+#ifdef O_CLOEXEC
+ int cloexec = 0;
+#endif
+#ifdef O_EXCL
+ int exclusive = 0;
+#endif
+
+ /* check input */
+ if (path == NULL)
+ return NULL;
+
+ /* allocate gzFile structure to return */
+ state = (gz_statep)malloc(sizeof(gz_state));
+ if (state == NULL)
+ return NULL;
+ state->size = 0; /* no buffers allocated yet */
+ state->want = GZBUFSIZE; /* requested buffer size */
+ state->msg = NULL; /* no error message yet */
+
+ /* interpret mode */
+ state->mode = GZ_NONE;
+ state->level = Z_DEFAULT_COMPRESSION;
+ state->strategy = Z_DEFAULT_STRATEGY;
+ state->direct = 0;
+ while (*mode) {
+ if (*mode >= '0' && *mode <= '9')
+ state->level = *mode - '0';
+ else
+ switch (*mode) {
+ case 'r':
+ state->mode = GZ_READ;
+ break;
+#ifndef NO_GZCOMPRESS
+ case 'w':
+ state->mode = GZ_WRITE;
+ break;
+ case 'a':
+ state->mode = GZ_APPEND;
+ break;
+#endif
+ case '+': /* can't read and write at the same time */
+ free(state);
+ return NULL;
+ case 'b': /* ignore -- will request binary anyway */
+ break;
+#ifdef O_CLOEXEC
+ case 'e':
+ cloexec = 1;
+ break;
+#endif
+#ifdef O_EXCL
+ case 'x':
+ exclusive = 1;
+ break;
+#endif
+ case 'f':
+ state->strategy = Z_FILTERED;
+ break;
+ case 'h':
+ state->strategy = Z_HUFFMAN_ONLY;
+ break;
+ case 'R':
+ state->strategy = Z_RLE;
+ break;
+ case 'F':
+ state->strategy = Z_FIXED;
+ break;
+ case 'T':
+ state->direct = 1;
+ break;
+ default: /* could consider as an error, but just ignore */
+ ;
+ }
+ mode++;
+ }
+
+ /* must provide an "r", "w", or "a" */
+ if (state->mode == GZ_NONE) {
+ free(state);
+ return NULL;
+ }
+
+ /* can't force transparent read */
+ if (state->mode == GZ_READ) {
+ if (state->direct) {
+ free(state);
+ return NULL;
+ }
+ state->direct = 1; /* for empty file */
+ }
+
+ /* save the path name for error messages */
+#ifdef _WIN32
+ if (fd == -2) {
+ len = wcstombs(NULL, path, 0);
+ if (len == (size_t)-1)
+ len = 0;
+ }
+ else
+#endif
+ len = strlen((const char *)path);
+ state->path = (char *)malloc(len + 1);
+ if (state->path == NULL) {
+ free(state);
+ return NULL;
+ }
+#ifdef _WIN32
+ if (fd == -2)
+ if (len)
+ wcstombs(state->path, path, len + 1);
+ else
+ *(state->path) = 0;
+ else
+#endif
+#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
+ snprintf(state->path, len + 1, "%s", (const char *)path);
+#else
+ strcpy(state->path, path);
+#endif
+
+ /* compute the flags for open() */
+ oflag =
+#ifdef O_LARGEFILE
+ O_LARGEFILE |
+#endif
+#ifdef O_BINARY
+ O_BINARY |
+#endif
+#ifdef O_CLOEXEC
+ (cloexec ? O_CLOEXEC : 0) |
+#endif
+ (state->mode == GZ_READ ?
+ O_RDONLY :
+ (O_WRONLY | O_CREAT |
+#ifdef O_EXCL
+ (exclusive ? O_EXCL : 0) |
+#endif
+ (state->mode == GZ_WRITE ?
+ O_TRUNC :
+ O_APPEND)));
+
+ /* open the file with the appropriate flags (or just use fd) */
+ state->fd = fd > -1 ? fd : (
+#ifdef _WIN32
+ fd == -2 ? _wopen(path, oflag, 0666) :
+#endif
+ open((const char *)path, oflag, 0666));
+ if (state->fd == -1) {
+ free(state->path);
+ free(state);
+ return NULL;
+ }
+ if (state->mode == GZ_APPEND)
+ state->mode = GZ_WRITE; /* simplify later checks */
+
+ /* save the current position for rewinding (only if reading) */
+ if (state->mode == GZ_READ) {
+ state->start = LSEEK(state->fd, 0, SEEK_CUR);
+ if (state->start == -1) state->start = 0;
+ }
+
+ /* initialize stream */
+ gz_reset(state);
+
+ /* return stream */
+ return (gzFile)state;
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen(path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen64(path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzdopen(fd, mode)
+ int fd;
+ const char *mode;
+{
+ char *path; /* identifier for error messages */
+ gzFile gz;
+
+ if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
+ return NULL;
+#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
+ snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */
+#else
+ sprintf(path, "<fd:%d>", fd); /* for debugging */
+#endif
+ gz = gz_open(path, fd, mode);
+ free(path);
+ return gz;
+}
+
+/* -- see zlib.h -- */
+#ifdef _WIN32
+gzFile ZEXPORT gzopen_w(path, mode)
+ const wchar_t *path;
+ const char *mode;
+{
+ return gz_open(path, -2, mode);
+}
+#endif
+
+/* -- see zlib.h -- */
+int ZEXPORT gzbuffer(file, size)
+ gzFile file;
+ unsigned size;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* make sure we haven't already allocated memory */
+ if (state->size != 0)
+ return -1;
+
+ /* check and set requested size */
+ if (size < 2)
+ size = 2; /* need two bytes to check magic header */
+ state->want = size;
+ return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzrewind(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return -1;
+
+ /* back up and start over */
+ if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
+ return -1;
+ gz_reset(state);
+ return 0;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzseek64(file, offset, whence)
+ gzFile file;
+ z_off64_t offset;
+ int whence;
+{
+ unsigned n;
+ z_off64_t ret;
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* check that there's no error */
+ if (state->err != Z_OK && state->err != Z_BUF_ERROR)
+ return -1;
+
+ /* can only seek from start or relative to current position */
+ if (whence != SEEK_SET && whence != SEEK_CUR)
+ return -1;
+
+ /* normalize offset to a SEEK_CUR specification */
+ if (whence == SEEK_SET)
+ offset -= state->x.pos;
+ else if (state->seek)
+ offset += state->skip;
+ state->seek = 0;
+
+ /* if within raw area while reading, just go there */
+ if (state->mode == GZ_READ && state->how == COPY &&
+ state->x.pos + offset >= 0) {
+ ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
+ if (ret == -1)
+ return -1;
+ state->x.have = 0;
+ state->eof = 0;
+ state->past = 0;
+ state->seek = 0;
+ gz_error(state, Z_OK, NULL);
+ state->strm.avail_in = 0;
+ state->x.pos += offset;
+ return state->x.pos;
+ }
+
+ /* calculate skip amount, rewinding if needed for back seek when reading */
+ if (offset < 0) {
+ if (state->mode != GZ_READ) /* writing -- can't go backwards */
+ return -1;
+ offset += state->x.pos;
+ if (offset < 0) /* before start of file! */
+ return -1;
+ if (gzrewind(file) == -1) /* rewind, then skip to offset */
+ return -1;
+ }
+
+ /* if reading, skip what's in output buffer (one less gzgetc() check) */
+ if (state->mode == GZ_READ) {
+ n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
+ (unsigned)offset : state->x.have;
+ state->x.have -= n;
+ state->x.next += n;
+ state->x.pos += n;
+ offset -= n;
+ }
+
+ /* request skip (if not zero) */
+ if (offset) {
+ state->seek = 1;
+ state->skip = offset;
+ }
+ return state->x.pos + offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzseek(file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ z_off64_t ret;
+
+ ret = gzseek64(file, (z_off64_t)offset, whence);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gztell64(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* return position */
+ return state->x.pos + (state->seek ? state->skip : 0);
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gztell(file)
+ gzFile file;
+{
+ z_off64_t ret;
+
+ ret = gztell64(file);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzoffset64(file)
+ gzFile file;
+{
+ z_off64_t offset;
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* compute and return effective offset in file */
+ offset = LSEEK(state->fd, 0, SEEK_CUR);
+ if (offset == -1)
+ return -1;
+ if (state->mode == GZ_READ) /* reading */
+ offset -= state->strm.avail_in; /* don't count buffered input */
+ return offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzoffset(file)
+ gzFile file;
+{
+ z_off64_t ret;
+
+ ret = gzoffset64(file);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzeof(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return 0;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return 0;
+
+ /* return end-of-file state */
+ return state->mode == GZ_READ ? state->past : 0;
+}
+
+/* -- see zlib.h -- */
+const char * ZEXPORT gzerror(file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return NULL;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return NULL;
+
+ /* return error information */
+ if (errnum != NULL)
+ *errnum = state->err;
+ return state->err == Z_MEM_ERROR ? "out of memory" :
+ (state->msg == NULL ? "" : state->msg);
+}
+
+/* -- see zlib.h -- */
+void ZEXPORT gzclearerr(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return;
+
+ /* clear error and end-of-file */
+ if (state->mode == GZ_READ) {
+ state->eof = 0;
+ state->past = 0;
+ }
+ gz_error(state, Z_OK, NULL);
+}
+
+/* Create an error message in allocated memory and set state->err and
+ state->msg accordingly. Free any previous error message already there. Do
+ not try to free or allocate space if the error is Z_MEM_ERROR (out of
+ memory). Simply save the error message as a static string. If there is an
+ allocation failure constructing the error message, then convert the error to
+ out of memory. */
+void ZLIB_INTERNAL gz_error(state, err, msg)
+ gz_statep state;
+ int err;
+ const char *msg;
+{
+ /* free previously allocated message and clear */
+ if (state->msg != NULL) {
+ if (state->err != Z_MEM_ERROR)
+ free(state->msg);
+ state->msg = NULL;
+ }
+
+ /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
+ if (err != Z_OK && err != Z_BUF_ERROR)
+ state->x.have = 0;
+
+ /* set error code, and if no message, then done */
+ state->err = err;
+ if (msg == NULL)
+ return;
+
+ /* for an out of memory error, return literal string when requested */
+ if (err == Z_MEM_ERROR)
+ return;
+
+ /* construct error message with path */
+ if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
+ NULL) {
+ state->err = Z_MEM_ERROR;
+ return;
+ }
+#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
+ snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
+ "%s%s%s", state->path, ": ", msg);
+#else
+ strcpy(state->msg, state->path);
+ strcat(state->msg, ": ");
+ strcat(state->msg, msg);
+#endif
+ return;
+}
+
+#ifndef INT_MAX
+/* portably return maximum value for an int (when limits.h presumed not
+ available) -- we need to do this to cover cases where 2's complement not
+ used, since C standard permits 1's complement and sign-bit representations,
+ otherwise we could just use ((unsigned)-1) >> 1 */
+unsigned ZLIB_INTERNAL gz_intmax()
+{
+ unsigned p, q;
+
+ p = 1;
+ do {
+ q = p;
+ p <<= 1;
+ p++;
+ } while (p > q);
+ return q >> 1;
+}
+#endif
diff --git a/zlib/gzread.c b/zlib/gzread.c
new file mode 100644
index 0000000..bf4538e
--- /dev/null
+++ b/zlib/gzread.c
@@ -0,0 +1,594 @@
+/* gzread.c -- zlib functions for reading gzip files
+ * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
+local int gz_avail OF((gz_statep));
+local int gz_look OF((gz_statep));
+local int gz_decomp OF((gz_statep));
+local int gz_fetch OF((gz_statep));
+local int gz_skip OF((gz_statep, z_off64_t));
+
+/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
+ state->fd, and update state->eof, state->err, and state->msg as appropriate.
+ This function needs to loop on read(), since read() is not guaranteed to
+ read the number of bytes requested, depending on the type of descriptor. */
+local int gz_load(state, buf, len, have)
+ gz_statep state;
+ unsigned char *buf;
+ unsigned len;
+ unsigned *have;
+{
+ int ret;
+
+ *have = 0;
+ do {
+ ret = read(state->fd, buf + *have, len - *have);
+ if (ret <= 0)
+ break;
+ *have += ret;
+ } while (*have < len);
+ if (ret < 0) {
+ gz_error(state, Z_ERRNO, zstrerror());
+ return -1;
+ }
+ if (ret == 0)
+ state->eof = 1;
+ return 0;
+}
+
+/* Load up input buffer and set eof flag if last data loaded -- return -1 on
+ error, 0 otherwise. Note that the eof flag is set when the end of the input
+ file is reached, even though there may be unused data in the buffer. Once
+ that data has been used, no more attempts will be made to read the file.
+ If strm->avail_in != 0, then the current data is moved to the beginning of
+ the input buffer, and then the remainder of the buffer is loaded with the
+ available data from the input file. */
+local int gz_avail(state)
+ gz_statep state;
+{
+ unsigned got;
+ z_streamp strm = &(state->strm);
+
+ if (state->err != Z_OK && state->err != Z_BUF_ERROR)
+ return -1;
+ if (state->eof == 0) {
+ if (strm->avail_in) { /* copy what's there to the start */
+ unsigned char *p = state->in;
+ unsigned const char *q = strm->next_in;
+ unsigned n = strm->avail_in;
+ do {
+ *p++ = *q++;
+ } while (--n);
+ }
+ if (gz_load(state, state->in + strm->avail_in,
+ state->size - strm->avail_in, &got) == -1)
+ return -1;
+ strm->avail_in += got;
+ strm->next_in = state->in;
+ }
+ return 0;
+}
+
+/* Look for gzip header, set up for inflate or copy. state->x.have must be 0.
+ If this is the first time in, allocate required memory. state->how will be
+ left unchanged if there is no more input data available, will be set to COPY
+ if there is no gzip header and direct copying will be performed, or it will
+ be set to GZIP for decompression. If direct copying, then leftover input
+ data from the input buffer will be copied to the output buffer. In that
+ case, all further file reads will be directly to either the output buffer or
+ a user buffer. If decompressing, the inflate state will be initialized.
+ gz_look() will return 0 on success or -1 on failure. */
+local int gz_look(state)
+ gz_statep state;
+{
+ z_streamp strm = &(state->strm);
+
+ /* allocate read buffers and inflate memory */
+ if (state->size == 0) {
+ /* allocate buffers */
+ state->in = (unsigned char *)malloc(state->want);
+ state->out = (unsigned char *)malloc(state->want << 1);
+ if (state->in == NULL || state->out == NULL) {
+ if (state->out != NULL)
+ free(state->out);
+ if (state->in != NULL)
+ free(state->in);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ state->size = state->want;
+
+ /* allocate inflate memory */
+ state->strm.zalloc = Z_NULL;
+ state->strm.zfree = Z_NULL;
+ state->strm.opaque = Z_NULL;
+ state->strm.avail_in = 0;
+ state->strm.next_in = Z_NULL;
+ if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */
+ free(state->out);
+ free(state->in);
+ state->size = 0;
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ }
+
+ /* get at least the magic bytes in the input buffer */
+ if (strm->avail_in < 2) {
+ if (gz_avail(state) == -1)
+ return -1;
+ if (strm->avail_in == 0)
+ return 0;
+ }
+
+ /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
+ a logical dilemma here when considering the case of a partially written
+ gzip file, to wit, if a single 31 byte is written, then we cannot tell
+ whether this is a single-byte file, or just a partially written gzip
+ file -- for here we assume that if a gzip file is being written, then
+ the header will be written in a single operation, so that reading a
+ single byte is sufficient indication that it is not a gzip file) */
+ if (strm->avail_in > 1 &&
+ strm->next_in[0] == 31 && strm->next_in[1] == 139) {
+ inflateReset(strm);
+ state->how = GZIP;
+ state->direct = 0;
+ return 0;
+ }
+
+ /* no gzip header -- if we were decoding gzip before, then this is trailing
+ garbage. Ignore the trailing garbage and finish. */
+ if (state->direct == 0) {
+ strm->avail_in = 0;
+ state->eof = 1;
+ state->x.have = 0;
+ return 0;
+ }
+
+ /* doing raw i/o, copy any leftover input to output -- this assumes that
+ the output buffer is larger than the input buffer, which also assures
+ space for gzungetc() */
+ state->x.next = state->out;
+ if (strm->avail_in) {
+ memcpy(state->x.next, strm->next_in, strm->avail_in);
+ state->x.have = strm->avail_in;
+ strm->avail_in = 0;
+ }
+ state->how = COPY;
+ state->direct = 1;
+ return 0;
+}
+
+/* Decompress from input to the provided next_out and avail_out in the state.
+ On return, state->x.have and state->x.next point to the just decompressed
+ data. If the gzip stream completes, state->how is reset to LOOK to look for
+ the next gzip stream or raw data, once state->x.have is depleted. Returns 0
+ on success, -1 on failure. */
+local int gz_decomp(state)
+ gz_statep state;
+{
+ int ret = Z_OK;
+ unsigned had;
+ z_streamp strm = &(state->strm);
+
+ /* fill output buffer up to end of deflate stream */
+ had = strm->avail_out;
+ do {
+ /* get more input for inflate() */
+ if (strm->avail_in == 0 && gz_avail(state) == -1)
+ return -1;
+ if (strm->avail_in == 0) {
+ gz_error(state, Z_BUF_ERROR, "unexpected end of file");
+ break;
+ }
+
+ /* decompress and handle errors */
+ ret = inflate(strm, Z_NO_FLUSH);
+ if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
+ gz_error(state, Z_STREAM_ERROR,
+ "internal error: inflate stream corrupt");
+ return -1;
+ }
+ if (ret == Z_MEM_ERROR) {
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ if (ret == Z_DATA_ERROR) { /* deflate stream invalid */
+ gz_error(state, Z_DATA_ERROR,
+ strm->msg == NULL ? "compressed data error" : strm->msg);
+ return -1;
+ }
+ } while (strm->avail_out && ret != Z_STREAM_END);
+
+ /* update available output */
+ state->x.have = had - strm->avail_out;
+ state->x.next = strm->next_out - state->x.have;
+
+ /* if the gzip stream completed successfully, look for another */
+ if (ret == Z_STREAM_END)
+ state->how = LOOK;
+
+ /* good decompression */
+ return 0;
+}
+
+/* Fetch data and put it in the output buffer. Assumes state->x.have is 0.
+ Data is either copied from the input file or decompressed from the input
+ file depending on state->how. If state->how is LOOK, then a gzip header is
+ looked for to determine whether to copy or decompress. Returns -1 on error,
+ otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the
+ end of the input file has been reached and all data has been processed. */
+local int gz_fetch(state)
+ gz_statep state;
+{
+ z_streamp strm = &(state->strm);
+
+ do {
+ switch(state->how) {
+ case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */
+ if (gz_look(state) == -1)
+ return -1;
+ if (state->how == LOOK)
+ return 0;
+ break;
+ case COPY: /* -> COPY */
+ if (gz_load(state, state->out, state->size << 1, &(state->x.have))
+ == -1)
+ return -1;
+ state->x.next = state->out;
+ return 0;
+ case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */
+ strm->avail_out = state->size << 1;
+ strm->next_out = state->out;
+ if (gz_decomp(state) == -1)
+ return -1;
+ }
+ } while (state->x.have == 0 && (!state->eof || strm->avail_in));
+ return 0;
+}
+
+/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
+local int gz_skip(state, len)
+ gz_statep state;
+ z_off64_t len;
+{
+ unsigned n;
+
+ /* skip over len bytes or reach end-of-file, whichever comes first */
+ while (len)
+ /* skip over whatever is in output buffer */
+ if (state->x.have) {
+ n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
+ (unsigned)len : state->x.have;
+ state->x.have -= n;
+ state->x.next += n;
+ state->x.pos += n;
+ len -= n;
+ }
+
+ /* output buffer empty -- return if we're at the end of the input */
+ else if (state->eof && state->strm.avail_in == 0)
+ break;
+
+ /* need more data to skip -- load up output buffer */
+ else {
+ /* get more output, looking for header if required */
+ if (gz_fetch(state) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzread(file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ unsigned got, n;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're reading and that there's no (serious) error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return -1;
+
+ /* since an int is returned, make sure len fits in one, otherwise return
+ with an error (this avoids the flaw in the interface) */
+ if ((int)len < 0) {
+ gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
+ return -1;
+ }
+
+ /* if len is zero, avoid unnecessary operations */
+ if (len == 0)
+ return 0;
+
+ /* process a skip request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_skip(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* get len bytes to buf, or less than len if at the end */
+ got = 0;
+ do {
+ /* first just try copying data from the output buffer */
+ if (state->x.have) {
+ n = state->x.have > len ? len : state->x.have;
+ memcpy(buf, state->x.next, n);
+ state->x.next += n;
+ state->x.have -= n;
+ }
+
+ /* output buffer empty -- return if we're at the end of the input */
+ else if (state->eof && strm->avail_in == 0) {
+ state->past = 1; /* tried to read past end */
+ break;
+ }
+
+ /* need output data -- for small len or new stream load up our output
+ buffer */
+ else if (state->how == LOOK || len < (state->size << 1)) {
+ /* get more output, looking for header if required */
+ if (gz_fetch(state) == -1)
+ return -1;
+ continue; /* no progress yet -- go back to copy above */
+ /* the copy above assures that we will leave with space in the
+ output buffer, allowing at least one gzungetc() to succeed */
+ }
+
+ /* large len -- read directly into user buffer */
+ else if (state->how == COPY) { /* read directly */
+ if (gz_load(state, (unsigned char *)buf, len, &n) == -1)
+ return -1;
+ }
+
+ /* large len -- decompress directly into user buffer */
+ else { /* state->how == GZIP */
+ strm->avail_out = len;
+ strm->next_out = (unsigned char *)buf;
+ if (gz_decomp(state) == -1)
+ return -1;
+ n = state->x.have;
+ state->x.have = 0;
+ }
+
+ /* update progress */
+ len -= n;
+ buf = (char *)buf + n;
+ got += n;
+ state->x.pos += n;
+ } while (len);
+
+ /* return number of bytes read into user buffer (will fit in int) */
+ return (int)got;
+}
+
+/* -- see zlib.h -- */
+#ifdef Z_PREFIX_SET
+# undef z_gzgetc
+#else
+# undef gzgetc
+#endif
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ int ret;
+ unsigned char buf[1];
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no (serious) error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return -1;
+
+ /* try output buffer (no need to check for skip request) */
+ if (state->x.have) {
+ state->x.have--;
+ state->x.pos++;
+ return *(state->x.next)++;
+ }
+
+ /* nothing there -- try gzread() */
+ ret = gzread(file, buf, 1);
+ return ret < 1 ? -1 : buf[0];
+}
+
+int ZEXPORT gzgetc_(file)
+gzFile file;
+{
+ return gzgetc(file);
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzungetc(c, file)
+ int c;
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no (serious) error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return -1;
+
+ /* process a skip request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_skip(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* can't push EOF */
+ if (c < 0)
+ return -1;
+
+ /* if output buffer empty, put byte at end (allows more pushing) */
+ if (state->x.have == 0) {
+ state->x.have = 1;
+ state->x.next = state->out + (state->size << 1) - 1;
+ state->x.next[0] = c;
+ state->x.pos--;
+ state->past = 0;
+ return c;
+ }
+
+ /* if no room, give up (must have already done a gzungetc()) */
+ if (state->x.have == (state->size << 1)) {
+ gz_error(state, Z_DATA_ERROR, "out of room to push characters");
+ return -1;
+ }
+
+ /* slide output data if needed and insert byte before existing data */
+ if (state->x.next == state->out) {
+ unsigned char *src = state->out + state->x.have;
+ unsigned char *dest = state->out + (state->size << 1);
+ while (src > state->out)
+ *--dest = *--src;
+ state->x.next = dest;
+ }
+ state->x.have++;
+ state->x.next--;
+ state->x.next[0] = c;
+ state->x.pos--;
+ state->past = 0;
+ return c;
+}
+
+/* -- see zlib.h -- */
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ unsigned left, n;
+ char *str;
+ unsigned char *eol;
+ gz_statep state;
+
+ /* check parameters and get internal structure */
+ if (file == NULL || buf == NULL || len < 1)
+ return NULL;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no (serious) error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return NULL;
+
+ /* process a skip request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_skip(state, state->skip) == -1)
+ return NULL;
+ }
+
+ /* copy output bytes up to new line or len - 1, whichever comes first --
+ append a terminating zero to the string (we don't check for a zero in
+ the contents, let the user worry about that) */
+ str = buf;
+ left = (unsigned)len - 1;
+ if (left) do {
+ /* assure that something is in the output buffer */
+ if (state->x.have == 0 && gz_fetch(state) == -1)
+ return NULL; /* error */
+ if (state->x.have == 0) { /* end of file */
+ state->past = 1; /* read past end */
+ break; /* return what we have */
+ }
+
+ /* look for end-of-line in current output buffer */
+ n = state->x.have > left ? left : state->x.have;
+ eol = (unsigned char *)memchr(state->x.next, '\n', n);
+ if (eol != NULL)
+ n = (unsigned)(eol - state->x.next) + 1;
+
+ /* copy through end-of-line, or remainder if not found */
+ memcpy(buf, state->x.next, n);
+ state->x.have -= n;
+ state->x.next += n;
+ state->x.pos += n;
+ left -= n;
+ buf += n;
+ } while (left && eol == NULL);
+
+ /* return terminated string, or if nothing, end of file */
+ if (buf == str)
+ return NULL;
+ buf[0] = 0;
+ return str;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzdirect(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return 0;
+ state = (gz_statep)file;
+
+ /* if the state is not known, but we can find out, then do so (this is
+ mainly for right after a gzopen() or gzdopen()) */
+ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
+ (void)gz_look(state);
+
+ /* return 1 if transparent, 0 if processing a gzip stream */
+ return state->direct;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_r(file)
+ gzFile file;
+{
+ int ret, err;
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ /* check that we're reading */
+ if (state->mode != GZ_READ)
+ return Z_STREAM_ERROR;
+
+ /* free memory and close file */
+ if (state->size) {
+ inflateEnd(&(state->strm));
+ free(state->out);
+ free(state->in);
+ }
+ err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
+ gz_error(state, Z_OK, NULL);
+ free(state->path);
+ ret = close(state->fd);
+ free(state);
+ return ret ? Z_ERRNO : err;
+}
diff --git a/zlib/gzwrite.c b/zlib/gzwrite.c
new file mode 100644
index 0000000..aa767fb
--- /dev/null
+++ b/zlib/gzwrite.c
@@ -0,0 +1,577 @@
+/* gzwrite.c -- zlib functions for writing gzip files
+ * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_init OF((gz_statep));
+local int gz_comp OF((gz_statep, int));
+local int gz_zero OF((gz_statep, z_off64_t));
+
+/* Initialize state for writing a gzip file. Mark initialization by setting
+ state->size to non-zero. Return -1 on failure or 0 on success. */
+local int gz_init(state)
+ gz_statep state;
+{
+ int ret;
+ z_streamp strm = &(state->strm);
+
+ /* allocate input buffer */
+ state->in = (unsigned char *)malloc(state->want);
+ if (state->in == NULL) {
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+
+ /* only need output buffer and deflate state if compressing */
+ if (!state->direct) {
+ /* allocate output buffer */
+ state->out = (unsigned char *)malloc(state->want);
+ if (state->out == NULL) {
+ free(state->in);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+
+ /* allocate deflate memory, set up for gzip compression */
+ strm->zalloc = Z_NULL;
+ strm->zfree = Z_NULL;
+ strm->opaque = Z_NULL;
+ ret = deflateInit2(strm, state->level, Z_DEFLATED,
+ MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
+ if (ret != Z_OK) {
+ free(state->out);
+ free(state->in);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ }
+
+ /* mark state as initialized */
+ state->size = state->want;
+
+ /* initialize write buffer if compressing */
+ if (!state->direct) {
+ strm->avail_out = state->size;
+ strm->next_out = state->out;
+ state->x.next = strm->next_out;
+ }
+ return 0;
+}
+
+/* Compress whatever is at avail_in and next_in and write to the output file.
+ Return -1 if there is an error writing to the output file, otherwise 0.
+ flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH,
+ then the deflate() state is reset to start a new gzip stream. If gz->direct
+ is true, then simply write to the output file without compressing, and
+ ignore flush. */
+local int gz_comp(state, flush)
+ gz_statep state;
+ int flush;
+{
+ int ret, got;
+ unsigned have;
+ z_streamp strm = &(state->strm);
+
+ /* allocate memory if this is the first time through */
+ if (state->size == 0 && gz_init(state) == -1)
+ return -1;
+
+ /* write directly if requested */
+ if (state->direct) {
+ got = write(state->fd, strm->next_in, strm->avail_in);
+ if (got < 0 || (unsigned)got != strm->avail_in) {
+ gz_error(state, Z_ERRNO, zstrerror());
+ return -1;
+ }
+ strm->avail_in = 0;
+ return 0;
+ }
+
+ /* run deflate() on provided input until it produces no more output */
+ ret = Z_OK;
+ do {
+ /* write out current buffer contents if full, or if flushing, but if
+ doing Z_FINISH then don't write until we get to Z_STREAM_END */
+ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
+ (flush != Z_FINISH || ret == Z_STREAM_END))) {
+ have = (unsigned)(strm->next_out - state->x.next);
+ if (have && ((got = write(state->fd, state->x.next, have)) < 0 ||
+ (unsigned)got != have)) {
+ gz_error(state, Z_ERRNO, zstrerror());
+ return -1;
+ }
+ if (strm->avail_out == 0) {
+ strm->avail_out = state->size;
+ strm->next_out = state->out;
+ }
+ state->x.next = strm->next_out;
+ }
+
+ /* compress */
+ have = strm->avail_out;
+ ret = deflate(strm, flush);
+ if (ret == Z_STREAM_ERROR) {
+ gz_error(state, Z_STREAM_ERROR,
+ "internal error: deflate stream corrupt");
+ return -1;
+ }
+ have -= strm->avail_out;
+ } while (have);
+
+ /* if that completed a deflate stream, allow another to start */
+ if (flush == Z_FINISH)
+ deflateReset(strm);
+
+ /* all done, no errors */
+ return 0;
+}
+
+/* Compress len zeros to output. Return -1 on error, 0 on success. */
+local int gz_zero(state, len)
+ gz_statep state;
+ z_off64_t len;
+{
+ int first;
+ unsigned n;
+ z_streamp strm = &(state->strm);
+
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return -1;
+
+ /* compress len zeros (len guaranteed > 0) */
+ first = 1;
+ while (len) {
+ n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
+ (unsigned)len : state->size;
+ if (first) {
+ memset(state->in, 0, n);
+ first = 0;
+ }
+ strm->avail_in = n;
+ strm->next_in = state->in;
+ state->x.pos += n;
+ if (gz_comp(state, Z_NO_FLUSH) == -1)
+ return -1;
+ len -= n;
+ }
+ return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzwrite(file, buf, len)
+ gzFile file;
+ voidpc buf;
+ unsigned len;
+{
+ unsigned put = len;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return 0;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return 0;
+
+ /* since an int is returned, make sure len fits in one, otherwise return
+ with an error (this avoids the flaw in the interface) */
+ if ((int)len < 0) {
+ gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
+ return 0;
+ }
+
+ /* if len is zero, avoid unnecessary operations */
+ if (len == 0)
+ return 0;
+
+ /* allocate memory if this is the first time through */
+ if (state->size == 0 && gz_init(state) == -1)
+ return 0;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return 0;
+ }
+
+ /* for small len, copy to input buffer, otherwise compress directly */
+ if (len < state->size) {
+ /* copy to input buffer, compress when full */
+ do {
+ unsigned have, copy;
+
+ if (strm->avail_in == 0)
+ strm->next_in = state->in;
+ have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
+ copy = state->size - have;
+ if (copy > len)
+ copy = len;
+ memcpy(state->in + have, buf, copy);
+ strm->avail_in += copy;
+ state->x.pos += copy;
+ buf = (const char *)buf + copy;
+ len -= copy;
+ if (len && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+ } while (len);
+ }
+ else {
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+
+ /* directly compress user buffer to file */
+ strm->avail_in = len;
+ strm->next_in = (z_const Bytef *)buf;
+ state->x.pos += len;
+ if (gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+ }
+
+ /* input was all buffered or compressed (put will fit in int) */
+ return (int)put;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned have;
+ unsigned char buf[1];
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return -1;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* try writing to input buffer for speed (state->size == 0 if buffer not
+ initialized) */
+ if (state->size) {
+ if (strm->avail_in == 0)
+ strm->next_in = state->in;
+ have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
+ if (have < state->size) {
+ state->in[have] = c;
+ strm->avail_in++;
+ state->x.pos++;
+ return c & 0xff;
+ }
+ }
+
+ /* no room in buffer or not initialized, use gz_write() */
+ buf[0] = c;
+ if (gzwrite(file, buf, 1) != 1)
+ return -1;
+ return c & 0xff;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputs(file, str)
+ gzFile file;
+ const char *str;
+{
+ int ret;
+ unsigned len;
+
+ /* write string */
+ len = (unsigned)strlen(str);
+ ret = gzwrite(file, str, len);
+ return ret == 0 && len != 0 ? -1 : ret;
+}
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#include <stdarg.h>
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
+{
+ int size, len;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return 0;
+
+ /* make sure we have some buffer space */
+ if (state->size == 0 && gz_init(state) == -1)
+ return 0;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return 0;
+ }
+
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+
+ /* do the printf() into the input buffer, put length in len */
+ size = (int)(state->size);
+ state->in[size - 1] = 0;
+#ifdef NO_vsnprintf
+# ifdef HAS_vsprintf_void
+ (void)vsprintf((char *)(state->in), format, va);
+ for (len = 0; len < size; len++)
+ if (state->in[len] == 0) break;
+# else
+ len = vsprintf((char *)(state->in), format, va);
+# endif
+#else
+# ifdef HAS_vsnprintf_void
+ (void)vsnprintf((char *)(state->in), size, format, va);
+ len = strlen((char *)(state->in));
+# else
+ len = vsnprintf((char *)(state->in), size, format, va);
+# endif
+#endif
+
+ /* check that printf() results fit in buffer */
+ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+ return 0;
+
+ /* update buffer and position, defer compression until needed */
+ strm->avail_in = (unsigned)len;
+ strm->next_in = state->in;
+ state->x.pos += len;
+ return len;
+}
+
+int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
+{
+ va_list va;
+ int ret;
+
+ va_start(va, format);
+ ret = gzvprintf(file, format, va);
+ va_end(va);
+ return ret;
+}
+
+#else /* !STDC && !Z_HAVE_STDARG_H */
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ int size, len;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that can really pass pointer in ints */
+ if (sizeof(int) != sizeof(void *))
+ return 0;
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return 0;
+
+ /* make sure we have some buffer space */
+ if (state->size == 0 && gz_init(state) == -1)
+ return 0;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return 0;
+ }
+
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+
+ /* do the printf() into the input buffer, put length in len */
+ size = (int)(state->size);
+ state->in[size - 1] = 0;
+#ifdef NO_snprintf
+# ifdef HAS_sprintf_void
+ sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ for (len = 0; len < size; len++)
+ if (state->in[len] == 0) break;
+# else
+ len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#else
+# ifdef HAS_snprintf_void
+ snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ len = strlen((char *)(state->in));
+# else
+ len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6,
+ a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18,
+ a19, a20);
+# endif
+#endif
+
+ /* check that printf() results fit in buffer */
+ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+ return 0;
+
+ /* update buffer and position, defer compression until needed */
+ strm->avail_in = (unsigned)len;
+ strm->next_in = state->in;
+ state->x.pos += len;
+ return len;
+}
+
+#endif
+
+/* -- see zlib.h -- */
+int ZEXPORT gzflush(file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return Z_STREAM_ERROR;
+
+ /* check flush parameter */
+ if (flush < 0 || flush > Z_FINISH)
+ return Z_STREAM_ERROR;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* compress remaining data with requested flush */
+ gz_comp(state, flush);
+ return state->err;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzsetparams(file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return Z_STREAM_ERROR;
+
+ /* if no change is requested, then do nothing */
+ if (level == state->level && strategy == state->strategy)
+ return Z_OK;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* change compression parameters for subsequent input */
+ if (state->size) {
+ /* flush previous input with previous parameters before changing */
+ if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
+ return state->err;
+ deflateParams(strm, level, strategy);
+ }
+ state->level = level;
+ state->strategy = strategy;
+ return Z_OK;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_w(file)
+ gzFile file;
+{
+ int ret = Z_OK;
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ /* check that we're writing */
+ if (state->mode != GZ_WRITE)
+ return Z_STREAM_ERROR;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ ret = state->err;
+ }
+
+ /* flush, free memory, and close file */
+ if (gz_comp(state, Z_FINISH) == -1)
+ ret = state->err;
+ if (state->size) {
+ if (!state->direct) {
+ (void)deflateEnd(&(state->strm));
+ free(state->out);
+ }
+ free(state->in);
+ }
+ gz_error(state, Z_OK, NULL);
+ free(state->path);
+ if (close(state->fd) == -1)
+ ret = Z_ERRNO;
+ free(state);
+ return ret;
+}
diff --git a/zlib/inffast.c b/zlib/inffast.c
new file mode 100644
index 0000000..bda59ce
--- /dev/null
+++ b/zlib/inffast.c
@@ -0,0 +1,340 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2008, 2010, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ z_const unsigned char FAR *in; /* local strm->next_in */
+ z_const unsigned char FAR *last; /* have enough input while in < last */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code here; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ wnext = state->wnext;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ PUP(out) = (unsigned char)(here.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ if (state->sane) {
+ strm->msg =
+ (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ if (len <= op - whave) {
+ do {
+ PUP(out) = 0;
+ } while (--len);
+ continue;
+ }
+ len -= op - whave;
+ do {
+ PUP(out) = 0;
+ } while (--op > whave);
+ if (op == 0) {
+ from = out - dist;
+ do {
+ PUP(out) = PUP(from);
+ } while (--len);
+ continue;
+ }
+#endif
+ }
+ from = window - OFF;
+ if (wnext == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (wnext < op) { /* wrap around window */
+ from += wsize + wnext - op;
+ op -= wnext;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (wnext < len) { /* some from start of window */
+ op = wnext;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += wnext - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ here = dcode[here.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ here = lcode[here.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and wnext == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/zlib/inffast.h b/zlib/inffast.h
new file mode 100644
index 0000000..e5c1aa4
--- /dev/null
+++ b/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/zlib/inffixed.h b/zlib/inffixed.h
new file mode 100644
index 0000000..d628327
--- /dev/null
+++ b/zlib/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications.
+ It is part of the implementation of this library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/zlib/inflate.c b/zlib/inflate.c
new file mode 100644
index 0000000..4fd3f3c
--- /dev/null
+++ b/zlib/inflate.c
@@ -0,0 +1,1513 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2012 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common wnext == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
+ unsigned copy));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateResetKeep(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ if (state->wrap) /* to support ill-conceived Java test suite */
+ strm->adler = state->wrap & 1;
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ state->sane = 1;
+ state->back = -1;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ state->wsize = 0;
+ state->whave = 0;
+ state->wnext = 0;
+ return inflateResetKeep(strm);
+}
+
+int ZEXPORT inflateReset2(strm, windowBits)
+z_streamp strm;
+int windowBits;
+{
+ int wrap;
+ struct inflate_state FAR *state;
+
+ /* get the state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* extract wrap request from windowBits parameter */
+ if (windowBits < 0) {
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48)
+ windowBits &= 15;
+#endif
+ }
+
+ /* set number of window bits, free window if different */
+ if (windowBits && (windowBits < 8 || windowBits > 15))
+ return Z_STREAM_ERROR;
+ if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
+ ZFREE(strm, state->window);
+ state->window = Z_NULL;
+ }
+
+ /* update state and reset the rest of it */
+ state->wrap = wrap;
+ state->wbits = (unsigned)windowBits;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ int ret;
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+#endif
+ }
+ if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zfree = zcfree;
+#endif
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->window = Z_NULL;
+ ret = inflateReset2(strm, windowBits);
+ if (ret != Z_OK) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ }
+ return ret;
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits < 0) {
+ state->hold = 0;
+ state->bits = 0;
+ return Z_OK;
+ }
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
+ state.lencode[low].bits, state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, end, copy)
+z_streamp strm;
+const Bytef *end;
+unsigned copy;
+{
+ struct inflate_state FAR *state;
+ unsigned dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->wnext = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, end - state->wsize, state->wsize);
+ state->wnext = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->wnext;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->wnext, end - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, end - copy, copy);
+ state->wnext = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->wnext += dist;
+ if (state->wnext == state->wsize) state->wnext = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ z_const unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code here; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (state->wbits == 0)
+ state->wbits = len;
+ else if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = ZSWAP32(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN_; /* decode codes */
+ if (flush == Z_TREES) {
+ DROPBITS(2);
+ goto inf_leave;
+ }
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY_;
+ if (flush == Z_TREES) goto inf_leave;
+ case COPY_:
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (const code FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.val < 16) {
+ DROPBITS(here.bits);
+ state->lens[state->have++] = here.val;
+ }
+ else {
+ if (here.val == 16) {
+ NEEDBITS(here.bits + 2);
+ DROPBITS(here.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (here.val == 17) {
+ NEEDBITS(here.bits + 3);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(here.bits + 7);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* check for end-of-block code (better have one) */
+ if (state->lens[256] == 0) {
+ strm->msg = (char *)"invalid code -- missing end-of-block";
+ state->mode = BAD;
+ break;
+ }
+
+ /* build code tables -- note: do not change the lenbits or distbits
+ values here (9 and 6) without reading the comments in inftrees.h
+ concerning the ENOUGH constants, which depend on those values */
+ state->next = state->codes;
+ state->lencode = (const code FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (const code FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN_;
+ if (flush == Z_TREES) goto inf_leave;
+ case LEN_:
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ if (state->mode == TYPE)
+ state->back = -1;
+ break;
+ }
+ state->back = 0;
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.op && (here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ state->length = (unsigned)here.val;
+ if ((int)(here.op) == 0) {
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ state->mode = LIT;
+ break;
+ }
+ if (here.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->back = -1;
+ state->mode = TYPE;
+ break;
+ }
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->was = state->length;
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ here = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)here.val;
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->whave) {
+ if (state->sane) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ Trace((stderr, "inflate.c too far\n"));
+ copy -= state->whave;
+ if (copy > state->length) copy = state->length;
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = 0;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+#endif
+ }
+ if (copy > state->wnext) {
+ copy -= state->wnext;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->wnext - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ ZSWAP32(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
+ (state->mode < CHECK || flush != Z_FINISH)))
+ if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0) +
+ (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+Bytef *dictionary;
+uInt *dictLength;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* copy dictionary */
+ if (state->whave && dictionary != Z_NULL) {
+ zmemcpy(dictionary, state->window + state->wnext,
+ state->whave - state->wnext);
+ zmemcpy(dictionary + state->whave - state->wnext,
+ state->window, state->wnext);
+ }
+ if (dictLength != Z_NULL)
+ *dictLength = state->whave;
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long dictid;
+ int ret;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary identifier */
+ if (state->mode == DICT) {
+ dictid = adler32(0L, Z_NULL, 0);
+ dictid = adler32(dictid, dictionary, dictLength);
+ if (dictid != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window using updatewindow(), which will amend the
+ existing dictionary if appropriate */
+ ret = updatewindow(strm, dictionary + dictLength, dictLength);
+ if (ret) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+const unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+ zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
+
+int ZEXPORT inflateUndermine(strm, subvert)
+z_streamp strm;
+int subvert;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ state->sane = !subvert;
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ return Z_OK;
+#else
+ state->sane = 1;
+ return Z_DATA_ERROR;
+#endif
+}
+
+long ZEXPORT inflateMark(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return (long)(((unsigned long)0 - 1) << 16);
+ state = (struct inflate_state FAR *)strm->state;
+ return (long)(((unsigned long)((long)state->back)) << 16) +
+ (state->mode == COPY ? state->length :
+ (state->mode == MATCH ? state->was - state->length : 0));
+}
diff --git a/zlib/inflate.h b/zlib/inflate.h
new file mode 100644
index 0000000..95f4986
--- /dev/null
+++ b/zlib/inflate.h
@@ -0,0 +1,122 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY_, /* i/o: same as COPY below, but only first time in */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN_, /* i: same as LEN below, but only first time in */
+ LEN, /* i: waiting for length/lit/eob code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to BAD or MEM on error -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib) or (raw)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
+ HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ (raw) -> TYPEDO
+ Read deflate blocks:
+ TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
+ STORED -> COPY_ -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN_
+ LEN_ -> LEN
+ Read deflate codes in fixed or dynamic block:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 10K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+ int sane; /* if false, allow invalid distance too far */
+ int back; /* bits back of last unprocessed length/lit */
+ unsigned was; /* initial length of match */
+};
diff --git a/zlib/inftrees.c b/zlib/inftrees.c
new file mode 100644
index 0000000..44d89cf
--- /dev/null
+++ b/zlib/inftrees.c
@@ -0,0 +1,306 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.8 Copyright 1995-2013 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code here; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)1;
+ here.val = (unsigned short)0;
+ *(*table)++ = here; /* make a table to force an error */
+ *(*table)++ = here;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min < max; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked for LENS and DIST tables against
+ the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+ the initial root table size constants. See the comments in inftrees.h
+ for more information.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if ((type == LENS && used > ENOUGH_LENS) ||
+ (type == DISTS && used > ENOUGH_DISTS))
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ here.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ here.op = (unsigned char)0;
+ here.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ here.op = (unsigned char)(extra[work[sym]]);
+ here.val = base[work[sym]];
+ }
+ else {
+ here.op = (unsigned char)(32 + 64); /* end of block */
+ here.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = here;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if ((type == LENS && used > ENOUGH_LENS) ||
+ (type == DISTS && used > ENOUGH_DISTS))
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /* fill in remaining table entry if code is incomplete (guaranteed to have
+ at most one remaining entry, since if the code is incomplete, the
+ maximum code length that was allowed to get this far is one bit) */
+ if (huff != 0) {
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)(len - drop);
+ here.val = (unsigned short)0;
+ next[huff] = here;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/zlib/inftrees.h b/zlib/inftrees.h
new file mode 100644
index 0000000..baa53a0
--- /dev/null
+++ b/zlib/inftrees.h
@@ -0,0 +1,62 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table. The maximum number of code structures is
+ 1444, which is the sum of 852 for literal/length codes and 592 for distance
+ codes. These values were found by exhaustive searches using the program
+ examples/enough.c found in the zlib distribtution. The arguments to that
+ program are the number of symbols, the initial root table size, and the
+ maximum bit length of a code. "enough 286 9 15" for literal/length codes
+ returns returns 852, and "enough 30 6 15" for distance codes returns 592.
+ The initial root table size (9 or 6) is found in the fifth argument of the
+ inflate_table() calls in inflate.c and infback.c. If the root table size is
+ changed, then these maximum sizes would be need to be recalculated and
+ updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 592
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/zlib/trees.c b/zlib/trees.c
new file mode 100644
index 0000000..1fd7759
--- /dev/null
+++ b/zlib/trees.c
@@ -0,0 +1,1226 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2012 Jean-loup Gailly
+ * detect_data_type() function provided freely by Cosmin Truta, 2006
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, const ct_data *ltree,
+ const ct_data *dtree));
+local int detect_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (ush)val << s->bi_valid;\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (ush)(value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+#ifdef NO_INIT_GLOBAL_POINTERS
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+#endif
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header,
+ "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void ZLIB_INTERNAL _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
+ */
+void ZLIB_INTERNAL _tr_flush_bits(s)
+ deflate_state *s;
+{
+ bi_flush(s);
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ */
+void ZLIB_INTERNAL _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (s->strm->data_type == Z_UNKNOWN)
+ s->strm->data_type = detect_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, last);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+last, 3);
+ compress_block(s, (const ct_data *)static_ltree,
+ (const ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+last, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (const ct_data *)s->dyn_ltree,
+ (const ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (last) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ZLIB_INTERNAL _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ const ct_data *ltree; /* literal tree */
+ const ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ * a) There are no non-portable control characters belonging to the
+ * "black list" (0..6, 14..25, 28..31).
+ * b) There is at least one printable character belonging to the
+ * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ * "gray list" that is ignored in this detection algorithm:
+ * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(s)
+ deflate_state *s;
+{
+ /* black_mask is the bit mask of black-listed bytes
+ * set bits 0..6, 14..25, and 28..31
+ * 0xf3ffc07f = binary 11110011111111111100000001111111
+ */
+ unsigned long black_mask = 0xf3ffc07fUL;
+ int n;
+
+ /* Check for non-textual ("black-listed") bytes. */
+ for (n = 0; n <= 31; n++, black_mask >>= 1)
+ if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+ return Z_BINARY;
+
+ /* Check for textual ("white-listed") bytes. */
+ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+ || s->dyn_ltree[13].Freq != 0)
+ return Z_TEXT;
+ for (n = 32; n < LITERALS; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ return Z_TEXT;
+
+ /* There are no "black-listed" or "white-listed" bytes:
+ * this stream either is empty or has tolerated ("gray-listed") bytes only.
+ */
+ return Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/zlib/trees.h b/zlib/trees.h
new file mode 100644
index 0000000..d35639d
--- /dev/null
+++ b/zlib/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/zlib/zconf.h b/zlib/zconf.h
new file mode 100644
index 0000000..9987a77
--- /dev/null
+++ b/zlib/zconf.h
@@ -0,0 +1,511 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
+# define Z_PREFIX_SET
+
+/* all linked symbols */
+# define _dist_code z__dist_code
+# define _length_code z__length_code
+# define _tr_align z__tr_align
+# define _tr_flush_bits z__tr_flush_bits
+# define _tr_flush_block z__tr_flush_block
+# define _tr_init z__tr_init
+# define _tr_stored_block z__tr_stored_block
+# define _tr_tally z__tr_tally
+# define adler32 z_adler32
+# define adler32_combine z_adler32_combine
+# define adler32_combine64 z_adler32_combine64
+# ifndef Z_SOLO
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# endif
+# define crc32 z_crc32
+# define crc32_combine z_crc32_combine
+# define crc32_combine64 z_crc32_combine64
+# define deflate z_deflate
+# define deflateBound z_deflateBound
+# define deflateCopy z_deflateCopy
+# define deflateEnd z_deflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateInit_ z_deflateInit_
+# define deflateParams z_deflateParams
+# define deflatePending z_deflatePending
+# define deflatePrime z_deflatePrime
+# define deflateReset z_deflateReset
+# define deflateResetKeep z_deflateResetKeep
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateSetHeader z_deflateSetHeader
+# define deflateTune z_deflateTune
+# define deflate_copyright z_deflate_copyright
+# define get_crc_table z_get_crc_table
+# ifndef Z_SOLO
+# define gz_error z_gz_error
+# define gz_intmax z_gz_intmax
+# define gz_strwinerror z_gz_strwinerror
+# define gzbuffer z_gzbuffer
+# define gzclearerr z_gzclearerr
+# define gzclose z_gzclose
+# define gzclose_r z_gzclose_r
+# define gzclose_w z_gzclose_w
+# define gzdirect z_gzdirect
+# define gzdopen z_gzdopen
+# define gzeof z_gzeof
+# define gzerror z_gzerror
+# define gzflush z_gzflush
+# define gzgetc z_gzgetc
+# define gzgetc_ z_gzgetc_
+# define gzgets z_gzgets
+# define gzoffset z_gzoffset
+# define gzoffset64 z_gzoffset64
+# define gzopen z_gzopen
+# define gzopen64 z_gzopen64
+# ifdef _WIN32
+# define gzopen_w z_gzopen_w
+# endif
+# define gzprintf z_gzprintf
+# define gzvprintf z_gzvprintf
+# define gzputc z_gzputc
+# define gzputs z_gzputs
+# define gzread z_gzread
+# define gzrewind z_gzrewind
+# define gzseek z_gzseek
+# define gzseek64 z_gzseek64
+# define gzsetparams z_gzsetparams
+# define gztell z_gztell
+# define gztell64 z_gztell64
+# define gzungetc z_gzungetc
+# define gzwrite z_gzwrite
+# endif
+# define inflate z_inflate
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define inflateBackInit_ z_inflateBackInit_
+# define inflateCopy z_inflateCopy
+# define inflateEnd z_inflateEnd
+# define inflateGetHeader z_inflateGetHeader
+# define inflateInit2_ z_inflateInit2_
+# define inflateInit_ z_inflateInit_
+# define inflateMark z_inflateMark
+# define inflatePrime z_inflatePrime
+# define inflateReset z_inflateReset
+# define inflateReset2 z_inflateReset2
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateGetDictionary z_inflateGetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateUndermine z_inflateUndermine
+# define inflateResetKeep z_inflateResetKeep
+# define inflate_copyright z_inflate_copyright
+# define inflate_fast z_inflate_fast
+# define inflate_table z_inflate_table
+# ifndef Z_SOLO
+# define uncompress z_uncompress
+# endif
+# define zError z_zError
+# ifndef Z_SOLO
+# define zcalloc z_zcalloc
+# define zcfree z_zcfree
+# endif
+# define zlibCompileFlags z_zlibCompileFlags
+# define zlibVersion z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+# define Byte z_Byte
+# define Bytef z_Bytef
+# define alloc_func z_alloc_func
+# define charf z_charf
+# define free_func z_free_func
+# ifndef Z_SOLO
+# define gzFile z_gzFile
+# endif
+# define gz_header z_gz_header
+# define gz_headerp z_gz_headerp
+# define in_func z_in_func
+# define intf z_intf
+# define out_func z_out_func
+# define uInt z_uInt
+# define uIntf z_uIntf
+# define uLong z_uLong
+# define uLongf z_uLongf
+# define voidp z_voidp
+# define voidpc z_voidpc
+# define voidpf z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+# define gz_header_s z_gz_header_s
+# define internal_state z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+# define z_const const
+#else
+# define z_const
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+# if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# define Z_ARG(args) args
+# else
+# define Z_ARG(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+# include <limits.h>
+# if (UINT_MAX == 0xffffffffUL)
+# define Z_U4 unsigned
+# elif (ULONG_MAX == 0xffffffffUL)
+# define Z_U4 unsigned long
+# elif (USHRT_MAX == 0xffffffffUL)
+# define Z_U4 unsigned short
+# endif
+#endif
+
+#ifdef Z_U4
+ typedef Z_U4 z_crc_t;
+#else
+ typedef unsigned long z_crc_t;
+#endif
+
+#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
+# define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
+# define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+# ifndef Z_SOLO
+# include <sys/types.h> /* for off_t */
+# endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifndef Z_SOLO
+# include <stdarg.h> /* for va_list */
+# endif
+#endif
+
+#ifdef _WIN32
+# ifndef Z_SOLO
+# include <stddef.h> /* for wchar_t */
+# endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+# undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+# define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# ifndef z_off_t
+# define z_off_t off_t
+# endif
+# endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+# define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+# define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+# define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+# define z_off64_t off64_t
+#else
+# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+# define z_off64_t __int64
+# else
+# define z_off64_t z_off_t
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+ #pragma map(deflateInit_,"DEIN")
+ #pragma map(deflateInit2_,"DEIN2")
+ #pragma map(deflateEnd,"DEEND")
+ #pragma map(deflateBound,"DEBND")
+ #pragma map(inflateInit_,"ININ")
+ #pragma map(inflateInit2_,"ININ2")
+ #pragma map(inflateEnd,"INEND")
+ #pragma map(inflateSync,"INSY")
+ #pragma map(inflateSetDictionary,"INSEDI")
+ #pragma map(compressBound,"CMBND")
+ #pragma map(inflate_table,"INTABL")
+ #pragma map(inflate_fast,"INFA")
+ #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/zlib/zlib.h b/zlib/zlib.h
new file mode 100644
index 0000000..3e0c767
--- /dev/null
+++ b/zlib/zlib.h
@@ -0,0 +1,1768 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.8, April 28th, 2013
+
+ Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+ (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.8"
+#define ZLIB_VERNUM 0x1280
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 8
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed data.
+ This version of the library supports only one compression method (deflation)
+ but other algorithms will be added later and will have the same stream
+ interface.
+
+ Compression can be done in a single step if the buffers are large enough,
+ or can be done by repeated calls of the compression function. In the latter
+ case, the application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never crash
+ even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ z_const Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total number of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total number of bytes output so far */
+
+ z_const char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has dropped
+ to zero. It must update next_out and avail_out when avail_out has dropped
+ to zero. The application must initialize zalloc, zfree and opaque before
+ calling the init function. All other fields are set by the compression
+ library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this if
+ the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers
+ returned by zalloc for objects of exactly 65536 bytes *must* have their
+ offset normalized to zero. The default allocation function provided by this
+ library ensures this (see zutil.c). To reduce memory requirements and avoid
+ any allocation of 64K objects, at the expense of compression ratio, compile
+ the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or progress
+ reports. After compression, total_in holds the total size of the
+ uncompressed data and may be saved for use in the decompressor (particularly
+ if the decompressor wants to decompress everything in a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+#define Z_TREES 6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is not
+ compatible with the zlib.h header file used by the application. This check
+ is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller. If
+ zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+ allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at all
+ (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION
+ requests a default compromise between speed and compression (currently
+ equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if level is not a valid compression level, or
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION). msg is set to null
+ if there is no error message. deflateInit does not perform any compression:
+ this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications). Some
+ output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating avail_in or avail_out accordingly; avail_out should
+ never be zero before the call. The application can consume the compressed
+ output when it wants, for example when the output buffer is full (avail_out
+ == 0), or after each call of deflate(). If deflate returns Z_OK and with
+ zero avail_out, it must be called again after making room in the output
+ buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumulate before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In
+ particular avail_in is zero after the call if enough output space has been
+ provided before the call.) Flushing may degrade compression for some
+ compression algorithms and so it should be used only when necessary. This
+ completes the current deflate block and follows it with an empty stored block
+ that is three bits plus filler bits to the next byte, followed by four bytes
+ (00 00 ff ff).
+
+ If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+ output buffer, but the output is not aligned to a byte boundary. All of the
+ input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+ This completes the current deflate block and follows it with an empty fixed
+ codes block that is 10 bits long. This assures that enough bytes are output
+ in order for the decompressor to finish the block before the empty fixed code
+ block.
+
+ If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+ for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+ seven bits of the current block are held to be written as the next byte after
+ the next deflate block is completed. In this case, the decompressor may not
+ be provided enough bits at this point in order to complete decompression of
+ the data provided so far to the compressor. It may need to wait for the next
+ block to be emitted. This is for advanced applications that need to control
+ the emission of deflate blocks.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there was
+ enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the stream
+ are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least the
+ value returned by deflateBound (see below). Then deflate is guaranteed to
+ return Z_STREAM_END. If not enough output space is provided, deflate will
+ not return Z_STREAM_END, and it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect the
+ compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case, msg
+ may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the
+ exact value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit() does not process any header information -- that is deferred
+ until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing will
+ resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there is
+ no more input data or no more space in the output buffer (see below about
+ the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating the next_* and avail_* values accordingly. The
+ application can consume the uncompressed output when it wants, for example
+ when the output buffer is full (avail_out == 0), or after each call of
+ inflate(). If inflate returns Z_OK and with zero avail_out, it must be
+ called again after making room in the output buffer because there might be
+ more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+ Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate()
+ stop if and when it gets to the next deflate block boundary. When decoding
+ the zlib or gzip format, this will cause inflate() to return immediately
+ after the header and before the first block. When doing a raw inflate,
+ inflate() will go ahead and process the first block, and will return when it
+ gets to the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64 if
+ inflate() is currently decoding the last block in the deflate stream, plus
+ 128 if inflate() returned immediately after decoding an end-of-block code or
+ decoding the complete header up to just before the first byte of the deflate
+ stream. The end-of-block will not be indicated until all of the uncompressed
+ data from that block has been written to strm->next_out. The number of
+ unused bits may in general be greater than seven, except when bit 7 of
+ data_type is set, in which case the number of unused bits will be less than
+ eight. data_type is set as noted here every time inflate() returns for all
+ flush options, and so can be used to determine the amount of currently
+ consumed input in bits.
+
+ The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+ end of each deflate block header is reached, before any actual data in that
+ block is decoded. This allows the caller to determine the length of the
+ deflate block header for later use in random access within a deflate block.
+ 256 is added to the value of strm->data_type when inflate() returns
+ immediately after reaching the end of the deflate block header.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step (a
+ single call of inflate), the parameter flush should be set to Z_FINISH. In
+ this case all pending input is processed and all pending output is flushed;
+ avail_out must be large enough to hold all of the uncompressed data for the
+ operation to complete. (The size of the uncompressed data may have been
+ saved by the compressor for this purpose.) The use of Z_FINISH is not
+ required to perform an inflation in one step. However it may be used to
+ inform inflate that a faster approach can be used for the single inflate()
+ call. Z_FINISH also informs inflate to not maintain a sliding window if the
+ stream completes, which reduces inflate's memory footprint. If the stream
+ does not complete, either because not all of the stream is provided or not
+ enough output space is provided, then a sliding window will be allocated and
+ inflate() can be called again to continue the operation as if Z_NO_FLUSH had
+ been used.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the effects of the flush parameter in this implementation are
+ on the return value of inflate() as noted below, when inflate() returns early
+ when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
+ memory for a sliding window when Z_FINISH is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the Adler-32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically, if requested when
+ initializing with inflateInit2(). Any information contained in the gzip
+ header is not retained, so applications that need that information should
+ instead use raw inflate, see inflateInit2() below, or inflateBack() and
+ perform their own processing of the gzip header and trailer. When processing
+ gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
+ producted so far. The CRC-32 is checked against the gzip trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may
+ then call inflateSync() to look for a good compression block if a partial
+ recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by the
+ caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero), no
+ header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but is
+ slow and reduces compression ratio; memLevel=9 uses maximum memory for
+ optimal speed. The default value is 8. See zconf.h for total memory usage
+ as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as
+ fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The
+ strategy parameter only affects the compression ratio but not the
+ correctness of the compressed output even if it is not set appropriately.
+ Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+ decoder for special applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+ method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+ incompatible with the version assumed by the caller (ZLIB_VERSION). msg is
+ set to null if there is no error message. deflateInit2 does not perform any
+ compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. When using the zlib format, this
+ function must be called immediately after deflateInit, deflateInit2 or
+ deflateReset, and before any call of deflate. When doing raw deflate, this
+ function must be called either before any call of deflate, or immediately
+ after the completion of a deflate block, i.e. after all input has been
+ consumed and all output has been delivered when using any of the flush
+ options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The
+ compressor and decompressor must use exactly the same dictionary (see
+ inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size
+ provided in deflateInit or deflateInit2. Thus the strings most likely to be
+ useful should be put at the end of the dictionary, not at the front. In
+ addition, the current implementation of deflate will use at most the window
+ size minus 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if not at a block boundary for raw deflate). deflateSetDictionary does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and can
+ consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state. The
+ stream will keep the same compression level and any other attributes that
+ may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different strategy.
+ If the compression level is changed, the input available so far is
+ compressed with the old level (and may be flushed); the new level will take
+ effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to be
+ compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+ strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit() or
+ deflateInit2(), and after deflateSetHeader(), if used. This would be used
+ to allocate an output buffer for deflation in a single pass, and so would be
+ called before deflate(). If that first deflate() call is provided the
+ sourceLen input bytes, an output buffer allocated to the size returned by
+ deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
+ to return Z_STREAM_END. Note that it is possible for the compressed size to
+ be larger than the value returned by deflateBound() if flush options other
+ than Z_FINISH or Z_NO_FLUSH are used.
+*/
+
+ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
+ unsigned *pending,
+ int *bits));
+/*
+ deflatePending() returns the number of bytes and bits of output that have
+ been generated, but not yet provided in the available output. The bytes not
+ provided would be due to the available output space having being consumed.
+ The number of bits of output not provided are between 0 and 7, where they
+ await more bits to join them in order to fill out a full byte. If pending
+ or bits are Z_NULL, then those values are not set.
+
+ deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+ */
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the bits
+ leftover from a previous deflate stream when appending to it. As such, this
+ function can only be used for raw deflate, and must be used before the first
+ deflate() call after a deflateInit2() or deflateReset(). bits must be less
+ than or equal to 16, and that many of the least significant bits of value
+ will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
+ room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
+ source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be zero to request that inflate use the window size in
+ the zlib header of the compressed stream.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a
+ crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit2 does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit2() does not process any header information -- that is
+ deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called at any
+ time to set the dictionary. If the provided dictionary is smaller than the
+ window and there is already data in the window, then the provided dictionary
+ will amend what's there. The application must insure that the dictionary
+ that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
+ Bytef *dictionary,
+ uInt *dictLength));
+/*
+ Returns the sliding dictionary being maintained by inflate. dictLength is
+ set to the number of bytes in the dictionary, and that many bytes are copied
+ to dictionary. dictionary must have enough space, where 32768 bytes is
+ always enough. If inflateGetDictionary() is called with dictionary equal to
+ Z_NULL, then only the dictionary length is returned, and nothing is copied.
+ Similary, if dictLength is Z_NULL, then it is not set.
+
+ inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
+ stream state is inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a possible full flush point (see above
+ for the description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync searches for a 00 00 FF FF pattern in the compressed data.
+ All full flush points have this pattern, but not all occurrences of this
+ pattern are full flush points.
+
+ inflateSync returns Z_OK if a possible full flush point has been found,
+ Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
+ has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
+ In the success case, the application may save the current current value of
+ total_in which indicates where valid compressed data was found. In the
+ error case, the application may repeatedly call inflateSync, providing more
+ input each time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state. The
+ stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+ int windowBits));
+/*
+ This function is the same as inflateReset, but it also permits changing
+ the wrap and window size requests. The windowBits parameter is interpreted
+ the same as it is for inflateInit2.
+
+ inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+ the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ If bits is negative, then the input stream bit buffer is emptied. Then
+ inflatePrime() can be called again to put bits in the buffer. This is used
+ to clear out bits leftover after feeding inflate a block description prior
+ to feeding inflate codes.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+ This function returns two values, one in the lower 16 bits of the return
+ value, and the other in the remaining upper bits, obtained by shifting the
+ return value down 16 bits. If the upper value is -1 and the lower value is
+ zero, then inflate() is currently decoding information outside of a block.
+ If the upper value is -1 and the lower value is non-zero, then inflate is in
+ the middle of a stored block, with the lower value equaling the number of
+ bytes from the input remaining to copy. If the upper value is not -1, then
+ it is the number of bits back from the current bit position in the input of
+ the code (literal or length/distance pair) currently being processed. In
+ that case the lower value is the number of bytes already emitted for that
+ code.
+
+ A code is being processed if inflate is waiting for more input to complete
+ decoding of the code, or if it has completed decoding but is waiting for
+ more output space to write the literal or match data.
+
+ inflateMark() is used to mark locations in the input data for random
+ access, which may be at bit positions, and to note those cases where the
+ output of a code may span boundaries of random access blocks. The current
+ location in the input stream can be determined from avail_in and data_type
+ as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+ inflateMark returns the value noted above or -1 << 16 if the provided
+ source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be
+ used to force inflate() to return immediately after header processing is
+ complete and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When any
+ of extra, name, or comment are not Z_NULL and the respective field is not
+ present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the parameters are invalid, Z_MEM_ERROR if the internal state could not be
+ allocated, or Z_VERSION_ERROR if the version of the library does not match
+ the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *,
+ z_const unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is potentially more efficient than
+ inflate() for file i/o applications, in that it avoids copying between the
+ output and the sliding window by simply making the window itself the output
+ buffer. inflate() can be faster on modern CPUs when used with large
+ buffers. inflateBack() trusts the application to not change the output
+ buffer passed by the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free the
+ allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects only
+ the raw deflate stream to decompress. This is different from the normal
+ behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+ in the deflate stream (in which case strm->msg is set to indicate the nature
+ of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+ In the case of Z_BUF_ERROR, an input or output error can be distinguished
+ using strm->next_in which will be Z_NULL only if in() returned an error. If
+ strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+ non-zero. (in() will always be called before out(), so strm->next_in is
+ assured to be defined if out() returns non-zero.) Note that inflateBack()
+ cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+#ifndef Z_SOLO
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the basic
+ stream-oriented functions. To simplify the interface, some default options
+ are assumed (compression level and memory usage, standard memory allocation
+ functions). The source code of these utility functions can be modified if
+ you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before a
+ compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be large enough to hold the entire
+ uncompressed data. (The size of the uncompressed data must have been saved
+ previously by the compressor and transmitted to the decompressor by some
+ mechanism outside the scope of this compression library.) Upon exit, destLen
+ is the actual size of the uncompressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In
+ the case where there is not enough room, uncompress() will fill the output
+ buffer with the uncompressed data up to that point.
+*/
+
+ /* gzip file access functions */
+
+/*
+ This library supports reading and writing files in gzip (.gz) format with
+ an interface similar to that of stdio, using the functions that start with
+ "gz". The gzip format is different from the zlib format. gzip is a gzip
+ wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+ Opens a gzip (.gz) file for reading or writing. The mode parameter is as
+ in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+ a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+ compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+ for fixed code compression as in "wb9F". (See the description of
+ deflateInit2 for more information about the strategy parameter.) 'T' will
+ request transparent writing or appending with no compression and not using
+ the gzip format.
+
+ "a" can be used instead of "w" to request that the gzip stream that will
+ be written be appended to the file. "+" will result in an error, since
+ reading and writing to the same gzip file is not supported. The addition of
+ "x" when writing will create the file exclusively, which fails if the file
+ already exists. On systems that support it, the addition of "e" when
+ reading or writing will set the flag to close the file on an execve() call.
+
+ These functions, as well as gzip, will read and decode a sequence of gzip
+ streams in a file. The append function of gzopen() can be used to create
+ such a file. (Also see gzflush() for another way to do this.) When
+ appending, gzopen does not test whether the file begins with a gzip stream,
+ nor does it look for the end of the gzip streams to begin appending. gzopen
+ will simply append a gzip stream to the existing file.
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression. When
+ reading, this will be detected automatically by looking for the magic two-
+ byte gzip header.
+
+ gzopen returns NULL if the file could not be opened, if there was
+ insufficient memory to allocate the gzFile state, or if an invalid mode was
+ specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+ errno can be checked to determine if the reason gzopen failed was that the
+ file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen associates a gzFile with the file descriptor fd. File descriptors
+ are obtained from calls like open, dup, creat, pipe or fileno (if the file
+ has been previously opened with fopen). The mode parameter is as in gzopen.
+
+ The next call of gzclose on the returned gzFile will also close the file
+ descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+ fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+ mode);. The duplicated descriptor should be saved to avoid a leak, since
+ gzdopen does not close fd if it fails. If you are using fileno() to get the
+ file descriptor from a FILE *, then you will have to use dup() to avoid
+ double-close()ing the file descriptor. Both gzclose() and fclose() will
+ close the associated file descriptor, so they need to have different file
+ descriptors.
+
+ gzdopen returns NULL if there was insufficient memory to allocate the
+ gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+ provided, or '+' was provided), or if fd is -1. The file descriptor is not
+ used until the next gz* read, write, seek, or close operation, so gzdopen
+ will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+ Set the internal buffer size used by this library's functions. The
+ default buffer size is 8192 bytes. This function must be called after
+ gzopen() or gzdopen(), and before any other calls that read or write the
+ file. The buffer memory allocation is always deferred to the first read or
+ write. Two buffers are allocated, either both of the specified size when
+ writing, or one of the specified size and the other twice that size when
+ reading. A larger buffer size of, for example, 64K or 128K bytes will
+ noticeably increase the speed of decompression (reading).
+
+ The new buffer size also affects the maximum length for gzprintf().
+
+ gzbuffer() returns 0 on success, or -1 on failure, such as being called
+ too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file. If
+ the input file is not in gzip format, gzread copies the given number of
+ bytes into the buffer directly from the file.
+
+ After reaching the end of a gzip stream in the input, gzread will continue
+ to read, looking for another gzip stream. Any number of gzip streams may be
+ concatenated in the input file, and will all be decompressed by gzread().
+ If something other than a gzip stream is encountered after a gzip stream,
+ that remaining trailing garbage is ignored (and no error is returned).
+
+ gzread can be used to read a gzip file that is being concurrently written.
+ Upon reaching the end of the input, gzread will return with the available
+ data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
+ gzclearerr can be used to clear the end of file indicator in order to permit
+ gzread to be tried again. Z_OK indicates that a gzip stream was completed
+ on the last gzread. Z_BUF_ERROR indicates that the input file ended in the
+ middle of a gzip stream. Note that gzread does not return -1 in the event
+ of an incomplete gzip stream. This error is deferred until gzclose(), which
+ will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
+ stream. Alternatively, gzerror can be used before gzclose to detect this
+ case.
+
+ gzread returns the number of uncompressed bytes actually read, less than
+ len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes written or 0 in case of
+ error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the arguments to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written, or 0 in case of error. The number of
+ uncompressed bytes written is limited to 8191, or one less than the buffer
+ size given to gzbuffer(). The caller should assure that this limit is not
+ exceeded. If it is exceeded, then gzprintf() will return an error (0) with
+ nothing written. In this case, there may also be a buffer overflow with
+ unpredictable consequences, which is possible only if zlib was compiled with
+ the insecure functions sprintf() or vsprintf() because the secure snprintf()
+ or vsnprintf() functions were not available. This can be determined using
+ zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or a
+ newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. If any characters are read or if len == 1, the
+ string is terminated with a null character. If no characters are read due
+ to an end-of-file or len < 1, then the buffer is left untouched.
+
+ gzgets returns buf which is a null-terminated string, or it returns NULL
+ for end-of-file or in case of error. If there was an error, the contents at
+ buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file. gzputc
+ returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte or -1
+ in case of end of file or error. This is implemented as a macro for speed.
+ As such, it does not do all of the checking the other functions do. I.e.
+ it does not check to see if file is NULL, nor whether the structure file
+ points to has been clobbered or not.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read as the first character
+ on the next read. At least one character of push-back is allowed.
+ gzungetc() returns the character pushed, or -1 on failure. gzungetc() will
+ fail if c is -1, and may fail if a character has been pushed but not read
+ yet. If gzungetc is used immediately after gzopen or gzdopen, at least the
+ output buffer size of pushed characters is allowed. (See gzbuffer above.)
+ The pushed character will be discarded if the stream is repositioned with
+ gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter flush
+ is as in the deflate() function. The return value is the zlib error number
+ (see function gzerror below). gzflush is only permitted when writing.
+
+ If the flush parameter is Z_FINISH, the remaining data is written and the
+ gzip stream is completed in the output. If gzwrite() is called again, a new
+ gzip stream will be started in the output. gzread() is able to read such
+ concatented gzip streams.
+
+ gzflush should be called only when strictly necessary because it will
+ degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+
+ Returns the starting position for the next gzread or gzwrite on the given
+ compressed file. This position represents a number of bytes in the
+ uncompressed data stream, and is zero when starting, even if appending or
+ reading a gzip stream from the middle of a file using gzdopen().
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+ Returns the current offset in the file being read or written. This offset
+ includes the count of bytes that precede the gzip stream, for example when
+ appending or when using gzdopen() for reading. When reading, the offset
+ does not include as yet unused buffered input. This information can be used
+ for a progress indicator. On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns true (1) if the end-of-file indicator has been set while reading,
+ false (0) otherwise. Note that the end-of-file indicator is set only if the
+ read tried to go past the end of the input, but came up short. Therefore,
+ just like feof(), gzeof() may return false even if there is no more data to
+ read, in the event that the last read request was for the exact number of
+ bytes remaining in the input file. This will happen if the input file size
+ is an exact multiple of the buffer size.
+
+ If gzeof() returns true, then the read functions will return no more data,
+ unless the end-of-file indicator is reset by gzclearerr() and the input file
+ has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns true (1) if file is being copied directly while reading, or false
+ (0) if file is a gzip stream being decompressed.
+
+ If the input file is empty, gzdirect() will return true, since the input
+ does not contain a gzip stream.
+
+ If gzdirect() is used immediately after gzopen() or gzdopen() it will
+ cause buffers to be allocated to allow reading the file to determine if it
+ is a gzip file. Therefore if gzbuffer() is used, it should be called before
+ gzdirect().
+
+ When writing, gzdirect() returns true (1) if transparent writing was
+ requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note:
+ gzdirect() is not needed when writing. Transparent writing must be
+ explicitly requested, so the application already knows the answer. When
+ linking statically, using gzdirect() will include all of the zlib code for
+ gzip file reading and decompression, which may not be desired.)
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file and
+ deallocates the (de)compression state. Note that once file is closed, you
+ cannot call gzerror with file, since its structures have been deallocated.
+ gzclose must not be called more than once on the same file, just as free
+ must not be called more than once on the same allocation.
+
+ gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+ file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
+ last read ended in the middle of a gzip stream, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+ Same as gzclose(), but gzclose_r() is only for use when reading, and
+ gzclose_w() is only for use when writing or appending. The advantage to
+ using these instead of gzclose() is that they avoid linking in zlib
+ compression or decompression code that is not used when only reading or only
+ writing respectively. If gzclose() is used, then both compression and
+ decompression code will be included the application when linking to a static
+ zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the given
+ compressed file. errnum is set to zlib error number. If an error occurred
+ in the file system and not in the compression library, errnum is set to
+ Z_ERRNO and the application may consult errno to get the exact error code.
+
+ The application must not modify the returned string. Future calls to
+ this function may invalidate the previously returned string. If file is
+ closed, then the string previously returned by gzerror will no longer be
+ available.
+
+ gzerror() should be used to distinguish errors from end-of-file for those
+ functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+#endif /* !Z_SOLO */
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the compression
+ library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is Z_NULL, this function returns the
+ required initial value for the checksum.
+
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster.
+
+ Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note
+ that the z_off_t type (like off_t) is a signed integer. If len2 is
+ negative, the result has no meaning or utility.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is Z_NULL, this function returns the required
+ initial value for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+ (int)sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, (int)sizeof(z_stream))
+
+#ifndef Z_SOLO
+
+/* gzgetc() macro and its supporting function and exposed data structure. Note
+ * that the real internal state is much larger than the exposed structure.
+ * This abbreviated structure exposes just enough for the gzgetc() macro. The
+ * user should not mess with these exposed elements, since their names or
+ * behavior could change in the future, perhaps even capriciously. They can
+ * only be used by the gzgetc() macro. You have been warned.
+ */
+struct gzFile_s {
+ unsigned have;
+ unsigned char *next;
+ z_off64_t pos;
+};
+ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
+#ifdef Z_PREFIX_SET
+# undef z_gzgetc
+# define z_gzgetc(g) \
+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#else
+# define gzgetc(g) \
+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#endif
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#ifdef Z_LARGE64
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
+# ifdef Z_PREFIX_SET
+# define z_gzopen z_gzopen64
+# define z_gzseek z_gzseek64
+# define z_gztell z_gztell64
+# define z_gzoffset z_gzoffset64
+# define z_adler32_combine z_adler32_combine64
+# define z_crc32_combine z_crc32_combine64
+# else
+# define gzopen gzopen64
+# define gzseek gzseek64
+# define gztell gztell64
+# define gzoffset gzoffset64
+# define adler32_combine adler32_combine64
+# define crc32_combine crc32_combine64
+# endif
+# ifndef Z_LARGE64
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+# endif
+#else
+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+#else /* Z_SOLO */
+
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+
+#endif /* !Z_SOLO */
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void));
+ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
+ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp));
+ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp));
+#if defined(_WIN32) && !defined(Z_SOLO)
+ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path,
+ const char *mode));
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifndef Z_SOLO
+ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file,
+ const char *format,
+ va_list va));
+# endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/zlib/zutil.c b/zlib/zutil.c
new file mode 100644
index 0000000..23d2ebe
--- /dev/null
+++ b/zlib/zutil.c
@@ -0,0 +1,324 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+#ifndef Z_SOLO
+# include "gzguts.h"
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+z_const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch ((int)(sizeof(uInt))) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch ((int)(sizeof(uLong))) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch ((int)(sizeof(voidpf))) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch ((int)(sizeof(z_off_t))) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int ZLIB_INTERNAL z_verbose = verbose;
+
+void ZLIB_INTERNAL z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void ZLIB_INTERNAL zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int ZLIB_INTERNAL zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void ZLIB_INTERNAL zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+#ifndef Z_SOLO
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void ZLIB_INTERNAL zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
+
+#endif /* !Z_SOLO */
diff --git a/zlib/zutil.h b/zlib/zutil.h
new file mode 100644
index 0000000..24ab06b
--- /dev/null
+++ b/zlib/zutil.h
@@ -0,0 +1,253 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#ifdef HAVE_HIDDEN
+# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+# define ZLIB_INTERNAL
+#endif
+
+#include "zlib.h"
+
+#if defined(STDC) && !defined(Z_SOLO)
+# if !(defined(_WIN32_WCE) && defined(_MSC_VER))
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#ifdef Z_SOLO
+ typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# ifndef Z_SOLO
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# if defined(M_I86) && !defined(Z_SOLO)
+# include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# ifndef Z_SOLO
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+#if defined(__BORLANDC__) && !defined(MSDOS)
+ #pragma warn -8004
+ #pragma warn -8008
+ #pragma warn -8066
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_WIN32) && \
+ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(pyr) || defined(Z_SOLO)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int ZLIB_INTERNAL z_verbose;
+ extern void ZLIB_INTERNAL z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+#ifndef Z_SOLO
+ voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
+ unsigned size));
+ void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
+#endif
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+/* Reverse the bytes in a 32-bit value */
+#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+#endif /* ZUTIL_H */